Display actions and merge recent upstream/dev

- Add ActionListAdapter
- Add ChooseActionDialog
- Merge upstream/dev branch
This commit is contained in:
Nico Schmitz 2019-03-19 19:08:46 +01:00
parent 49b0e3ab71
commit 91e4b01f10
527 changed files with 32316 additions and 16818 deletions

View file

@ -1,10 +1,10 @@
Reporting bugs
--------------
- Note the precise time the problem occurred and describe the circumstances and steps that caused
- **Note the precise time the problem occurred** and describe the circumstances and steps that caused
the problem
- Note the Build version (found in the About dialog in the app, when pressing the three dots in the
upper-right corner).
- Obtain the app's log files, which can be found on the phone in
_/storage/emulated/0/Android/data/info.nightscout.androidaps/_
See https://github.com/MilosKozak/AndroidAPS/wiki/Accessing-logfiles
- Open an issue at https://github.com/MilosKozak/AndroidAPS/issues/new
- Open an issue at https://github.com/MilosKozak/AndroidAPS/issues/new

View file

@ -1,6 +1,6 @@
# AndroidAPS
* Check the wiki: https://github.com/MilosKozak/AndroidAPS/wiki
* Check the wiki: http://wiki.androidaps.org
* Everyone whos been looping with AndroidAPS needs to fill out the form after 3 days of looping https://docs.google.com/forms/d/14KcMjlINPMJHVt28MDRupa4sz4DDIooI4SrW0P3HSN8/viewform?c=0&w=1
[![Gitter](https://badges.gitter.im/MilosKozak/AndroidAPS.svg)](https://gitter.im/MilosKozak/AndroidAPS?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

View file

@ -63,7 +63,7 @@ android {
targetSdkVersion 25
multiDexEnabled true
versionCode 1500
version "2.0g-dev"
version "2.0"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
@ -198,6 +198,7 @@ dependencies {
implementation "com.google.android.gms:play-services-wearable:7.5.0"
implementation(name: "android-edittext-validator-v1.3.4-mod", ext: "aar")
implementation(name: "sightparser-release", ext: "aar")
implementation 'com.madgag.spongycastle:core:1.58.0.0'
implementation("com.google.android:flexbox:0.3.0") {
exclude group: "com.android.support"

View file

@ -12,6 +12,7 @@
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.SEND_MMS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
@ -31,10 +32,13 @@
android:name=".MainApp"
android:allowBackup="true"
android:icon="${appIcon}"
android:roundIcon="${appIconRound}"
android:label="@string/app_name"
android:roundIcon="${appIconRound}"
android:supportsRtl="true"
android:theme="@style/AppTheme.NoActionBar">
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -181,6 +185,8 @@
android:exported="false" />
<service android:name=".plugins.Persistentnotification.DummyService" />
<service android:name=".plugins.PumpInsightLocal.connection_service.InsightConnectionService" />
<service android:name=".plugins.PumpInsightLocal.InsightAlertService" />
<meta-data
android:name="io.fabric.ApiKey"
@ -189,12 +195,25 @@
<activity
android:name=".setupwizard.SetupWizardActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/AppTheme.NoActionBar"
android:label="@string/title_activity_setup_wizard" />
android:label="@string/title_activity_setup_wizard"
android:theme="@style/AppTheme.NoActionBar" />
<activity android:name=".activities.SingleFragmentActivity"
<activity
android:name=".activities.SingleFragmentActivity"
android:theme="@style/AppTheme" />
<activity android:name=".plugins.Maintenance.activities.LogSettingActivity"></activity>
<activity
android:name=".plugins.PumpInsightLocal.activities.InsightPairingActivity"
android:theme="@style/AppTheme"
android:label="@string/insight_pairing" />
<activity
android:name=".plugins.PumpInsightLocal.activities.InsightAlertActivity"
android:label="@string/pump_alert"
android:theme="@style/InsightAlertDialog" />
<activity
android:name=".plugins.PumpInsightLocal.activities.InsightPairingInformationActivity"
android:theme="@style/AppTheme"
android:label="@string/pairing_information" />
</application>
</manifest>

View file

@ -9,33 +9,32 @@ var tempBasalFunctions = {};
tempBasalFunctions.getMaxSafeBasal = function getMaxSafeBasal(profile) {
var max_daily_safety_multiplier = (isNaN(profile.max_daily_safety_multiplier) || profile.max_daily_safety_multiplier == null) ? 3 : profile.max_daily_safety_multiplier;
var current_basal_safety_multiplier = (isNaN(profile.current_basal_safety_multiplier) || profile.current_basal_safety_multiplier == null) ? 4 : profile.current_basal_safety_multiplier;
return Math.min(profile.max_basal, max_daily_safety_multiplier * profile.max_daily_basal, current_basal_safety_multiplier * profile.current_basal);
var max_daily_safety_multiplier = (isNaN(profile.max_daily_safety_multiplier) || profile.max_daily_safety_multiplier == null) ? 3 : profile.max_daily_safety_multiplier;
var current_basal_safety_multiplier = (isNaN(profile.current_basal_safety_multiplier) || profile.current_basal_safety_multiplier == null) ? 4 : profile.current_basal_safety_multiplier;
return Math.min(profile.max_basal, max_daily_safety_multiplier * profile.max_daily_basal, current_basal_safety_multiplier * profile.current_basal);
};
tempBasalFunctions.setTempBasal = function setTempBasal(rate, duration, profile, rT, currenttemp) {
//var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal);
var maxSafeBasal = tempBasalFunctions.getMaxSafeBasal(profile);
var round_basal = require('./round-basal');
if (rate < 0) {
rate = 0;
} // if >30m @ 0 required, zero temp will be extended to 30m instead
else if (rate > maxSafeBasal) {
rate = maxSafeBasal;
var round_basal = require('./round-basal');
if (rate < 0) {
rate = 0;
} else if (rate > maxSafeBasal) {
rate = maxSafeBasal;
}
var suggestedRate = round_basal(rate, profile);
if (typeof(currenttemp) !== 'undefined' && typeof(currenttemp.duration) !== 'undefined' && typeof(currenttemp.rate) !== 'undefined' && currenttemp.duration > (duration-10) && currenttemp.duration <= 120 && suggestedRate <= currenttemp.rate * 1.2 && suggestedRate >= currenttemp.rate * 0.8) {
if (typeof(currenttemp) !== 'undefined' && typeof(currenttemp.duration) !== 'undefined' && typeof(currenttemp.rate) !== 'undefined' && currenttemp.duration > (duration-10) && currenttemp.duration <= 120 && suggestedRate <= currenttemp.rate * 1.2 && suggestedRate >= currenttemp.rate * 0.8 && duration > 0 ) {
rT.reason += " "+currenttemp.duration+"m left and " + currenttemp.rate + " ~ req " + suggestedRate + "U/hr: no temp required";
return rT;
}
if (suggestedRate === profile.current_basal) {
if (profile.skip_neutral_temps) {
if (profile.skip_neutral_temps === true) {
if (typeof(currenttemp) !== 'undefined' && typeof(currenttemp.duration) !== 'undefined' && currenttemp.duration > 0) {
reason(rT, 'Suggested rate is same as profile rate, a temp basal is active, canceling current temp');
rT.duration = 0;
@ -58,4 +57,4 @@ var round_basal = require('./round-basal');
}
};
module.exports = tempBasalFunctions;
module.exports = tempBasalFunctions;

View file

@ -182,7 +182,7 @@ public class MainActivity extends AppCompatActivity {
@Subscribe
public void onStatusEvent(final EventRefreshGui ev) {
String lang = SP.getString("language", "en");
String lang = SP.getString(R.string.key_language, "en");
LocaleHelper.setLocale(getApplicationContext(), lang);
runOnUiThread(() -> {
if (ev.recreate) {
@ -326,6 +326,7 @@ public class MainActivity extends AppCompatActivity {
case AndroidPermission.CASE_LOCATION:
case AndroidPermission.CASE_SMS:
case AndroidPermission.CASE_BATTERY:
case AndroidPermission.CASE_PHONESTATE:
break;
}
}

View file

@ -59,6 +59,7 @@ import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin;
import info.nightscout.androidaps.plugins.PumpInsightLocal.LocalInsightPlugin;
import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityAAPSPlugin;
@ -158,9 +159,10 @@ public class MainApp extends Application {
if (Config.PUMPDRIVERS) pluginsList.add(DanaRKoreanPlugin.getPlugin());
if (Config.PUMPDRIVERS) pluginsList.add(DanaRv2Plugin.getPlugin());
if (Config.PUMPDRIVERS) pluginsList.add(DanaRSPlugin.getPlugin());
if (Config.PUMPDRIVERS && engineeringMode) pluginsList.add(LocalInsightPlugin.getInstance());
pluginsList.add(CareportalPlugin.getPlugin());
if (Config.PUMPDRIVERS && engineeringMode)
pluginsList.add(InsightPlugin.getPlugin()); // <-- Enable Insight plugin here
/*if (Config.PUMPDRIVERS && engineeringMode)
pluginsList.add(InsightPlugin.getPlugin());*/
if (Config.PUMPDRIVERS) pluginsList.add(ComboPlugin.getPlugin());
if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin());
pluginsList.add(VirtualPumpPlugin.getPlugin());

View file

@ -9,6 +9,7 @@ import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.text.TextUtils;
import info.nightscout.androidaps.Config;
@ -192,6 +193,17 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
addPreferencesFromResourceIfEnabled(StatuslinePlugin.getPlugin(), PluginType.GENERAL);
}
if (Config.NSCLIENT) {
PreferenceScreen scrnAdvancedSettings = (PreferenceScreen)findPreference(getString(R.string.key_advancedsettings));
if (scrnAdvancedSettings != null) {
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_res_warning)));
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_res_critical)));
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_bat_warning)));
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_statuslights_bat_critical)));
scrnAdvancedSettings.removePreference(getPreference(getString(R.string.key_show_statuslights)));
}
}
initSummary(getPreferenceScreen());
}

View file

@ -42,6 +42,10 @@ public class ConstraintChecker implements ConstraintsInterface {
return isSMBModeEnabled(new Constraint<>(true));
}
public Constraint<Boolean> isUAMEnabled() {
return isUAMEnabled(new Constraint<>(true));
}
public Constraint<Boolean> isAdvancedFilteringEnabled() {
return isAdvancedFilteringEnabled(new Constraint<>(true));
}
@ -130,6 +134,18 @@ public class ConstraintChecker implements ConstraintsInterface {
return value;
}
@Override
public Constraint<Boolean> isUAMEnabled(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
constraint.isUAMEnabled(value);
}
return value;
}
@Override
public Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);

View file

@ -23,6 +23,7 @@ import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.MidnightTime;
public class Profile {
private static Logger log = LoggerFactory.getLogger(Profile.class);
@ -381,7 +382,7 @@ public class Profile {
}
public double getIsf() {
return getIsfTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
return getIsfTimeFromMidnight(secondsFromMidnight());
}
public double getIsf(long time) {
@ -397,11 +398,11 @@ public class Profile {
public String getIsfList() {
if (isf_v == null)
isf_v = convertToSparseArray(isf);
return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits() + "/U");
return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits() + MainApp.gs(R.string.profile_per_unit));
}
public double getIc() {
return getIcTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
return getIcTimeFromMidnight(secondsFromMidnight());
}
public double getIc(long time) {
@ -417,11 +418,11 @@ public class Profile {
public String getIcList() {
if (ic_v == null)
ic_v = convertToSparseArray(ic);
return getValuesList(ic_v, null, new DecimalFormat("0.0"), "g/U");
return getValuesList(ic_v, null, new DecimalFormat("0.0"), MainApp.gs(R.string.profile_carbs_per_unit));
}
public double getBasal() {
return getBasalTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
return getBasalTimeFromMidnight(secondsFromMidnight());
}
public double getBasal(long time) {
@ -438,7 +439,7 @@ public class Profile {
public String getBasalList() {
if (basal_v == null)
basal_v = convertToSparseArray(basal);
return getValuesList(basal_v, null, new DecimalFormat("0.00"), "U/h");
return getValuesList(basal_v, null, new DecimalFormat("0.00"), MainApp.gs(R.string.profile_ins_units_per_hout));
}
public class BasalValue {
@ -465,7 +466,7 @@ public class Profile {
}
public double getTarget() {
return getTarget(secondsFromMidnight(System.currentTimeMillis()));
return getTarget(secondsFromMidnight());
}
protected double getTarget(int timeAsSeconds) {
@ -473,7 +474,7 @@ public class Profile {
}
public double getTargetLow() {
return getTargetLowTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
return getTargetLowTimeFromMidnight(secondsFromMidnight());
}
public double getTargetLow(long time) {
@ -487,7 +488,7 @@ public class Profile {
}
public double getTargetHigh() {
return getTargetHighTimeFromMidnight(secondsFromMidnight(System.currentTimeMillis()));
return getTargetHighTimeFromMidnight(secondsFromMidnight());
}
public double getTargetHigh(long time) {
@ -518,24 +519,13 @@ public class Profile {
}
public static int secondsFromMidnight() {
Calendar c = Calendar.getInstance();
long now = c.getTimeInMillis();
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
long passed = now - c.getTimeInMillis();
long passed = DateUtil.now() - MidnightTime.calc();
return (int) (passed / 1000);
}
public static int secondsFromMidnight(long date) {
Calendar c = Calendar.getInstance();
c.setTimeInMillis(date);
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
long passed = date - c.getTimeInMillis();
long midnight = MidnightTime.calc(date);
long passed = date - midnight;
return (int) (passed / 1000);
}

View file

@ -220,14 +220,8 @@ public class BgReading implements DataPointWithLabelInterface {
@Override
public int getColor() {
String units = ProfileFunctions.getInstance().getProfileUnits();
Double lowLine = SP.getDouble("low_mark", 0d);
Double highLine = SP.getDouble("high_mark", 0d);
if (lowLine < 1) {
lowLine = Profile.fromMgdlToUnits(OverviewPlugin.bgTargetLow, units);
}
if (highLine < 1) {
highLine = Profile.fromMgdlToUnits(OverviewPlugin.bgTargetHigh, units);
}
Double lowLine = OverviewPlugin.getPlugin().determineLowLine(units);
Double highLine = OverviewPlugin.getPlugin().determineHighLine(units);
int color = MainApp.gc(R.color.inrange);
if (isPrediction())
return getPredectionColor();

View file

@ -90,8 +90,8 @@ public class CareportalEvent implements DataPointWithLabelInterface, Interval {
return System.currentTimeMillis() - date;
}
public long getHoursFromStart() {
return (System.currentTimeMillis() - date) / (60 * 60 * 1000);
public double getHoursFromStart() {
return (System.currentTimeMillis() - date) / (60 * 60 * 1000.0);
}
public String age() {

View file

@ -50,6 +50,9 @@ import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventNewHistor
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRNSHistorySync;
import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.PumpInsightLocal.database.InsightBolusID;
import info.nightscout.androidaps.plugins.PumpInsightLocal.database.InsightHistoryOffset;
import info.nightscout.androidaps.plugins.PumpInsightLocal.database.InsightPumpID;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.utils.JsonHelper;
import info.nightscout.utils.PercentageSplitter;
@ -76,8 +79,11 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public static final String DATABASE_CAREPORTALEVENTS = "CareportalEvents";
public static final String DATABASE_PROFILESWITCHES = "ProfileSwitches";
public static final String DATABASE_TDDS = "TDDs";
public static final String DATABASE_INSIGHT_HISTORY_OFFSETS = "InsightHistoryOffsets";
public static final String DATABASE_INSIGHT_BOLUS_IDS = "InsightBolusIDs";
public static final String DATABASE_INSIGHT_PUMP_IDS = "InsightPumpIDs";
private static final int DATABASE_VERSION = 9;
private static final int DATABASE_VERSION = 10;
public static Long earliestDataChange = null;
@ -122,6 +128,9 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class);
TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class);
TableUtils.createTableIfNotExists(connectionSource, TDD.class);
TableUtils.createTableIfNotExists(connectionSource, InsightHistoryOffset.class);
TableUtils.createTableIfNotExists(connectionSource, InsightBolusID.class);
TableUtils.createTableIfNotExists(connectionSource, InsightPumpID.class);
} catch (SQLException e) {
log.error("Can't create database", e);
throw new RuntimeException(e);
@ -138,6 +147,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
log.debug("Upgrading database from v7 to v8");
} else if (oldVersion == 8 && newVersion == 9) {
log.debug("Upgrading database from v8 to v9");
} else if (oldVersion == 9 && newVersion == 10) {
TableUtils.createTableIfNotExists(connectionSource, InsightHistoryOffset.class);
TableUtils.createTableIfNotExists(connectionSource, InsightBolusID.class);
TableUtils.createTableIfNotExists(connectionSource, InsightPumpID.class);
} else {
log.info(DatabaseHelper.class.getName(), "onUpgrade");
TableUtils.dropTable(connectionSource, TempTarget.class, true);
@ -156,6 +169,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
}
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
log.info("Do nothing for downgrading...");
log.debug("oldVersion: {}, newVersion: {}", oldVersion, newVersion);
}
public int getOldVersion() {
return oldVersion;
}
@ -321,6 +340,18 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return getDao(ProfileSwitch.class);
}
private Dao<InsightPumpID, Long> getDaoInsightPumpID() throws SQLException {
return getDao(InsightPumpID.class);
}
private Dao<InsightBolusID, Long> getDaoInsightBolusID() throws SQLException {
return getDao(InsightBolusID.class);
}
private Dao<InsightHistoryOffset, String> getDaoInsightHistoryOffset() throws SQLException {
return getDao(InsightHistoryOffset.class);
}
public static long roundDateToSec(long date) {
long rounded = date - date % 1000;
if (rounded != date)
@ -397,7 +428,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<BgReading, Long> queryBuilder = daoBgReadings.queryBuilder();
queryBuilder.orderBy("date", false);
queryBuilder.limit(1L);
queryBuilder.where().gt("value", 38).and().eq("isValid", true);
queryBuilder.where().ge("value", 39).and().eq("isValid", true);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgList = daoBgReadings.query(preparedQuery);
@ -435,7 +466,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills).and().gt("value", 38).and().eq("isValid", true);
where.ge("date", mills).and().ge("value", 39).and().eq("isValid", true);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings;
@ -452,7 +483,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.between("date", start, end).and().gt("value", 38).and().eq("isValid", true);
where.between("date", start, end).and().ge("value", 39).and().eq("isValid", true);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings;
@ -1143,6 +1174,17 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return false;
}
public ExtendedBolus getExtendedBolusByPumpId(long pumpId) {
try {
return getDaoExtendedBolus().queryBuilder()
.where().eq("pumpId", pumpId)
.queryForFirst();
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
public void delete(ExtendedBolus extendedBolus) {
try {
getDaoExtendedBolus().delete(extendedBolus);
@ -1650,5 +1692,67 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return null;
}
// ---------------- Insight history handling ---------------
public void createOrUpdate(InsightHistoryOffset offset) {
try {
getDaoInsightHistoryOffset().createOrUpdate(offset);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
}
public InsightHistoryOffset getInsightHistoryOffset(String pumpSerial) {
try {
return getDaoInsightHistoryOffset().queryForId(pumpSerial);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
public void createOrUpdate(InsightBolusID bolusID) {
try {
getDaoInsightBolusID().createOrUpdate(bolusID);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
}
public InsightBolusID getInsightBolusID(String pumpSerial, int bolusID, long timestamp) {
try {
return getDaoInsightBolusID().queryBuilder()
.where().eq("pumpSerial", pumpSerial)
.and().eq("bolusID", bolusID)
.and().between("timestamp", timestamp - 259200000, timestamp + 259200000)
.queryForFirst();
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
public void createOrUpdate(InsightPumpID pumpID) {
try {
getDaoInsightPumpID().createOrUpdate(pumpID);
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
}
public InsightPumpID getPumpStoppedEvent(String pumpSerial, long before) {
try {
return getDaoInsightPumpID().queryBuilder()
.orderBy("timestamp", false)
.where().eq("pumpSerial", pumpSerial)
.and().eq("eventType", "PumpStopped")
.and().lt("timestamp", before)
.queryForFirst();
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return null;
}
// ---------------- Food handling ---------------
}

View file

@ -101,6 +101,11 @@ public class ProfileSwitch implements Interval, DataPointWithLabelInterface {
return profile;
}
/**
* Note: the name returned here is used as the PS name when uploading to NS. When such a PS is retrieved
* again from NS, the added parts must be removed again, see
* {@link info.nightscout.utils.PercentageSplitter#pureName}
*/
public String getCustomizedName() {
String name = profileName;
if(LocalProfilePlugin.LOCAL_PROFILE.equals(name)){

View file

@ -27,6 +27,10 @@ public interface ConstraintsInterface {
return value;
}
default Constraint<Boolean> isUAMEnabled(Constraint<Boolean> value) {
return value;
}
default Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
return value;
}

View file

@ -33,6 +33,10 @@ public interface PumpInterface {
double getBaseBasalRate(); // base basal rate, not temp basal
double getReservoirLevel();
int getBatteryLevel(); // in percent as integer
PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo);
void stopBolusDelivering();
PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew);

View file

@ -100,13 +100,13 @@ public class L {
private static void initialize() {
logElements = new ArrayList<>();
logElements.add(new LogElement(APS, true));
logElements.add(new LogElement(AUTOSENS, true));
logElements.add(new LogElement(AUTOSENS, false));
logElements.add(new LogElement(BGSOURCE, true));
logElements.add(new LogElement(CONFIGBUILDER, true));
logElements.add(new LogElement(CONFIGBUILDER, false));
logElements.add(new LogElement(CONSTRAINTS, true));
logElements.add(new LogElement(CORE, true));
logElements.add(new LogElement(DATABASE, true));
logElements.add(new LogElement(DATAFOOD, true));
logElements.add(new LogElement(DATAFOOD, false));
logElements.add(new LogElement(DATASERVICE, true));
logElements.add(new LogElement(DATATREATMENTS, true));
logElements.add(new LogElement(EVENTS, false, true));

View file

@ -185,7 +185,7 @@ public class FillDialog extends DialogFragment implements OnClickListener {
confirmMessage.add(MainApp.gs(R.string.fillwarning));
confirmMessage.add("");
confirmMessage.add(MainApp.gs(R.string.bolus) + ": " + "<font color='" + MainApp.gc(R.color.colorCarbsButton) + "'>" + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints) + "U" + "</font>");
if (!insulinAfterConstraints.equals(insulin))
if (Math.abs(insulinAfterConstraints - insulin) > 0.01d)
confirmMessage.add("<font color='" + MainApp.gc(R.color.low) + "'>" + MainApp.gs(R.string.bolusconstraintapplied) + "</font>");
}

View file

@ -270,7 +270,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
if (profile == null) {
editBg.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false, bgTextWatcher);
editTemptarget.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false);
} else if (profile.getUnits().equals(Constants.MMOL)) {
} else if (units.equals(Constants.MMOL)) {
editBg.setParams(bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false, bgTextWatcher);
editTemptarget.setParams(bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false);
} else {
@ -279,7 +279,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
}
sensorRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> {
Double bg1 = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, profile.getUnits());
Double bg1 = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, units);
if (savedInstanceState != null && savedInstanceState.getDouble("editBg") != bg1) {
editBg.setValue(savedInstanceState.getDouble("editBg"));
} else {
@ -459,7 +459,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
if ((data.size() > 0) &&
(data.get(0).date > millis - 7 * 60 * 1000L) &&
(data.get(0).date < millis + 7 * 60 * 1000L)) {
editBg.setValue(Profile.fromMgdlToUnits(data.get(0).value, profile != null ? profile.getUnits() : Constants.MGDL));
editBg.setValue(Profile.fromMgdlToUnits(data.get(0).value, units));
}
}
@ -736,8 +736,8 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
.reason(reason)
.source(Source.USER);
if (tempTarget.durationInMinutes != 0) {
tempTarget.low(Profile.toMgdl(targetBottom, profile.getUnits()))
.high(Profile.toMgdl(targetTop, profile.getUnits()));
tempTarget.low(Profile.toMgdl(targetBottom, units))
.high(Profile.toMgdl(targetTop, units));
} else {
tempTarget.low(0).high(0);
}

View file

@ -18,6 +18,7 @@ import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref1Plugin;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.HardLimits;
import info.nightscout.utils.Round;
@ -94,6 +95,17 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
return value;
}
@Override
public Constraint<Boolean> isUAMEnabled(Constraint<Boolean> value) {
boolean enabled = SP.getBoolean(R.string.key_use_uam, false);
if (!enabled)
value.set(false, MainApp.gs(R.string.uamdisabledinpreferences), this);
boolean oref1Enabled = SensitivityOref1Plugin.getPlugin().isEnabled(PluginType.SENSITIVITY);
if (!oref1Enabled)
value.set(false, MainApp.gs(R.string.uamdisabledoref1notselected), this);
return value;
}
@Override
public Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
BgSourceInterface bgSource = ConfigBuilderPlugin.getPlugin().getActiveBgSource();

View file

@ -21,6 +21,7 @@ import info.nightscout.androidaps.plugins.Overview.graphExtensions.Scale;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.SP;
/**
@ -40,7 +41,7 @@ public class AutosensData implements DataPointWithLabelInterface {
double min5minCarbImpact = 0d;
double remaining = 0d;
public CarbsInPast(Treatment t) {
CarbsInPast(Treatment t) {
time = t.date;
carbs = t.carbs;
remaining = t.carbs;
@ -56,6 +57,18 @@ public class AutosensData implements DataPointWithLabelInterface {
min5minCarbImpact = SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact);
}
}
CarbsInPast (CarbsInPast other) {
this.time = other.time;
this.carbs = other.carbs;
this.min5minCarbImpact = other.min5minCarbImpact;
this.remaining = other.remaining;
}
@Override
public String toString() {
return String.format("CarbsInPast: time: %s carbs: %.02f min5minCI: %.02f remaining: %.2f", new Date(time).toLocaleString(), carbs, min5minCarbImpact, remaining);
}
}
public long time = 0L;
@ -89,11 +102,18 @@ public class AutosensData implements DataPointWithLabelInterface {
@Override
public String toString() {
return "AutosensData: " + new Date(time).toLocaleString() + " " + pastSensitivity + " Delta=" + delta + " avgDelta=" + avgDelta + " Bgi=" + bgi + " Deviation=" + deviation + " avgDeviation=" + avgDeviation + " Absorbed=" + absorbed + " CarbsFromBolus=" + carbsFromBolus + " COB=" + cob + " autosensRatio=" + autosensResult.ratio + " slopeFromMaxDeviation=" + slopeFromMaxDeviation + " slopeFromMinDeviation=" + slopeFromMinDeviation;
return String.format("AutosensData: %s pastSensitivity=%s delta=%.02f avgDelta=%.02f bgi=%.02f deviation=%.02f avgDeviation=%.02f absorbed=%.02f carbsFromBolus=%.02f cob=%.02f autosensRatio=%.02f slopeFromMaxDeviation=%.02f slopeFromMinDeviation=%.02f activeCarbsList=%s",
new Date(time).toLocaleString(), pastSensitivity, delta, avgDelta, bgi, deviation, avgDeviation, absorbed, carbsFromBolus, cob, autosensResult.ratio, slopeFromMaxDeviation, slopeFromMinDeviation, activeCarbsList.toString());
}
public int minOld() {
return (int) ((System.currentTimeMillis() - time) / 1000 / 60);
public List<CarbsInPast> cloneCarbsList() {
List<CarbsInPast> newActiveCarbsList = new ArrayList<>();
for(CarbsInPast c: activeCarbsList) {
newActiveCarbsList.add(new CarbsInPast(c));
}
return newActiveCarbsList;
}
// remove carbs older than timeframe
@ -111,7 +131,7 @@ public class AutosensData implements DataPointWithLabelInterface {
if (c.remaining > 0)
cob -= c.remaining;
if (L.isEnabled(L.AUTOSENS))
log.debug("Removing carbs at " + new Date(toTime).toLocaleString() + " + after " + maxAbsorptionHours + "h :" + new Date(c.time).toLocaleString());
log.debug("Removing carbs at " + new Date(toTime).toLocaleString() + " after " + maxAbsorptionHours + "h > " + c.toString());
}
}
}

View file

@ -146,8 +146,8 @@ public class IobCobCalculatorPlugin extends PluginBase {
return false;
}
}
double averageDiff = totalDiff / (bgReadings.size() - 1) / 1000d;
boolean is5mindata = averageDiff < 10;
long averageDiff = totalDiff / bgReadings.size() / 1000;
boolean is5mindata = averageDiff < 1;
if (L.isEnabled(L.AUTOSENS))
log.debug("Interval detection: values: " + bgReadings.size() + " averageDiff: " + averageDiff + "[s] is5minData: " + is5mindata);
return is5mindata;
@ -231,13 +231,15 @@ public class IobCobCalculatorPlugin extends PluginBase {
bucketed_data = new ArrayList<>();
bucketed_data.add(bgReadings.get(0));
if (L.isEnabled(L.AUTOSENS))
log.debug("Adding. bgTime: " + DateUtil.toISOString(bgReadings.get(0).date) + " lastbgTime: " + "none-first-value" + " " + bgReadings.get(0).toString());
int j = 0;
for (int i = 1; i < bgReadings.size(); ++i) {
long bgTime = bgReadings.get(i).date;
long lastbgTime = bgReadings.get(i - 1).date;
//log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value);
if (bgReadings.get(i).value < 39 || bgReadings.get(i - 1).value < 39) {
continue;
throw new IllegalStateException("<39");
}
long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
@ -294,6 +296,13 @@ public class IobCobCalculatorPlugin extends PluginBase {
long adjusted = (msecDiff - T.mins(5).msecs()) / 1000;
if (L.isEnabled(L.AUTOSENS))
log.debug("Adjusting bucketed data time. Current: " + DateUtil.toISOString(current.date) + " to: " + DateUtil.toISOString(previous.date + T.mins(5).msecs()) + " by " + adjusted + " sec");
if (Math.abs(adjusted) > 90) {
// too big adjustment, fallback to non 5 min data
if (L.isEnabled(L.AUTOSENS))
log.debug("Fallback to non 5 min data");
createBucketedDataRecalculated();
return;
}
current.date = previous.date + T.mins(5).msecs();
}

View file

@ -36,7 +36,10 @@ import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.MidnightTime;
import info.nightscout.utils.Profiler;
import info.nightscout.utils.SP;
import static info.nightscout.utils.DateUtil.now;
@ -74,6 +77,7 @@ public class IobCobOref1Thread extends Thread {
@Override
public final void run() {
long start = DateUtil.now();
mWakeLock.acquire();
try {
if (L.isEnabled(L.AUTOSENS))
@ -148,7 +152,7 @@ public class IobCobOref1Thread extends Thread {
AutosensData autosensData = new AutosensData();
autosensData.time = bgTime;
if (previous != null)
autosensData.activeCarbsList = new ArrayList<>(previous.activeCarbsList);
autosensData.activeCarbsList = previous.cloneCarbsList();
else
autosensData.activeCarbsList = new ArrayList<>();
@ -242,6 +246,7 @@ public class IobCobOref1Thread extends Thread {
for (int ir = 0; ir < recentTreatments.size(); ir++) {
autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir)));
autosensData.pastSensitivity += "[" + DecimalFormatter.to0Decimal(recentTreatments.get(ir).carbs) + "g]";
}
@ -339,19 +344,19 @@ public class IobCobOref1Thread extends Thread {
// Exclude meal-related deviations (carb absorption) from autosens
if (autosensData.type.equals("non-meal")) {
if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
autosensData.pastSensitivity = "=";
autosensData.pastSensitivity += "=";
autosensData.validDeviation = true;
} else if (deviation > 0) {
autosensData.pastSensitivity = "+";
autosensData.pastSensitivity += "+";
autosensData.validDeviation = true;
} else {
autosensData.pastSensitivity = "-";
autosensData.pastSensitivity += "-";
autosensData.validDeviation = true;
}
} else if (autosensData.type.equals("uam")) {
autosensData.pastSensitivity = "u";
autosensData.pastSensitivity += "u";
} else {
autosensData.pastSensitivity = "x";
autosensData.pastSensitivity += "x";
}
//log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
@ -391,8 +396,11 @@ public class IobCobOref1Thread extends Thread {
} finally {
mWakeLock.release();
MainApp.bus().post(new EventIobCalculationProgress(""));
if (L.isEnabled(L.AUTOSENS))
if (L.isEnabled(L.AUTOSENS)) {
log.debug("AUTOSENSDATA thread ended: " + from);
log.debug("Midnights: " + MidnightTime.log());
}
Profiler.log(log, "IobCobOref1Thread", start);
}
}

View file

@ -36,7 +36,10 @@ import info.nightscout.androidaps.plugins.Sensitivity.SensitivityWeightedAverage
import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.MidnightTime;
import info.nightscout.utils.Profiler;
import info.nightscout.utils.SP;
import static info.nightscout.utils.DateUtil.now;
@ -73,6 +76,7 @@ public class IobCobThread extends Thread {
@Override
public final void run() {
long start = DateUtil.now();
mWakeLock.acquire();
try {
if (L.isEnabled(L.AUTOSENS))
@ -147,7 +151,7 @@ public class IobCobThread extends Thread {
AutosensData autosensData = new AutosensData();
autosensData.time = bgTime;
if (previous != null)
autosensData.activeCarbsList = new ArrayList<>(previous.activeCarbsList);
autosensData.activeCarbsList = previous.cloneCarbsList();
else
autosensData.activeCarbsList = new ArrayList<>();
@ -241,6 +245,7 @@ public class IobCobThread extends Thread {
for (int ir = 0; ir < recentTreatments.size(); ir++) {
autosensData.carbsFromBolus += recentTreatments.get(ir).carbs;
autosensData.activeCarbsList.add(new AutosensData.CarbsInPast(recentTreatments.get(ir)));
autosensData.pastSensitivity += "[" + DecimalFormatter.to0Decimal(recentTreatments.get(ir).carbs) + "g]";
}
@ -284,17 +289,17 @@ public class IobCobThread extends Thread {
// calculate autosens only without COB
if (autosensData.cob <= 0) {
if (Math.abs(deviation) < Constants.DEVIATION_TO_BE_EQUAL) {
autosensData.pastSensitivity = "=";
autosensData.pastSensitivity += "=";
autosensData.validDeviation = true;
} else if (deviation > 0) {
autosensData.pastSensitivity = "+";
autosensData.pastSensitivity += "+";
autosensData.validDeviation = true;
} else {
autosensData.pastSensitivity = "-";
autosensData.pastSensitivity += "-";
autosensData.validDeviation = true;
}
} else {
autosensData.pastSensitivity = "C";
autosensData.pastSensitivity += "C";
}
//log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation);
@ -318,8 +323,11 @@ public class IobCobThread extends Thread {
} finally {
mWakeLock.release();
MainApp.bus().post(new EventIobCalculationProgress(""));
if (L.isEnabled(L.AUTOSENS))
if (L.isEnabled(L.AUTOSENS)) {
log.debug("AUTOSENSDATA thread ended: " + from);
log.debug("Midnights: " + MidnightTime.log());
}
Profiler.log(log, "IobCobThread", start);
}
}

View file

@ -307,6 +307,11 @@ public class APSResult {
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile == null) {
log.error("FALSE: No Profile");
return false;
}
if (usePercent) {
if (activeTemp == null && percent == 100) {
if (L.isEnabled(L.APS))

View file

@ -409,8 +409,10 @@ public class LoopPlugin extends PluginBase {
.setAutoCancel(true)
.setPriority(Notification.PRIORITY_HIGH)
.setCategory(Notification.CATEGORY_ALARM)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setLocalOnly(true);
.setVisibility(Notification.VISIBILITY_PUBLIC);
if (SP.getBoolean("wearcontrol", false)) {
builder.setLocalOnly(true);
}
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(MainApp.instance().getApplicationContext(), MainActivity.class);

View file

@ -73,8 +73,8 @@ public class MaintenancePlugin extends PluginBase {
}
public void sendLogs() {
String recipient = SP.getString("key_maintenance_logs_email", "logs@androidaps.org");
int amount = SP.getInt("key_maintenance_logs_amount", 2);
String recipient = SP.getString(R.string.key_maintenance_logs_email, "logs@androidaps.org");
int amount = SP.getInt(R.string.key_maintenance_logs_amount, 2);
String logDirectory = LoggerUtils.getLogDirectory();
List<File> logs = this.getLogfiles(logDirectory, amount);
@ -103,7 +103,7 @@ public class MaintenancePlugin extends PluginBase {
Arrays.sort(files, (f1, f2) -> f1.getName().compareTo(f2.getName()));
List<File> delFiles = Arrays.asList(files);
int amount = SP.getInt("key_logshipper_amount", 2);
int amount = SP.getInt(R.string.key_logshipper_amount, 2);
int keepIndex = amount - 1;
if (keepIndex < delFiles.size()) {
@ -213,6 +213,10 @@ public class MaintenancePlugin extends PluginBase {
builder.append("ADD TIME OF EVENT HERE: " + System.lineSeparator());
builder.append("ADD ISSUE DESCRIPTION OR GITHUB ISSUE REFERENCE NUMBER: " + System.lineSeparator());
builder.append("-------------------------------------------------------" + System.lineSeparator());
builder.append("(Please remember this will send only very recent logs." + System.lineSeparator());
builder.append("If you want to provide logs for event older than a few hours," + System.lineSeparator());
builder.append("you have to do it manually)" + System.lineSeparator());
builder.append("-------------------------------------------------------" + System.lineSeparator());
builder.append(MainApp.gs(R.string.app_name) + " " + BuildConfig.VERSION + System.lineSeparator());
if (Config.NSCLIENT)
builder.append("NSCLIENT" + System.lineSeparator());

View file

@ -211,6 +211,7 @@ public class DetermineBasalAdapterSMBJS {
double autosensDataRatio,
boolean tempTargetSet,
boolean microBolusAllowed,
boolean uamAllowed,
boolean advancedFiltering
) throws JSONException {
@ -247,7 +248,7 @@ public class DetermineBasalAdapterSMBJS {
// mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
//}
mProfile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap);
mProfile.put("enableUAM", SP.getBoolean(R.string.key_use_uam, false));
mProfile.put("enableUAM", uamAllowed);
mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable);
mProfile.put("enableSMB_with_COB", SP.getBoolean(R.string.key_enableSMB_with_COB, false));
mProfile.put("enableSMB_with_temptarget", SP.getBoolean(R.string.key_enableSMB_with_temptarget, false));

View file

@ -198,6 +198,10 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface {
MainApp.getConstraintChecker().isAdvancedFilteringEnabled(advancedFiltering);
inputConstraints.copyReasons(advancedFiltering);
Constraint<Boolean> uam = new Constraint<>(true);
MainApp.getConstraintChecker().isUAMEnabled(uam);
inputConstraints.copyReasons(uam);
if (L.isEnabled(L.APS))
Profiler.log(log, "detectSensitivityandCarbAbsorption()", startPart);
if (L.isEnabled(L.APS))
@ -209,6 +213,7 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface {
lastAutosensResult.ratio, //autosensDataRatio
isTempTarget,
smbAllowed.value(),
uam.value(),
advancedFiltering.value()
);
} catch (JSONException e) {

View file

@ -107,9 +107,9 @@ public class BolusProgressDialog extends DialogFragment implements View.OnClickL
@Override
public void onPause() {
running = false;
super.onPause();
MainApp.unsubscribe(this);
running = false;
if (L.isEnabled(L.UI))
log.debug("onPause");
}
@ -173,10 +173,12 @@ public class BolusProgressDialog extends DialogFragment implements View.OnClickL
Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(() -> {
if (L.isEnabled(L.UI))
log.debug("executing");
try {
dismiss();
if (running) {
if (L.isEnabled(L.UI))
log.debug("executing");
dismiss();
}
} catch (Exception e) {
log.error("Unhandled exception", e);
}

View file

@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.Overview;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.NotificationManager;
import android.arch.core.util.Function;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
@ -97,6 +98,7 @@ import info.nightscout.androidaps.plugins.Loop.LoopPlugin;
import info.nightscout.androidaps.plugins.Loop.events.EventNewOpenLoopNotification;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSDeviceStatus;
import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSettingsStatus;
import info.nightscout.androidaps.plugins.Overview.Dialogs.CalibrationDialog;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.Overview.Dialogs.NewCarbsDialog;
@ -162,6 +164,13 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
TextView sage;
TextView pbage;
TextView iageView;
TextView cageView;
TextView reservoirView;
TextView sageView;
TextView batteryView;
LinearLayout statuslightsLayout;
RecyclerView notificationsView;
LinearLayoutManager llm;
@ -258,8 +267,15 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
sage = (TextView) view.findViewById(R.id.careportal_sensorage);
pbage = (TextView) view.findViewById(R.id.careportal_pbage);
bgGraph = (GraphView) view.findViewById(R.id.overview_bggraph);
iobGraph = (GraphView) view.findViewById(R.id.overview_iobgraph);
iageView = (TextView) view.findViewById(R.id.overview_insulinage);
cageView = (TextView) view.findViewById(R.id.overview_canulaage);
reservoirView = (TextView) view.findViewById(R.id.overview_reservoirlevel);
sageView = (TextView) view.findViewById(R.id.overview_sensorage);
batteryView = (TextView) view.findViewById(R.id.overview_batterylevel);
statuslightsLayout = (LinearLayout) view.findViewById(R.id.overview_statuslights);
bgGraph = (GraphView) view.findViewById(R.id.overview_bggraph);
iobGraph = (GraphView) view.findViewById(R.id.overview_iobgraph);
treatmentButton = (SingleClickButton) view.findViewById(R.id.overview_treatmentbutton);
treatmentButton.setOnClickListener(this);
@ -446,7 +462,8 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
super.onCreateContextMenu(menu, v, menuInfo);
if (v == apsModeView) {
final LoopPlugin loopPlugin = LoopPlugin.getPlugin();
final PumpDescription pumpDescription = ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription();
final PumpDescription pumpDescription =
ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription();
if (!ProfileFunctions.getInstance().isProfileValid("ContexMenuCreation"))
return;
menu.setHeaderTitle(MainApp.gs(R.string.loop));
@ -457,19 +474,23 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
menu.add(MainApp.gs(R.string.suspendloopfor2h));
menu.add(MainApp.gs(R.string.suspendloopfor3h));
menu.add(MainApp.gs(R.string.suspendloopfor10h));
if (pumpDescription.tempDurationStep15mAllowed)
menu.add(MainApp.gs(R.string.disconnectpumpfor15m));
if (pumpDescription.tempDurationStep30mAllowed)
menu.add(MainApp.gs(R.string.disconnectpumpfor30m));
menu.add(MainApp.gs(R.string.disconnectpumpfor1h));
menu.add(MainApp.gs(R.string.disconnectpumpfor2h));
menu.add(MainApp.gs(R.string.disconnectpumpfor3h));
} else {
menu.add(MainApp.gs(R.string.resume));
} else {
if (!loopPlugin.isDisconnected()) {
menu.add(MainApp.gs(R.string.resume));
}
}
}
if (!loopPlugin.isEnabled(PluginType.LOOP))
if (!loopPlugin.isEnabled(PluginType.LOOP)) {
menu.add(MainApp.gs(R.string.enableloop));
}
if (!loopPlugin.isDisconnected()) {
showSuspendtPump(menu, pumpDescription);
} else {
menu.add(MainApp.gs(R.string.reconnect));
}
} else if (v == activeProfileView) {
menu.setHeaderTitle(MainApp.gs(R.string.profile));
menu.add(MainApp.gs(R.string.danar_viewprofile));
@ -488,6 +509,17 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
}
}
private void showSuspendtPump(ContextMenu menu,
PumpDescription pumpDescription) {
if (pumpDescription.tempDurationStep15mAllowed)
menu.add(MainApp.gs(R.string.disconnectpumpfor15m));
if (pumpDescription.tempDurationStep30mAllowed)
menu.add(MainApp.gs(R.string.disconnectpumpfor30m));
menu.add(MainApp.gs(R.string.disconnectpumpfor1h));
menu.add(MainApp.gs(R.string.disconnectpumpfor2h));
menu.add(MainApp.gs(R.string.disconnectpumpfor3h));
}
@Override
public boolean onContextItemSelected(MenuItem item) {
final Profile profile = ProfileFunctions.getInstance().getProfile();
@ -516,7 +548,8 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
updateGUI("suspendmenu");
NSUpload.uploadOpenAPSOffline(0);
return true;
} else if (item.getTitle().equals(MainApp.gs(R.string.resume))) {
} else if (item.getTitle().equals(MainApp.gs(R.string.resume)) ||
item.getTitle().equals(MainApp.gs(R.string.reconnect))) {
loopPlugin.suspendTo(0L);
updateGUI("suspendmenu");
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() {
@ -1088,25 +1121,25 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
final LoopPlugin.LastRun finalLastRun = LoopPlugin.lastRun;
if (Config.APS && pump.getPumpDescription().isTempBasalCapable) {
apsModeView.setVisibility(View.VISIBLE);
apsModeView.setBackgroundColor(MainApp.gc(R.color.loopenabled));
apsModeView.setTextColor(Color.BLACK);
apsModeView.setBackgroundColor(MainApp.gc(R.color.ribbonDefault));
apsModeView.setTextColor(MainApp.gc(R.color.ribbonTextDefault));
final LoopPlugin loopPlugin = LoopPlugin.getPlugin();
if (loopPlugin.isEnabled(PluginType.LOOP) && loopPlugin.isSuperBolus()) {
apsModeView.setBackgroundColor(MainApp.gc(R.color.looppumpsuspended));
apsModeView.setBackgroundColor(MainApp.gc(R.color.ribbonWarning));
apsModeView.setText(String.format(MainApp.gs(R.string.loopsuperbolusfor), loopPlugin.minutesToEndOfSuspend()));
apsModeView.setTextColor(Color.WHITE);
} else if (loopPlugin.isEnabled(PluginType.LOOP) && loopPlugin.isDisconnected()) {
apsModeView.setBackgroundColor(MainApp.gc(R.color.looppumpsuspended));
apsModeView.setTextColor(MainApp.gc(R.color.ribbonTextWarning));
} else if (loopPlugin.isDisconnected()) {
apsModeView.setBackgroundColor(MainApp.gc(R.color.ribbonCritical));
apsModeView.setText(String.format(MainApp.gs(R.string.loopdisconnectedfor), loopPlugin.minutesToEndOfSuspend()));
apsModeView.setTextColor(Color.WHITE);
apsModeView.setTextColor(MainApp.gc(R.color.ribbonTextCritical));
} else if (loopPlugin.isEnabled(PluginType.LOOP) && loopPlugin.isSuspended()) {
apsModeView.setBackgroundColor(MainApp.gc(R.color.looppumpsuspended));
apsModeView.setBackgroundColor(MainApp.gc(R.color.ribbonWarning));
apsModeView.setText(String.format(MainApp.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend()));
apsModeView.setTextColor(Color.WHITE);
apsModeView.setTextColor(MainApp.gc(R.color.ribbonTextWarning));
} else if (pump.isSuspended()) {
apsModeView.setBackgroundColor(MainApp.gc(R.color.looppumpsuspended));
apsModeView.setBackgroundColor(MainApp.gc(R.color.ribbonWarning));
apsModeView.setText(MainApp.gs(R.string.pumpsuspended));
apsModeView.setTextColor(Color.WHITE);
apsModeView.setTextColor(MainApp.gc(R.color.ribbonTextWarning));
} else if (loopPlugin.isEnabled(PluginType.LOOP)) {
if (closedLoopEnabled.value()) {
apsModeView.setText(MainApp.gs(R.string.closedloop));
@ -1114,9 +1147,9 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
apsModeView.setText(MainApp.gs(R.string.openloop));
}
} else {
apsModeView.setBackgroundColor(MainApp.gc(R.color.loopdisabled));
apsModeView.setBackgroundColor(MainApp.gc(R.color.ribbonCritical));
apsModeView.setText(MainApp.gs(R.string.disabledloop));
apsModeView.setTextColor(Color.WHITE);
apsModeView.setTextColor(MainApp.gc(R.color.ribbonTextCritical));
}
} else {
apsModeView.setVisibility(View.GONE);
@ -1125,13 +1158,13 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
// temp target
TempTarget tempTarget = TreatmentsPlugin.getPlugin().getTempTargetFromHistory();
if (tempTarget != null) {
tempTargetView.setTextColor(Color.BLACK);
tempTargetView.setBackgroundColor(MainApp.gc(R.color.tempTargetBackground));
tempTargetView.setTextColor(MainApp.gc(R.color.ribbonTextWarning));
tempTargetView.setBackgroundColor(MainApp.gc(R.color.ribbonWarning));
tempTargetView.setVisibility(View.VISIBLE);
tempTargetView.setText(Profile.toTargetRangeString(tempTarget.low, tempTarget.high, Constants.MGDL, units) + " " + DateUtil.untilString(tempTarget.end()));
} else {
tempTargetView.setTextColor(Color.WHITE);
tempTargetView.setBackgroundColor(MainApp.gc(R.color.tempTargetDisabledBackground));
tempTargetView.setTextColor(MainApp.gc(R.color.ribbonTextDefault));
tempTargetView.setBackgroundColor(MainApp.gc(R.color.ribbonDefault));
tempTargetView.setText(Profile.toTargetRangeString(profile.getTargetLow(), profile.getTargetHigh(), units, units));
tempTargetView.setVisibility(View.VISIBLE);
}
@ -1230,7 +1263,13 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
}
activeProfileView.setText(ProfileFunctions.getInstance().getProfileName());
activeProfileView.setBackgroundColor(Color.GRAY);
if (profile.getPercentage() != 100 || profile.getTimeshift() != 0) {
activeProfileView.setBackgroundColor(MainApp.gc(R.color.ribbonWarning));
activeProfileView.setTextColor(MainApp.gc(R.color.ribbonTextWarning));
} else {
activeProfileView.setBackgroundColor(MainApp.gc(R.color.ribbonDefault));
activeProfileView.setTextColor(MainApp.gc(R.color.ribbonTextDefault));
}
// QuickWizard button
QuickWizardEntry quickWizardEntry = OverviewPlugin.getPlugin().quickWizard.getActive();
@ -1335,6 +1374,56 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
cobView.setText(cobText);
}
if (statuslightsLayout != null) {
if (SP.getBoolean(R.string.key_show_statuslights, false)) {
CareportalEvent careportalEvent;
NSSettingsStatus nsSettings = new NSSettingsStatus().getInstance();
double iageUrgent = nsSettings.getExtendedWarnValue("iage", "urgent", 96);
double iageWarn = nsSettings.getExtendedWarnValue("iage", "warn", 72);
double cageUrgent = nsSettings.getExtendedWarnValue("cage", "urgent", 72);
double cageWarn = nsSettings.getExtendedWarnValue("cage", "warn", 48);
double sageUrgent = nsSettings.getExtendedWarnValue("sage", "urgent", 166);
double sageWarn = nsSettings.getExtendedWarnValue("sage", "warn", 164);
//double pbageUrgent = nsSettings.getExtendedWarnValue("pgage", "urgent", 360);
//double pbageWarn = nsSettings.getExtendedWarnValue("pgage", "warn", 240);
double batUrgent = SP.getDouble(R.string.key_statuslights_bat_critical, 5.0);
double batWarn = SP.getDouble(R.string.key_statuslights_bat_warning, 25.0);
double resUrgent = SP.getDouble(R.string.key_statuslights_res_critical, 10.0);
double resWarn = SP.getDouble(R.string.key_statuslights_res_warning, 80.0);
if (cageView != null) {
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.SITECHANGE);
double canAge = careportalEvent != null ? careportalEvent.getHoursFromStart() : Double.MAX_VALUE;
applyStatuslight(cageView, "CAN", canAge, cageWarn, cageUrgent, Double.MAX_VALUE, true);
}
if (iageView != null) {
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.INSULINCHANGE);
double insulinAge = careportalEvent != null ? careportalEvent.getHoursFromStart() : Double.MAX_VALUE;
applyStatuslight(iageView, "INS", insulinAge, iageWarn, iageUrgent, Double.MAX_VALUE, true);
}
if (reservoirView != null) {
double reservoirLevel = pump.isInitialized() ? pump.getReservoirLevel() : -1;
applyStatuslight(reservoirView, "RES", reservoirLevel, resWarn, resUrgent, -1, false);
}
if (sageView != null) {
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.SENSORCHANGE);
double sensorAge = careportalEvent != null ? careportalEvent.getHoursFromStart() : Double.MAX_VALUE;
applyStatuslight(sageView, "SEN", sensorAge, sageWarn, sageUrgent, Double.MAX_VALUE, true);
}
if (batteryView != null) {
double batteryLevel = pump.isInitialized() ? pump.getBatteryLevel() : -1;
applyStatuslight(batteryView, "BAT", batteryLevel, batWarn, batUrgent, -1, false);
}
statuslightsLayout.setVisibility(View.VISIBLE);
} else {
statuslightsLayout.setVisibility(View.GONE);
}
}
boolean predictionsAvailable;
if (Config.APS)
predictionsAvailable = finalLastRun != null && finalLastRun.request.hasPredictions;
@ -1364,7 +1453,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
// Sensitivity
if (sensitivityView != null) {
AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensDataSynchronized("Overview");
AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensData("Overview");
if (autosensData != null)
sensitivityView.setText(String.format("%.0f%%", autosensData.autosensResult.ratio * 100));
else
@ -1525,4 +1614,21 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
}
}
public static void applyStatuslight(TextView view, String text, double value, double warnThreshold, double urgentThreshold, double invalid, boolean checkAscending) {
Function<Double, Boolean> check = checkAscending ? (Double threshold) -> value >= threshold : (Double threshold) -> value <= threshold;
if (value != invalid) {
view.setText(text);
if (check.apply(urgentThreshold)) {
view.setTextColor(MainApp.gc(R.color.ribbonCritical));
} else if (check.apply(warnThreshold)) {
view.setTextColor(MainApp.gc(R.color.ribbonWarning));
} else {
view.setTextColor(MainApp.gc(R.color.ribbonDefault));
}
view.setVisibility(View.VISIBLE);
} else {
view.setVisibility(View.GONE);
}
}
}

View file

@ -68,6 +68,11 @@ public class Notification {
public static final int NSMALFUNCTION = 40;
public static final int NEWVERSIONDETECTED = 41;
public static final int SENDLOGFILES = 42;
public static final int DEVICENOTPAIRED = 43;
public static final int MEDTRONIC_PUMP_ALARM = 44;
public static final int RILEYLINK_CONNECTION = 45;
public static final int PERMISSION_PHONESTATE = 46;
public static final int INSIGHT_DATE_TIME_UPDATED = 47;
public int id;

View file

@ -13,6 +13,14 @@ import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
// Android Auto
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.app.RemoteInput;
import com.squareup.otto.Subscribe;
import info.nightscout.androidaps.Config;
@ -60,6 +68,18 @@ public class PersistentNotificationPlugin extends PluginBase {
public static final int ONGOING_NOTIFICATION_ID = 4711;
private final Context ctx;
/// For Android Auto
/// Intents are not declared in manifest and not consumed, this is intentionally because actually we can't do anything with
private static final String PACKAGE = "info.nightscout";
private static final String READ_ACTION =
"info.nightscout.androidaps.ACTION_MESSAGE_READ";
private static final String REPLY_ACTION =
"info.nightscout.androidaps.ACTION_MESSAGE_REPLY";
private static final String CONVERSATION_ID = "conversation_id";
private static final String EXTRA_VOICE_REPLY = "extra_voice_reply";
/// End Android Auto
public PersistentNotificationPlugin(Context ctx) {
super(new PluginDescription()
.mainType(PluginType.GENERAL)
@ -107,7 +127,8 @@ public class PersistentNotificationPlugin extends PluginBase {
return null;
}
String line1 = "";
String line1;
String line1_aa;
if (ConfigBuilderPlugin.getPlugin().getActiveProfileInterface() == null || !ProfileFunctions.getInstance().isProfileValid("Notificiation"))
return null;
@ -118,22 +139,25 @@ public class PersistentNotificationPlugin extends PluginBase {
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
if (lastBG != null) {
line1 = lastBG.valueToUnitsToString(units);
line1 = line1_aa = lastBG.valueToUnitsToString(units);
if (glucoseStatus != null) {
line1 += " Δ" + deltastring(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
+ " avgΔ" + deltastring(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units);
line1_aa += " " + lastBG.directionToSymbol();
} else {
line1 += " " +
MainApp.gs(R.string.old_data) +
" ";
line1_aa += line1 + ".";
}
} else {
line1 = MainApp.gs(R.string.missed_bg_readings);
line1 = line1_aa = MainApp.gs(R.string.missed_bg_readings);
}
TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(System.currentTimeMillis());
if (activeTemp != null) {
line1 += " " + activeTemp.toStringShort();
line1_aa += " " + activeTemp.toStringShort() + ".";
}
//IOB
@ -143,12 +167,55 @@ public class PersistentNotificationPlugin extends PluginBase {
IobTotal basalIob = TreatmentsPlugin.getPlugin().getLastCalculationTempBasals().round();
String line2 = MainApp.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U " + MainApp.gs(R.string.cob)+": " + IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "PersistentNotificationPlugin").generateCOBString();;
String line2 = MainApp.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U " + MainApp.gs(R.string.cob)+": " + IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "PersistentNotificationPlugin").generateCOBString();
String line2_aa = MainApp.gs(R.string.treatments_iob_label_string) + " " + DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U. " + MainApp.gs(R.string.cob)+": " + IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "PersistentNotificationPlugin").generateCOBString() + ".";
String line3 = DecimalFormatter.to2Decimal(ConfigBuilderPlugin.getPlugin().getActivePump().getBaseBasalRate()) + " U/h";
String line3_aa = DecimalFormatter.to2Decimal(ConfigBuilderPlugin.getPlugin().getActivePump().getBaseBasalRate()) + " U/h.";
line3 += " - " + ProfileFunctions.getInstance().getProfileName();
line3_aa += " - " + ProfileFunctions.getInstance().getProfileName() + ".";
/// For Android Auto
Intent msgReadIntent = new Intent()
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
.setAction(READ_ACTION)
.putExtra(CONVERSATION_ID, ONGOING_NOTIFICATION_ID)
.setPackage(PACKAGE);
PendingIntent msgReadPendingIntent =
PendingIntent.getBroadcast(ctx,
ONGOING_NOTIFICATION_ID,
msgReadIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Intent msgReplyIntent = new Intent()
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
.setAction(REPLY_ACTION)
.putExtra(CONVERSATION_ID, ONGOING_NOTIFICATION_ID)
.setPackage(PACKAGE);
PendingIntent msgReplyPendingIntent = PendingIntent.getBroadcast(
ctx,
ONGOING_NOTIFICATION_ID,
msgReplyIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
// Build a RemoteInput for receiving voice input from devices
RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY).build();
// Create the UnreadConversation
NotificationCompat.CarExtender.UnreadConversation.Builder unreadConversationBuilder =
new NotificationCompat.CarExtender.UnreadConversation.Builder(line1_aa + "\n" + line2_aa)
.setLatestTimestamp(System.currentTimeMillis())
.setReadPendingIntent(msgReadPendingIntent)
.setReplyAction(msgReplyPendingIntent, remoteInput);
/// Add dot to produce a "more natural sounding result"
unreadConversationBuilder.addMessage(line3_aa);
/// End Android Auto
NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx, CHANNEL_ID);
@ -167,6 +234,11 @@ public class PersistentNotificationPlugin extends PluginBase {
builder.setContentTitle(line1);
builder.setContentText(line2);
builder.setSubText(line3);
/// Android Auto
builder.extend(new NotificationCompat.CarExtender()
.setUnreadConversation(unreadConversationBuilder.build()));
/// End Android Auto
Intent resultIntent = new Intent(ctx, MainActivity.class);

View file

@ -156,7 +156,7 @@ public class LocalProfileFragment extends SubscriberFragment {
public String getSumLabel() {
ProfileStore profile = LocalProfilePlugin.getPlugin().createProfileStore();
if (profile != null)
return "" + DecimalFormatter.to2Decimal(profile.getDefaultProfile().baseBasalSum()) + "U";
return "" + DecimalFormatter.to2Decimal(profile.getDefaultProfile().baseBasalSum()) + MainApp.gs(R.string.insulin_unit_shortname);
else
return MainApp.gs(R.string.localprofile);
}

View file

@ -52,6 +52,8 @@ public class NSProfileFragment extends SubscriberFragment {
TextView isf;
@BindView(R.id.profileview_basal)
TextView basal;
@BindView(R.id.profileview_basaltotal)
TextView basaltotal;
@BindView(R.id.profileview_target)
TextView target;
@BindView(R.id.basal_graph)
@ -116,6 +118,7 @@ public class NSProfileFragment extends SubscriberFragment {
ic.setText(profile.getIcList());
isf.setText(profile.getIsfList());
basal.setText(profile.getBasalList());
basaltotal.setText(String.format(MainApp.gs(R.string.profile_total), DecimalFormatter.to2Decimal(profile.baseBasalSum())));
target.setText(profile.getTargetList());
basalGraph.show(profile);
}
@ -141,6 +144,7 @@ public class NSProfileFragment extends SubscriberFragment {
ic.setText("");
isf.setText("");
basal.setText("");
basaltotal.setText("");
target.setText("");
activateButton.setVisibility(View.GONE);
}

View file

@ -435,6 +435,23 @@ public class ComboPlugin extends PluginBase implements PumpInterface, Constraint
return pump.basalProfile.hourlyRates[currentHour];
}
@Override
public double getReservoirLevel() {
return pump.reservoirLevel;
}
@Override
public int getBatteryLevel() {
switch (pump.state.batteryState) {
case PumpState.EMPTY:
return 5;
case PumpState.LOW:
return 25;
default:
return 100;
}
}
private static BolusProgressReporter bolusProgressReporter = (state, percent, delivered) -> {
EventOverviewBolusProgress event = EventOverviewBolusProgress.getInstance();
switch (state) {
@ -653,11 +670,7 @@ public class ComboPlugin extends PluginBase implements PumpInterface, Constraint
}
}
/**
* Updates a DetailedBolusInfo from a pump bolus and adds it as a Treatment to the DB.
* Handles edge cases when dates aren't unique which are extremely unlikely to occur,
* but if they do, the user should be warned since a bolus will be missing from calculations.
*/
/** Creates a treatment record based on the request in DetailBolusInfo and the delivered bolus. */
private boolean addBolusToTreatments(DetailedBolusInfo detailedBolusInfo, Bolus lastPumpBolus) {
DetailedBolusInfo dbi = detailedBolusInfo.copy();
dbi.date = calculateFakeBolusDate(lastPumpBolus);
@ -665,15 +678,7 @@ public class ComboPlugin extends PluginBase implements PumpInterface, Constraint
dbi.source = Source.PUMP;
dbi.insulin = lastPumpBolus.amount;
try {
boolean treatmentCreated = TreatmentsPlugin.getPlugin().addToHistoryTreatment(dbi, false);
if (!treatmentCreated) {
log.error("Adding treatment record overrode an existing record: " + dbi);
if (dbi.isSMB) {
Notification notification = new Notification(Notification.COMBO_PUMP_ALARM, MainApp.gs(R.string.combo_error_updating_treatment_record), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
}
return false;
}
TreatmentsPlugin.getPlugin().addToHistoryTreatment(dbi, true);
} catch (Exception e) {
log.error("Adding treatment record failed", e);
if (dbi.isSMB) {
@ -1149,6 +1154,7 @@ public class ComboPlugin extends PluginBase implements PumpInterface, Constraint
return historyResult.success;
}
/** Return value indicates whether a new record was created. */
private boolean updateDbFromPumpHistory(@NonNull PumpHistory history) {
boolean updated = false;
for (Bolus pumpBolus : history.bolusHistory) {
@ -1158,8 +1164,7 @@ public class ComboPlugin extends PluginBase implements PumpInterface, Constraint
dbi.source = Source.PUMP;
dbi.insulin = pumpBolus.amount;
dbi.eventType = CareportalEvent.CORRECTIONBOLUS;
if (TreatmentsPlugin.getPlugin().getService().getPumpRecordById(dbi.pumpId) == null) {
TreatmentsPlugin.getPlugin().addToHistoryTreatment(dbi, false);
if (TreatmentsPlugin.getPlugin().addToHistoryTreatment(dbi, true)) {
updated = true;
}
}

View file

@ -56,7 +56,7 @@ public enum PumpType {
AnimasVibe("Animas Vibe", 0.05d, null, // AnimasBolus?
new DoseSettings(0.05d, 30, 12*60, 0.05d), //
PumpTempBasalType.Percent, //
new DoseSettings(10, 30, 24*60, 0d, 200d), PumpCapability.BasalRate_Duration30minAllowed, //
new DoseSettings(10, 30, 24*60, 0d, 300d), PumpCapability.BasalRate_Duration30minAllowed, //
0.025d, 5d, 0d, null, PumpCapability.VirtualPumpCapabilities), //
AnimasPing("Animas Ping", AnimasVibe),

View file

@ -152,6 +152,12 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
return DanaRPump.getInstance().currentBasal;
}
@Override
public double getReservoirLevel() { return DanaRPump.getInstance().reservoirRemainingUnits; }
@Override
public int getBatteryLevel() { return DanaRPump.getInstance().batteryRemaining; }
@Override
public void stopBolusDelivering() {
if (sExecutionService == null) {

View file

@ -20,7 +20,7 @@ import info.nightscout.utils.SP;
* Created by mike on 04.07.2016.
*/
public class DanaRPump {
private Logger log = LoggerFactory.getLogger(L.PUMP);
private static Logger log = LoggerFactory.getLogger(L.PUMP);
private static DanaRPump instance = null;
@ -30,6 +30,7 @@ public class DanaRPump {
}
public static void reset() {
log.debug("DanaRPump reset");
instance = null;
}

View file

@ -40,6 +40,7 @@ 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.androidaps.plugins.Treatments.Treatment;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.SP;
import info.nightscout.utils.ToastUtils;
@ -55,7 +56,6 @@ public abstract class AbstractDanaRExecutionService extends Service {
protected BluetoothSocket mRfcommSocket;
protected BluetoothDevice mBTDevice;
protected DanaRPump mDanaRPump = DanaRPump.getInstance();
protected Treatment mBolusingTreatment = null;
protected boolean mConnectionInProgress = false;
@ -237,4 +237,15 @@ public abstract class AbstractDanaRExecutionService extends Service {
result.comment = "OK";
return result;
}
protected void waitForWholeMinute() {
while (true) {
long time = DateUtil.now();
long timeToWholeMinute = (60000 - time % 60000);
if (timeToWholeMinute > 59800 || timeToWholeMinute < 3000)
break;
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.waitingfortimesynchronization, (int) (timeToWholeMinute / 1000))));
SystemClock.sleep(Math.min(timeToWholeMinute, 100));
}
}
}

View file

@ -133,6 +133,7 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService {
}
public void getPumpStatus() {
DanaRPump danaRPump = DanaRPump.getInstance();
try {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumpstatus)));
MsgStatus statusMsg = new MsgStatus();
@ -141,7 +142,7 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService {
MsgStatusBolusExtended exStatusMsg = new MsgStatusBolusExtended();
MsgCheckValue checkValue = new MsgCheckValue();
if (mDanaRPump.isNewPump) {
if (danaRPump.isNewPump) {
mSerialIOThread.sendMessage(checkValue);
if (!checkValue.received) {
return;
@ -157,11 +158,11 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingbolusstatus)));
long now = System.currentTimeMillis();
mDanaRPump.lastConnection = now;
danaRPump.lastConnection = now;
Profile profile = ProfileFunctions.getInstance().getProfile();
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (profile != null && Math.abs(mDanaRPump.currentBasal - profile.getBasal()) >= pump.getPumpDescription().basalStep) {
if (profile != null && Math.abs(danaRPump.currentBasal - profile.getBasal()) >= pump.getPumpDescription().basalStep) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumpsettings)));
mSerialIOThread.sendMessage(new MsgSettingBasal());
if (!pump.isThisProfileSet(profile) && !ConfigBuilderPlugin.getPlugin().getCommandQueue().isRunning(Command.CommandType.BASALPROFILE)) {
@ -169,7 +170,7 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService {
}
}
if (mDanaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !pump.isInitialized()) {
if (danaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !pump.isInitialized()) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumpsettings)));
mSerialIOThread.sendMessage(new MsgSettingShippingInfo());
mSerialIOThread.sendMessage(new MsgSettingActiveProfile());
@ -184,29 +185,29 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService {
mSerialIOThread.sendMessage(new MsgSettingUserOptions());
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumptime)));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
long timeDiff = (mDanaRPump.pumpTime - System.currentTimeMillis()) / 1000L;
long timeDiff = (danaRPump.pumpTime - System.currentTimeMillis()) / 1000L;
if (L.isEnabled(L.PUMP))
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 10) {
mSerialIOThread.sendMessage(new MsgSetTime(new Date()));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
timeDiff = (mDanaRPump.pumpTime - System.currentTimeMillis()) / 1000L;
timeDiff = (danaRPump.pumpTime - System.currentTimeMillis()) / 1000L;
if (L.isEnabled(L.PUMP))
log.debug("Pump time difference: " + timeDiff + " seconds");
}
mDanaRPump.lastSettingsRead = now;
danaRPump.lastSettingsRead = now;
}
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
NSUpload.uploadDeviceStatus();
if (mDanaRPump.dailyTotalUnits > mDanaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
if (danaRPump.dailyTotalUnits > danaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
if (L.isEnabled(L.PUMP))
log.debug("Approaching daily limit: " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits);
log.debug("Approaching daily limit: " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits);
if (System.currentTimeMillis() > lastApproachingDailyLimit + 30 * 60 * 1000) {
Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, MainApp.gs(R.string.approachingdailylimit), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(reportFail));
NSUpload.uploadError(MainApp.gs(R.string.approachingdailylimit) + ": " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits + "U");
NSUpload.uploadError(MainApp.gs(R.string.approachingdailylimit) + ": " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits + "U");
lastApproachingDailyLimit = System.currentTimeMillis();
}
}
@ -216,8 +217,9 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService {
}
public boolean tempBasal(int percent, int durationInHours) {
DanaRPump danaRPump = DanaRPump.getInstance();
if (!isConnected()) return false;
if (mDanaRPump.isTempBasalInProgress) {
if (danaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
SystemClock.sleep(500);
@ -262,6 +264,7 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService {
}
public boolean bolus(double amount, int carbs, long carbtime, final Treatment t) {
DanaRPump danaRPump = DanaRPump.getInstance();
if (!isConnected()) return false;
if (BolusProgressDialog.stopPressed) return false;
@ -335,13 +338,13 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService {
ConfigBuilderPlugin.getPlugin().getCommandQueue().independentConnect("bolusingInterrupted", new Callback() {
@Override
public void run() {
if (mDanaRPump.lastBolusTime > System.currentTimeMillis() - 60 * 1000L) { // last bolus max 1 min old
t.insulin = mDanaRPump.lastBolusAmount;
if (danaRPump.lastBolusTime > System.currentTimeMillis() - 60 * 1000L) { // last bolus max 1 min old
t.insulin = danaRPump.lastBolusAmount;
if (L.isEnabled(L.PUMP))
log.debug("Used bolus amount from history: " + mDanaRPump.lastBolusAmount);
log.debug("Used bolus amount from history: " + danaRPump.lastBolusAmount);
} else {
if (L.isEnabled(L.PUMP))
log.debug("Bolus amount in history too old: " + DateUtil.dateAndTimeFullString(mDanaRPump.lastBolusTime));
log.debug("Bolus amount in history too old: " + DateUtil.dateAndTimeFullString(danaRPump.lastBolusTime));
}
synchronized (o) {
o.notify();
@ -379,6 +382,7 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService {
}
public boolean updateBasalsInPump(final Profile profile) {
DanaRPump danaRPump = DanaRPump.getInstance();
if (!isConnected()) return false;
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.updatingbasalrates)));
double[] basal = DanaRPump.getInstance().buildDanaRProfileRecord(profile);
@ -386,7 +390,7 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService {
mSerialIOThread.sendMessage(msgSet);
MsgSetActivateBasalProfile msgActivate = new MsgSetActivateBasalProfile((byte) 0);
mSerialIOThread.sendMessage(msgActivate);
mDanaRPump.lastSettingsRead = 0; // force read full settings
danaRPump.lastSettingsRead = 0; // force read full settings
getPumpStatus();
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING));
return true;

View file

@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
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;
@ -51,5 +52,9 @@ public class MsgInitConnStatusBolus_k extends MessageBase {
} else {
MainApp.bus().post(new EventDismissNotification(Notification.EXTENDED_BOLUS_DISABLED));
}
// This is last message of initial sequence
if (ConfigBuilderPlugin.getPlugin().getActivePump() != null)
ConfigBuilderPlugin.getPlugin().getActivePump().finishHandshaking();
}
}

View file

@ -24,6 +24,7 @@ import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
@ -55,8 +56,8 @@ import info.nightscout.androidaps.plugins.PumpDanaRKorean.comm.MsgSettingBasal_k
import info.nightscout.androidaps.plugins.PumpDanaRKorean.comm.MsgStatusBasic_k;
import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.queue.commands.Command;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
import info.nightscout.utils.SP;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.T;
public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
@ -137,6 +138,7 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
}
public void getPumpStatus() {
DanaRPump danaRPump = DanaRPump.getInstance();
try {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumpstatus)));
//MsgStatus_k statusMsg = new MsgStatus_k();
@ -145,7 +147,7 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
MsgStatusBolusExtended exStatusMsg = new MsgStatusBolusExtended();
MsgCheckValue_k checkValue = new MsgCheckValue_k();
if (mDanaRPump.isNewPump) {
if (danaRPump.isNewPump) {
mSerialIOThread.sendMessage(checkValue);
if (!checkValue.received) {
return;
@ -161,11 +163,11 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingbolusstatus)));
long now = System.currentTimeMillis();
mDanaRPump.lastConnection = now;
danaRPump.lastConnection = now;
Profile profile = ProfileFunctions.getInstance().getProfile();
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (profile != null && Math.abs(mDanaRPump.currentBasal - profile.getBasal()) >= pump.getPumpDescription().basalStep) {
if (profile != null && Math.abs(danaRPump.currentBasal - profile.getBasal()) >= pump.getPumpDescription().basalStep) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumpsettings)));
mSerialIOThread.sendMessage(new MsgSettingBasal());
if (!pump.isThisProfileSet(profile) && !ConfigBuilderPlugin.getPlugin().getCommandQueue().isRunning(Command.CommandType.BASALPROFILE)) {
@ -173,7 +175,7 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
}
}
if (mDanaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !pump.isInitialized()) {
if (danaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !pump.isInitialized()) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumpsettings)));
mSerialIOThread.sendMessage(new MsgSettingShippingInfo());
mSerialIOThread.sendMessage(new MsgSettingMeal());
@ -184,29 +186,31 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
mSerialIOThread.sendMessage(new MsgSettingProfileRatios());
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumptime)));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
long timeDiff = (mDanaRPump.pumpTime - System.currentTimeMillis()) / 1000L;
long timeDiff = (danaRPump.pumpTime - System.currentTimeMillis()) / 1000L;
if (L.isEnabled(L.PUMP))
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 10) {
mSerialIOThread.sendMessage(new MsgSetTime(new Date()));
waitForWholeMinute(); // Dana can set only whole minute
// add 10sec to be sure we are over minute (will be cutted off anyway)
mSerialIOThread.sendMessage(new MsgSetTime(new Date(DateUtil.now() + T.secs(10).msecs())));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
timeDiff = (mDanaRPump.pumpTime - System.currentTimeMillis()) / 1000L;
timeDiff = (danaRPump.pumpTime - System.currentTimeMillis()) / 1000L;
if (L.isEnabled(L.PUMP))
log.debug("Pump time difference: " + timeDiff + " seconds");
}
mDanaRPump.lastSettingsRead = now;
danaRPump.lastSettingsRead = now;
}
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
NSUpload.uploadDeviceStatus();
if (mDanaRPump.dailyTotalUnits > mDanaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
if (danaRPump.dailyTotalUnits > danaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
if (L.isEnabled(L.PUMP))
log.debug("Approaching daily limit: " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits);
log.debug("Approaching daily limit: " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits);
if (System.currentTimeMillis() > lastApproachingDailyLimit + 30 * 60 * 1000) {
Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, MainApp.gs(R.string.approachingdailylimit), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(reportFail));
NSUpload.uploadError(MainApp.gs(R.string.approachingdailylimit) + ": " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits + "U");
NSUpload.uploadError(MainApp.gs(R.string.approachingdailylimit) + ": " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits + "U");
lastApproachingDailyLimit = System.currentTimeMillis();
}
}
@ -216,8 +220,9 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
}
public boolean tempBasal(int percent, int durationInHours) {
DanaRPump danaRPump = DanaRPump.getInstance();
if (!isConnected()) return false;
if (mDanaRPump.isTempBasalInProgress) {
if (danaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
SystemClock.sleep(500);
@ -318,12 +323,13 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
}
public boolean updateBasalsInPump(final Profile profile) {
DanaRPump danaRPump = DanaRPump.getInstance();
if (!isConnected()) return false;
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.updatingbasalrates)));
double[] basal = DanaRPump.getInstance().buildDanaRProfileRecord(profile);
MsgSetSingleBasalProfile msgSet = new MsgSetSingleBasalProfile(basal);
mSerialIOThread.sendMessage(msgSet);
mDanaRPump.lastSettingsRead = 0; // force read full settings
danaRPump.lastSettingsRead = 0; // force read full settings
getPumpStatus();
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING));
return true;

View file

@ -373,6 +373,12 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
return DanaRPump.getInstance().currentBasal;
}
@Override
public double getReservoirLevel() { return DanaRPump.getInstance().reservoirRemainingUnits; }
@Override
public int getBatteryLevel() { return DanaRPump.getInstance().batteryRemaining; }
@Override
public synchronized PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
detailedBolusInfo.insulin = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(detailedBolusInfo.insulin)).value();
@ -415,6 +421,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
if (!result.success) {
String error = "" + DanaRS_Packet_Bolus_Set_Step_Bolus_Start.errorCode;
switch (DanaRS_Packet_Bolus_Set_Step_Bolus_Start.errorCode) {
// 4 reported as max bolus violation. Check later
case 0x10:
error = MainApp.gs(R.string.maxbolusviolation);
break;

View file

@ -45,6 +45,12 @@ public class DanaRS_Packet_APS_History_Events extends DanaRS_Packet {
public DanaRS_Packet_APS_History_Events(long from) {
this();
GregorianCalendar cal = new GregorianCalendar();
if (from > DateUtil.now()) {
log.debug("Asked to load from the future");
from = 0;
}
if (from != 0)
cal.setTimeInMillis(from);
else

View file

@ -144,9 +144,9 @@ public class BLEComm {
if (L.isEnabled(L.PUMPBTCOMM))
log.debug("Trying to create a new connection from: " + from);
mBluetoothDeviceName = device.getName();
mBluetoothGatt = device.connectGatt(service.getApplicationContext(), false, mGattCallback);
setCharacteristicNotification(getUARTReadBTGattChar(), true);
mBluetoothDeviceName = device.getName();
return true;
}
@ -662,7 +662,13 @@ public class BLEComm {
private void SendPumpCheck() {
// 1st message sent to pump after connect
byte[] bytes = BleCommandUtil.getInstance().getEncryptedPacket(BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK, null, getConnectDeviceName());
String devicename = getConnectDeviceName();
if(devicename == null || devicename.equals("")){
Notification n = new Notification(Notification.DEVICENOTPAIRED, MainApp.gs(R.string.pairfirst), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(n));
return;
}
byte[] bytes = BleCommandUtil.getInstance().getEncryptedPacket(BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK, null, devicename);
if (L.isEnabled(L.PUMPBTCOMM))
log.debug(">>>>> " + "ENCRYPTION__PUMP_CHECK (0x00)" + " " + DanaRS_Packet.toHexString(bytes));
writeCharacteristic_NO_RESPONSE(getUARTWriteBTGattChar(), bytes);

View file

@ -26,23 +26,30 @@ public class MsgHistoryEvents_v2 extends MessageBase {
public static long lastEventTimeLoaded = 0;
public MsgHistoryEvents_v2(long from) {
SetCommand(0xE003);
GregorianCalendar gfrom = new GregorianCalendar();
gfrom.setTimeInMillis(from);
AddParamDate(gfrom);
done = false;
if (L.isEnabled(L.PUMPCOMM))
log.debug("New message");
public MsgHistoryEvents_v2() {
this(0);
}
public MsgHistoryEvents_v2() {
public MsgHistoryEvents_v2(long from) {
SetCommand(0xE003);
AddParamByte((byte) 0);
AddParamByte((byte) 1);
AddParamByte((byte) 1);
AddParamByte((byte) 0);
AddParamByte((byte) 0);
if (from > DateUtil.now()) {
log.debug("Asked to load from the future");
from = 0;
}
if (from == 0) {
AddParamByte((byte) 0);
AddParamByte((byte) 1);
AddParamByte((byte) 1);
AddParamByte((byte) 0);
AddParamByte((byte) 0);
} else {
GregorianCalendar gfrom = new GregorianCalendar();
gfrom.setTimeInMillis(from);
AddParamDate(gfrom);
}
done = false;
if (L.isEnabled(L.PUMPCOMM))
log.debug("New message");

View file

@ -25,6 +25,7 @@ import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
import info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog;
import info.nightscout.androidaps.plugins.Overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
@ -71,7 +72,6 @@ import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.queue.commands.Command;
import info.nightscout.utils.DateUtil;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
import info.nightscout.utils.SP;
import info.nightscout.utils.T;
@ -156,6 +156,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
}
public void getPumpStatus() {
DanaRPump danaRPump = DanaRPump.getInstance();
try {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumpstatus)));
MsgStatus statusMsg = new MsgStatus();
@ -164,7 +165,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
MsgStatusBolusExtended_v2 exStatusMsg = new MsgStatusBolusExtended_v2();
MsgCheckValue_v2 checkValue = new MsgCheckValue_v2();
if (mDanaRPump.isNewPump) {
if (danaRPump.isNewPump) {
mSerialIOThread.sendMessage(checkValue);
if (!checkValue.received) {
return;
@ -179,11 +180,11 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingextendedbolusstatus)));
mSerialIOThread.sendMessage(exStatusMsg);
mDanaRPump.lastConnection = System.currentTimeMillis();
danaRPump.lastConnection = System.currentTimeMillis();
Profile profile = ProfileFunctions.getInstance().getProfile();
PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
if (profile != null && Math.abs(mDanaRPump.currentBasal - profile.getBasal()) >= pump.getPumpDescription().basalStep) {
if (profile != null && Math.abs(danaRPump.currentBasal - profile.getBasal()) >= pump.getPumpDescription().basalStep) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumpsettings)));
mSerialIOThread.sendMessage(new MsgSettingBasal());
if (!pump.isThisProfileSet(profile) && !ConfigBuilderPlugin.getPlugin().getCommandQueue().isRunning(Command.CommandType.BASALPROFILE)) {
@ -193,7 +194,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumptime)));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
long timeDiff = (mDanaRPump.pumpTime - System.currentTimeMillis()) / 1000L;
long timeDiff = (danaRPump.pumpTime - System.currentTimeMillis()) / 1000L;
if (L.isEnabled(L.PUMP))
log.debug("Pump time difference: " + timeDiff + " seconds");
if (Math.abs(timeDiff) > 3) {
@ -209,7 +210,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
MainApp.instance().startActivity(i);
//deinitialize pump
mDanaRPump.lastConnection = 0;
danaRPump.lastConnection = 0;
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
return;
@ -218,14 +219,14 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
// add 10sec to be sure we are over minute (will be cutted off anyway)
mSerialIOThread.sendMessage(new MsgSetTime(new Date(DateUtil.now() + T.secs(10).msecs())));
mSerialIOThread.sendMessage(new MsgSettingPumpTime());
timeDiff = (mDanaRPump.pumpTime - System.currentTimeMillis()) / 1000L;
timeDiff = (danaRPump.pumpTime - System.currentTimeMillis()) / 1000L;
if (L.isEnabled(L.PUMP))
log.debug("Pump time difference: " + timeDiff + " seconds");
}
}
long now = System.currentTimeMillis();
if (mDanaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !pump.isInitialized()) {
if (danaRPump.lastSettingsRead + 60 * 60 * 1000L < now || !pump.isInitialized()) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.gettingpumpsettings)));
mSerialIOThread.sendMessage(new MsgSettingShippingInfo());
mSerialIOThread.sendMessage(new MsgSettingActiveProfile());
@ -238,7 +239,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
mSerialIOThread.sendMessage(new MsgSettingProfileRatios());
mSerialIOThread.sendMessage(new MsgSettingUserOptions());
mSerialIOThread.sendMessage(new MsgSettingProfileRatiosAll());
mDanaRPump.lastSettingsRead = now;
danaRPump.lastSettingsRead = now;
}
loadEvents();
@ -246,13 +247,13 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
MainApp.bus().post(new EventDanaRNewStatus());
MainApp.bus().post(new EventInitializationChanged());
NSUpload.uploadDeviceStatus();
if (mDanaRPump.dailyTotalUnits > mDanaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
if (danaRPump.dailyTotalUnits > danaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) {
if (L.isEnabled(L.PUMP))
log.debug("Approaching daily limit: " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits);
log.debug("Approaching daily limit: " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits);
if (System.currentTimeMillis() > lastApproachingDailyLimit + 30 * 60 * 1000) {
Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, MainApp.gs(R.string.approachingdailylimit), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(reportFail));
NSUpload.uploadError(MainApp.gs(R.string.approachingdailylimit) + ": " + mDanaRPump.dailyTotalUnits + "/" + mDanaRPump.maxDailyTotalUnits + "U");
NSUpload.uploadError(MainApp.gs(R.string.approachingdailylimit) + ": " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits + "U");
lastApproachingDailyLimit = System.currentTimeMillis();
}
}
@ -262,8 +263,9 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
}
public boolean tempBasal(int percent, int durationInHours) {
DanaRPump danaRPump = DanaRPump.getInstance();
if (!isConnected()) return false;
if (mDanaRPump.isTempBasalInProgress) {
if (danaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
SystemClock.sleep(500);
@ -277,8 +279,9 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
}
public boolean highTempBasal(int percent) {
DanaRPump danaRPump = DanaRPump.getInstance();
if (!isConnected()) return false;
if (mDanaRPump.isTempBasalInProgress) {
if (danaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
SystemClock.sleep(500);
@ -292,13 +295,14 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
}
public boolean tempBasalShortDuration(int percent, int durationInMinutes) {
DanaRPump danaRPump = DanaRPump.getInstance();
if (durationInMinutes != 15 && durationInMinutes != 30) {
log.error("Wrong duration param");
return false;
}
if (!isConnected()) return false;
if (mDanaRPump.isTempBasalInProgress) {
if (danaRPump.isTempBasalInProgress) {
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.stoppingtempbasal)));
mSerialIOThread.sendMessage(new MsgSetTempBasalStop());
SystemClock.sleep(500);
@ -449,6 +453,7 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
}
public PumpEnactResult loadEvents() {
DanaRPump danaRPump = DanaRPump.getInstance();
if (!MainApp.getSpecificPlugin(DanaRv2Plugin.class).isInitialized()) {
PumpEnactResult result = new PumpEnactResult().success(false);
@ -460,16 +465,10 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
if (!isConnected())
return new PumpEnactResult().success(false);
SystemClock.sleep(300);
MsgHistoryEvents_v2 msg;
if (lastHistoryFetched == 0) {
msg = new MsgHistoryEvents_v2();
if (L.isEnabled(L.PUMP))
log.debug("Loading complete event history");
} else {
msg = new MsgHistoryEvents_v2(lastHistoryFetched);
if (L.isEnabled(L.PUMP))
log.debug("Loading event history from: " + DateUtil.dateAndTimeFullString(lastHistoryFetched));
}
MsgHistoryEvents_v2 msg = new MsgHistoryEvents_v2(lastHistoryFetched);
if (L.isEnabled(L.PUMP))
log.debug("Loading event history from: " + DateUtil.dateAndTimeFullString(lastHistoryFetched));
mSerialIOThread.sendMessage(msg);
while (!msg.done && mRfcommSocket.isConnected()) {
SystemClock.sleep(100);
@ -479,11 +478,12 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
lastHistoryFetched = MsgHistoryEvents_v2.lastEventTimeLoaded - T.mins(1).msecs();
else
lastHistoryFetched = 0;
mDanaRPump.lastConnection = System.currentTimeMillis();
danaRPump.lastConnection = System.currentTimeMillis();
return new PumpEnactResult().success(true);
}
public boolean updateBasalsInPump(final Profile profile) {
DanaRPump danaRPump = DanaRPump.getInstance();
if (!isConnected()) return false;
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.updatingbasalrates)));
double[] basal = DanaRPump.getInstance().buildDanaRProfileRecord(profile);
@ -491,23 +491,12 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
mSerialIOThread.sendMessage(msgSet);
MsgSetActivateBasalProfile msgActivate = new MsgSetActivateBasalProfile((byte) 0);
mSerialIOThread.sendMessage(msgActivate);
mDanaRPump.lastSettingsRead = 0; // force read full settings
danaRPump.lastSettingsRead = 0; // force read full settings
getPumpStatus();
MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING));
return true;
}
void waitForWholeMinute() {
while (true) {
long time = DateUtil.now();
long timeToWholeMinute = (60000 - time % 60000);
if (timeToWholeMinute > 59800 || timeToWholeMinute < 3000)
break;
MainApp.bus().post(new EventPumpStatusChanged(MainApp.gs(R.string.waitingfortimesynchronization, (int) (timeToWholeMinute / 1000))));
SystemClock.sleep(Math.min(timeToWholeMinute, 100));
}
}
public PumpEnactResult setUserOptions() {
if (!isConnected())
return new PumpEnactResult().success(false);

View file

@ -408,6 +408,12 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
return basalRate;
}
@Override
public double getReservoirLevel() { return reservoirInUnits; }
@Override
public int getBatteryLevel() { return batteryPercent; }
public String getBaseBasalRateString() {
final DecimalFormat df = new DecimalFormat("#.##");
return df.format(basalRate);

View file

@ -0,0 +1,6 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal;
import info.nightscout.androidaps.events.EventUpdateGui;
public class EventLocalInsightUpdateGUI extends EventUpdateGui {
}

View file

@ -0,0 +1,233 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Vibrator;
import android.support.annotation.Nullable;
import info.nightscout.androidaps.plugins.PumpInsightLocal.activities.InsightAlertActivity;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.remote_control.ConfirmAlertMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.remote_control.SnoozeAlertMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.status.GetActiveAlertMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.connection_service.InsightConnectionService;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.Alert;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.AlertStatus;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.AlertType;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.InsightState;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ExceptionTranslator;
public class InsightAlertService extends Service implements InsightConnectionService.StateCallback {
private LocalBinder localBinder = new LocalBinder();
private boolean connectionRequested;
private final Object $alertLock = new Object[0];
private Alert alert;
private Thread thread;
private InsightAlertActivity alertActivity;
private Ringtone ringtone;
private Vibrator vibrator;
private boolean vibrating;
private InsightConnectionService connectionService;
private long ignoreTimestamp;
private AlertType ignoreType;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
connectionService = ((InsightConnectionService.LocalBinder) binder).getService();
connectionService.registerStateCallback(InsightAlertService.this);
stateChanged(connectionService.getState());
}
@Override
public void onServiceDisconnected(ComponentName name) {
connectionService = null;
}
};
private void retrieveRingtone() {
Uri uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
ringtone = RingtoneManager.getRingtone(this, uri);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ringtone.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
.setLegacyStreamType(AudioManager.STREAM_RING).build());
} else ringtone.setStreamType(AudioManager.STREAM_RING);
}
public Alert getAlert() {
synchronized ($alertLock) {
return alert;
}
}
public void setAlertActivity(InsightAlertActivity alertActivity) {
this.alertActivity = alertActivity;
}
public void ignore(AlertType alertType) {
synchronized ($alertLock) {
if (alertType == null) {
ignoreTimestamp = 0;
ignoreType = null;
} else {
ignoreTimestamp = System.currentTimeMillis();
ignoreType = alertType;
}
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return localBinder;
}
@Override
public void onCreate() {
vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
bindService(new Intent(this, InsightConnectionService.class), serviceConnection, BIND_AUTO_CREATE);
}
@Override
public void onDestroy() {
if (thread != null) thread.interrupt();
unbindService(serviceConnection);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public void stateChanged(InsightState state) {
if (state == InsightState.CONNECTED) {
thread = new Thread(this::queryActiveAlert);
thread.start();
} else if (thread != null) thread.interrupt();
}
private void queryActiveAlert() {
while (!Thread.currentThread().isInterrupted()) {
try {
Alert alert = connectionService.requestMessage(new GetActiveAlertMessage()).await().getAlert();
if (Thread.currentThread().isInterrupted()) {
connectionService.withdrawConnectionRequest(thread);
break;
}
synchronized ($alertLock) {
if ((this.alert == null && alert != null)
|| (this.alert != null && alert == null)
|| (this.alert != null && alert != null && !this.alert.equals(alert))) {
if (this.alert != null && (alert == null || this.alert.getAlertId() != alert.getAlertId())) stopAlerting();
this.alert = alert;
if (alertActivity != null && alert != null)
new Handler(Looper.getMainLooper()).post(() -> alertActivity.update(alert));
}
if (alert == null) {
stopAlerting();
if (connectionRequested) {
connectionService.withdrawConnectionRequest(this);
connectionRequested = false;
}
if (alertActivity != null)
new Handler(Looper.getMainLooper()).post(() -> alertActivity.finish());
} else if (!(alert.getAlertType() == ignoreType && System.currentTimeMillis() - ignoreTimestamp < 10000)) {
if (alert.getAlertStatus() == AlertStatus.ACTIVE) alert();
else stopAlerting();
if (!connectionRequested) {
connectionService.requestConnection(this);
connectionRequested = true;
}
if (alertActivity == null) {
Intent intent = new Intent(InsightAlertService.this, InsightAlertActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
new Handler(Looper.getMainLooper()).post(() -> startActivity(intent));
}
}
}
} catch (InterruptedException ignored) {
connectionService.withdrawConnectionRequest(thread);
break;
} catch (Exception ignored) {
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
if (connectionRequested) {
connectionService.withdrawConnectionRequest(thread);
connectionRequested = false;
}
if (alertActivity != null)
new Handler(Looper.getMainLooper()).post(() -> alertActivity.finish());
stopAlerting();
thread = null;
}
private void alert() {
if (!vibrating) {
vibrator.vibrate(new long[] {0, 1000, 1000}, 0);
vibrating = true;
}
if (ringtone == null || !ringtone.isPlaying()) {
retrieveRingtone();
ringtone.play();
}
}
private void stopAlerting() {
if (vibrating) {
vibrator.cancel();
vibrating = false;
}
if (ringtone != null && ringtone.isPlaying()) ringtone.stop();
}
public void mute() {
new Thread(() -> {
try {
SnoozeAlertMessage snoozeAlertMessage = new SnoozeAlertMessage();
snoozeAlertMessage.setAlertID(alert.getAlertId());
connectionService.requestMessage(snoozeAlertMessage).await();
} catch (Exception e) {
ExceptionTranslator.makeToast(InsightAlertService.this, e);
}
}).start();
}
public void confirm() {
new Thread(() -> {
try {
ConfirmAlertMessage confirmAlertMessage = new ConfirmAlertMessage();
confirmAlertMessage.setAlertID(alert.getAlertId());
connectionService.requestMessage(confirmAlertMessage).await();
} catch (Exception e) {
ExceptionTranslator.makeToast(InsightAlertService.this, e);
}
}).start();
}
public class LocalBinder extends Binder {
public InsightAlertService getService() {
return InsightAlertService.this;
}
}
}

View file

@ -0,0 +1,297 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.parameter_blocks.TBROverNotificationBlock;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.ActiveBasalRate;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.ActiveBolus;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.ActiveTBR;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.CartridgeStatus;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.TotalDailyDose;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
public class LocalInsightFragment extends SubscriberFragment implements View.OnClickListener {
private static final boolean ENABLE_OPERATING_MODE_BUTTON = false;
private boolean viewsCreated;
private Button operatingMode;
private Button tbrOverNotification;
private Button refresh;
private LinearLayout statusItemContainer = null;
private Callback operatingModeCallback;
private Callback tbrOverNotificationCallback;
private Callback refreshCallback;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.local_insight_fragment, container, false);
statusItemContainer = view.findViewById(R.id.status_item_container);
tbrOverNotification = view.findViewById(R.id.tbr_over_notification);
tbrOverNotification.setOnClickListener(this);
operatingMode = view.findViewById(R.id.operating_mode);
operatingMode.setOnClickListener(this);
refresh = view.findViewById(R.id.refresh);
refresh.setOnClickListener(this);
viewsCreated = true;
return view;
}
@Override
public synchronized void onDestroyView() {
super.onDestroyView();
viewsCreated = false;
}
@Override
public void onClick(View v) {
if (v == operatingMode) {
if (LocalInsightPlugin.getInstance().getOperatingMode() != null) {
operatingMode.setEnabled(false);
operatingModeCallback = new Callback() {
@Override
public void run() {
new Handler(Looper.getMainLooper()).post(() -> {
operatingModeCallback = null;
updateGUI();
});
}
};
switch (LocalInsightPlugin.getInstance().getOperatingMode()) {
case PAUSED:
case STOPPED:
ConfigBuilderPlugin.getPlugin().getCommandQueue().startPump(operatingModeCallback);
break;
case STARTED:
ConfigBuilderPlugin.getPlugin().getCommandQueue().stopPump(operatingModeCallback);
}
}
} else if (v == tbrOverNotification) {
TBROverNotificationBlock notificationBlock = LocalInsightPlugin.getInstance().getTBROverNotificationBlock();
if (notificationBlock != null) {
tbrOverNotification.setEnabled(false);
tbrOverNotificationCallback = new Callback() {
@Override
public void run() {
new Handler(Looper.getMainLooper()).post(() -> {
tbrOverNotificationCallback = null;
updateGUI();
});
}
};
ConfigBuilderPlugin.getPlugin().getCommandQueue()
.setTBROverNotification(tbrOverNotificationCallback, !notificationBlock.isEnabled());
}
} else if (v == refresh) {
refresh.setEnabled(false);
refreshCallback = new Callback() {
@Override
public void run() {
new Handler(Looper.getMainLooper()).post(() -> {
refreshCallback = null;
updateGUI();
});
}
};
ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("InsightRefreshButton", refreshCallback);
}
}
@Subscribe
public void onUpdateGUIEvent(EventLocalInsightUpdateGUI event) {
updateGUI();
}
@Override
protected void updateGUI() {
if (!viewsCreated) return;
statusItemContainer.removeAllViews();
if (!LocalInsightPlugin.getInstance().isInitialized()) {
operatingMode.setVisibility(View.GONE);
tbrOverNotification.setVisibility(View.GONE);
refresh.setVisibility(View.GONE);
return;
}
refresh.setVisibility(View.VISIBLE);
refresh.setEnabled(refreshCallback == null);
TBROverNotificationBlock notificationBlock = LocalInsightPlugin.getInstance().getTBROverNotificationBlock();
tbrOverNotification.setVisibility(notificationBlock == null ? View.GONE : View.VISIBLE);
if (notificationBlock != null)
tbrOverNotification.setText(notificationBlock.isEnabled() ? R.string.disable_tbr_over_notification : R.string.enable_tbr_over_notification);
tbrOverNotification.setEnabled(tbrOverNotificationCallback == null);
List<View> statusItems = new ArrayList<>();
getConnectionStatusItem(statusItems);
getLastConnectedItem(statusItems);
getOperatingModeItem(statusItems);
getBatteryStatusItem(statusItems);
getCartridgeStatusItem(statusItems);
getTDDItems(statusItems);
getBaseBasalRateItem(statusItems);
getTBRItem(statusItems);
getBolusItems(statusItems);
for (int i = 0; i < statusItems.size(); i++) {
statusItemContainer.addView(statusItems.get(i));
if (i != statusItems.size() - 1)
getLayoutInflater().inflate(R.layout.local_insight_status_delimitter, statusItemContainer);
}
}
private View getStatusItem(String label, String value) {
View statusItem = getLayoutInflater().inflate(R.layout.local_insight_status_item, null);
((TextView) statusItem.findViewById(R.id.label)).setText(label);
((TextView) statusItem.findViewById(R.id.value)).setText(value);
return statusItem;
}
private void getConnectionStatusItem(List<View> statusItems) {
int string = 0;
switch (LocalInsightPlugin.getInstance().getConnectionService().getState()) {
case NOT_PAIRED:
string = R.string.not_paired;
break;
case DISCONNECTED:
string = R.string.disconnected;
break;
case CONNECTING:
case SATL_CONNECTION_REQUEST:
case SATL_KEY_REQUEST:
case SATL_SYN_REQUEST:
case SATL_VERIFY_CONFIRM_REQUEST:
case SATL_VERIFY_DISPLAY_REQUEST:
case APP_ACTIVATE_PARAMETER_SERVICE:
case APP_ACTIVATE_STATUS_SERVICE:
case APP_BIND_MESSAGE:
case APP_CONNECT_MESSAGE:
case APP_FIRMWARE_VERSIONS:
case APP_SYSTEM_IDENTIFICATION:
case AWAITING_CODE_CONFIRMATION:
string = R.string.connecting;
break;
case CONNECTED:
string = R.string.connected;
break;
case RECOVERING:
string = R.string.recovering;
break;
}
statusItems.add(getStatusItem(MainApp.gs(R.string.insight_status), MainApp.gs(string)));
}
private void getLastConnectedItem(List<View> statusItems) {
switch (LocalInsightPlugin.getInstance().getConnectionService().getState()) {
case CONNECTED:
case NOT_PAIRED:
return;
default:
long lastConnection = LocalInsightPlugin.getInstance().getConnectionService().getLastConnected();
if (lastConnection == 0) return;
int min = (int) ((System.currentTimeMillis() - lastConnection) / 60000);
statusItems.add(getStatusItem(MainApp.gs(R.string.last_connected), DateUtil.timeString(lastConnection)));
}
}
private void getOperatingModeItem(List<View> statusItems) {
if (LocalInsightPlugin.getInstance().getOperatingMode() == null) {
operatingMode.setVisibility(View.GONE);
return;
}
int string = 0;
if (ENABLE_OPERATING_MODE_BUTTON) operatingMode.setVisibility(View.VISIBLE);
operatingMode.setEnabled(operatingModeCallback == null);
switch (LocalInsightPlugin.getInstance().getOperatingMode()) {
case STARTED:
operatingMode.setText(R.string.stop_pump);
string = R.string.started;
break;
case STOPPED:
operatingMode.setText(R.string.start_pump);
string = R.string.stopped;
break;
case PAUSED:
operatingMode.setText(R.string.start_pump);
string = R.string.paused;
break;
}
statusItems.add(getStatusItem(MainApp.gs(R.string.operating_mode), MainApp.gs(string)));
}
private void getBatteryStatusItem(List<View> statusItems) {
if (LocalInsightPlugin.getInstance().getBatteryStatus() == null) return;
statusItems.add(getStatusItem(MainApp.gs(R.string.pump_battery_label),
LocalInsightPlugin.getInstance().getBatteryStatus().getBatteryAmount() + "%"));
}
private void getCartridgeStatusItem(List<View> statusItems) {
CartridgeStatus cartridgeStatus = LocalInsightPlugin.getInstance().getCartridgeStatus();
if (cartridgeStatus == null) return;
String status;
if (cartridgeStatus.isInserted())
status = DecimalFormatter.to2Decimal(LocalInsightPlugin.getInstance().getCartridgeStatus().getRemainingAmount()) + "U";
else status = MainApp.gs(R.string.not_inserted);
statusItems.add(getStatusItem(MainApp.gs(R.string.pump_reservoir_label), status));
}
private void getTDDItems(List<View> statusItems) {
if (LocalInsightPlugin.getInstance().getTotalDailyDose() == null) return;
TotalDailyDose tdd = LocalInsightPlugin.getInstance().getTotalDailyDose();
statusItems.add(getStatusItem(MainApp.gs(R.string.tdd_bolus), DecimalFormatter.to2Decimal(tdd.getBolus())));
statusItems.add(getStatusItem(MainApp.gs(R.string.tdd_basal), DecimalFormatter.to2Decimal(tdd.getBasal())));
statusItems.add(getStatusItem(MainApp.gs(R.string.tdd_total), DecimalFormatter.to2Decimal(tdd.getBolusAndBasal())));
}
private void getBaseBasalRateItem(List<View> statusItems) {
if (LocalInsightPlugin.getInstance().getActiveBasalRate() == null) return;
ActiveBasalRate activeBasalRate = LocalInsightPlugin.getInstance().getActiveBasalRate();
statusItems.add(getStatusItem(MainApp.gs(R.string.pump_basebasalrate_label),
DecimalFormatter.to2Decimal(activeBasalRate.getActiveBasalRate()) + " U/h (" + activeBasalRate.getActiveBasalProfileName() + ")"));
}
private void getTBRItem(List<View> statusItems) {
if (LocalInsightPlugin.getInstance().getActiveTBR() == null) return;
ActiveTBR activeTBR = LocalInsightPlugin.getInstance().getActiveTBR();
statusItems.add(getStatusItem(MainApp.gs(R.string.pump_tempbasal_label),
MainApp.gs(R.string.tbr_formatter, activeTBR.getPercentage(), activeTBR.getInitialDuration() - activeTBR.getRemainingDuration(), activeTBR.getInitialDuration())));
}
private void getBolusItems(List<View> statusItems) {
if (LocalInsightPlugin.getInstance().getActiveBoluses() == null) return;
for (ActiveBolus activeBolus : LocalInsightPlugin.getInstance().getActiveBoluses()) {
String label;
switch (activeBolus.getBolusType()) {
case MULTIWAVE:
label = MainApp.gs(R.string.multiwave_bolus);
break;
case EXTENDED:
label = MainApp.gs(R.string.extended_bolus);
break;
default:
continue;
}
statusItems.add(getStatusItem(label, MainApp.gs(R.string.eb_formatter, activeBolus.getRemainingAmount(), activeBolus.getInitialAmount(), activeBolus.getRemainingDuration())));
}
}
}

View file

@ -0,0 +1,257 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.activities;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import java.text.DecimalFormat;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.PumpInsightLocal.InsightAlertService;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.Alert;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.AlertStatus;
public class InsightAlertActivity extends AppCompatActivity {
private Alert alert;
private InsightAlertService alertService;
private ImageView icon;
private TextView errorCode;
private TextView errorTitle;
private TextView errorDescription;
private Button mute;
private Button confirm;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
alertService = ((InsightAlertService.LocalBinder) binder).getService();
alertService.setAlertActivity(InsightAlertActivity.this);
alert = alertService.getAlert();
if (alert == null) finish();
update(alert);
}
@Override
public void onServiceDisconnected(ComponentName name) {
alertService = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_insight_alert);
bindService(new Intent(this, InsightAlertService.class), serviceConnection, BIND_AUTO_CREATE);
icon = findViewById(R.id.icon);
errorCode = findViewById(R.id.error_code);
errorTitle = findViewById(R.id.error_title);
errorDescription = findViewById(R.id.error_description);
mute = findViewById(R.id.mute);
confirm = findViewById(R.id.confirm);
setFinishOnTouchOutside(false);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
layoutParams.screenBrightness = 1.0F;
getWindow().setAttributes(layoutParams);
}
@Override
protected void onDestroy() {
alertService.setAlertActivity(null);
unbindService(serviceConnection);
super.onDestroy();
}
public void update(Alert alert) {
this.alert = alert;
mute.setEnabled(true);
mute.setVisibility(alert.getAlertStatus() == AlertStatus.SNOOZED ? View.GONE : View.VISIBLE);
confirm.setEnabled(true);
int icon = 0;
int code = 0;
int title = 0;
String description = null;
switch (alert.getAlertCategory()) {
case ERROR:
icon = R.drawable.ic_error;
break;
case MAINTENANCE:
icon = R.drawable.ic_maintenance;
break;
case WARNING:
icon = R.drawable.ic_warning;
break;
case REMINDER:
icon = R.drawable.ic_reminder;
break;
}
DecimalFormat decimalFormat = new DecimalFormat("##0.00");
int hours = alert.getTBRDuration() / 60;
int minutes = alert.getTBRDuration() - hours * 60;
switch (alert.getAlertType()) {
case REMINDER_01:
code = R.string.alert_r1_code;
title = R.string.alert_r1_title;
break;
case REMINDER_02:
code = R.string.alert_r2_code;
title = R.string.alert_r2_title;
break;
case REMINDER_03:
code = R.string.alert_r3_code;
title = R.string.alert_r3_title;
break;
case REMINDER_04:
code = R.string.alert_r4_code;
title = R.string.alert_r4_title;
break;
case REMINDER_07:
code = R.string.alert_r7_code;
title = R.string.alert_r7_title;
description = getString(R.string.alert_r7_description, alert.getTBRAmount(), new DecimalFormat("#0").format(hours) + ":" + new DecimalFormat("00").format(minutes));
break;
case WARNING_31:
code = R.string.alert_w31_code;
title = R.string.alert_w31_title;
description = getString(R.string.alert_w31_description, decimalFormat.format(alert.getCartridgeAmount()));
break;
case WARNING_32:
code = R.string.alert_w32_code;
title = R.string.alert_w32_title;
description = getString(R.string.alert_w32_description);
break;
case WARNING_33:
code = R.string.alert_w33_code;
title = R.string.alert_w33_title;
description = getString(R.string.alert_w33_description);
break;
case WARNING_34:
code = R.string.alert_w34_code;
title = R.string.alert_w34_title;
description = getString(R.string.alert_w34_description);
break;
case WARNING_36:
code = R.string.alert_w36_code;
title = R.string.alert_w36_title;
description = getString(R.string.alert_w36_description, alert.getTBRAmount(), new DecimalFormat("#0").format(hours) + ":" + new DecimalFormat("00").format(minutes));
break;
case WARNING_38:
code = R.string.alert_w38_code;
title = R.string.alert_w38_title;
description = getString(R.string.alert_w38_description, decimalFormat.format(alert.getProgrammedBolusAmount()), decimalFormat.format(alert.getDeliveredBolusAmount()));
break;
case WARNING_39:
code = R.string.alert_w39_code;
title = R.string.alert_w39_title;
break;
case MAINTENANCE_20:
code = R.string.alert_m20_code;
title = R.string.alert_m20_title;
description = getString(R.string.alert_m20_description);
break;
case MAINTENANCE_21:
code = R.string.alert_m21_code;
title = R.string.alert_m21_title;
description = getString(R.string.alert_m21_description);
break;
case MAINTENANCE_22:
code = R.string.alert_m22_code;
title = R.string.alert_m22_title;
description = getString(R.string.alert_m22_description);
break;
case MAINTENANCE_23:
code = R.string.alert_m23_code;
title = R.string.alert_m23_title;
description = getString(R.string.alert_m23_description);
break;
case MAINTENANCE_24:
code = R.string.alert_m24_code;
title = R.string.alert_m24_title;
description = getString(R.string.alert_m24_description);
break;
case MAINTENANCE_25:
code = R.string.alert_m25_code;
title = R.string.alert_m25_title;
description = getString(R.string.alert_m25_description);
break;
case MAINTENANCE_26:
code = R.string.alert_m26_code;
title = R.string.alert_m26_title;
description = getString(R.string.alert_m26_description);
break;
case MAINTENANCE_27:
code = R.string.alert_m27_code;
title = R.string.alert_m27_title;
description = getString(R.string.alert_m27_description);
break;
case MAINTENANCE_28:
code = R.string.alert_m28_code;
title = R.string.alert_m28_title;
description = getString(R.string.alert_m28_description);
break;
case MAINTENANCE_29:
code = R.string.alert_m29_code;
title = R.string.alert_m29_title;
description = getString(R.string.alert_m29_description);
break;
case MAINTENANCE_30:
code = R.string.alert_m30_code;
title = R.string.alert_m30_title;
description = getString(R.string.alert_m30_description);
break;
case ERROR_6:
code = R.string.alert_e6_code;
title = R.string.alert_e6_title;
description = getString(R.string.alert_e6_description);
break;
case ERROR_10:
code = R.string.alert_e10_code;
title = R.string.alert_e10_title;
description = getString(R.string.alert_e10_description);
break;
case ERROR_13:
code = R.string.alert_e13_code;
title = R.string.alert_e13_title;
description = getString(R.string.alert_e13_description);
break;
}
this.icon.setImageDrawable(ContextCompat.getDrawable(this, icon));
this.errorCode.setText(code);
this.errorTitle.setText(title);
if (description == null) this.errorDescription.setVisibility(View.GONE);
else {
this.errorDescription.setVisibility(View.VISIBLE);
this.errorDescription.setText(Html.fromHtml(description));
}
}
public void muteClicked(View view) {
mute.setEnabled(false);
alertService.mute();
}
public void confirmClicked(View view) {
mute.setEnabled(false);
confirm.setEnabled(false);
alertService.confirm();
}
}

View file

@ -0,0 +1,255 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.activities;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.PumpInsightLocal.connection_service.InsightConnectionService;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.InsightState;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ExceptionTranslator;
public class InsightPairingActivity extends AppCompatActivity implements InsightConnectionService.StateCallback, View.OnClickListener, InsightConnectionService.ExceptionCallback {
private boolean scanning;
private LinearLayout deviceSearchSection;
private TextView pleaseWaitSection;
private LinearLayout codeCompareSection;
private LinearLayout pairingCompletedSection;
private Button yes;
private Button no;
private TextView code;
private Button exit;
private RecyclerView deviceList;
private DeviceAdapter deviceAdapter = new DeviceAdapter();
private InsightConnectionService service;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
service = ((InsightConnectionService.LocalBinder) binder).getService();
if (service.isPaired()) return;
else {
service.requestConnection(InsightPairingActivity.this);
service.registerStateCallback(InsightPairingActivity.this);
service.registerExceptionCallback(InsightPairingActivity.this);
stateChanged(service.getState());
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_insight_pairing);
deviceSearchSection = findViewById(R.id.device_search_section);
pleaseWaitSection = findViewById(R.id.please_wait_section);
codeCompareSection = findViewById(R.id.code_compare_section);
pairingCompletedSection = findViewById(R.id.pairing_completed_section);
yes = findViewById(R.id.yes);
no = findViewById(R.id.no);
code = findViewById(R.id.code);
exit = findViewById(R.id.exit);
deviceList = findViewById(R.id.device_list);
yes.setOnClickListener(this);
no.setOnClickListener(this);
exit.setOnClickListener(this);
deviceList.setLayoutManager(new LinearLayoutManager(this));
deviceList.setAdapter(deviceAdapter);
bindService(new Intent(this, InsightConnectionService.class), serviceConnection, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
if (service != null) {
service.withdrawConnectionRequest(InsightPairingActivity.this);
service.unregisterStateCallback(InsightPairingActivity.this);
service.unregisterExceptionCallback(InsightPairingActivity.this);
}
unbindService(serviceConnection);
super.onDestroy();
}
@Override
protected void onStart() {
super.onStart();
if (service != null && service.getState() == InsightState.NOT_PAIRED) startBLScan();
}
@Override
protected void onStop() {
stopBLScan();
super.onStop();
}
@Override
public void stateChanged(InsightState state) {
runOnUiThread(() -> {
switch (state) {
case NOT_PAIRED:
startBLScan();
deviceSearchSection.setVisibility(View.VISIBLE);
pleaseWaitSection.setVisibility(View.GONE);
codeCompareSection.setVisibility(View.GONE);
pairingCompletedSection.setVisibility(View.GONE);
break;
case CONNECTING:
case SATL_CONNECTION_REQUEST:
case SATL_KEY_REQUEST:
case SATL_VERIFY_DISPLAY_REQUEST:
case SATL_VERIFY_CONFIRM_REQUEST:
case APP_BIND_MESSAGE:
stopBLScan();
deviceSearchSection.setVisibility(View.GONE);
pleaseWaitSection.setVisibility(View.VISIBLE);
codeCompareSection.setVisibility(View.GONE);
pairingCompletedSection.setVisibility(View.GONE);
break;
case AWAITING_CODE_CONFIRMATION:
stopBLScan();
deviceSearchSection.setVisibility(View.GONE);
pleaseWaitSection.setVisibility(View.GONE);
codeCompareSection.setVisibility(View.VISIBLE);
pairingCompletedSection.setVisibility(View.GONE);
code.setText(service.getVerificationString());
break;
case DISCONNECTED:
case CONNECTED:
stopBLScan();
deviceSearchSection.setVisibility(View.GONE);
pleaseWaitSection.setVisibility(View.GONE);
codeCompareSection.setVisibility(View.GONE);
pairingCompletedSection.setVisibility(View.VISIBLE);
break;
}
});
}
private void startBLScan() {
if (!scanning) {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!bluetoothAdapter.isEnabled()) bluetoothAdapter.enable();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
registerReceiver(broadcastReceiver, intentFilter);
bluetoothAdapter.startDiscovery();
scanning = true;
}
}
private void stopBLScan() {
if (scanning) {
unregisterReceiver(broadcastReceiver);
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
scanning = false;
}
}
@Override
public void onClick(View v) {
if (v == exit) finish();
else if (v == yes) service.confirmVerificationString();
else if (v == no) service.rejectVerificationString();
}
@Override
public void onExceptionOccur(Exception e) {
ExceptionTranslator.makeToast(this, e);
}
private void deviceSelected(BluetoothDevice device) {
service.pair(device.getAddress());
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED))
BluetoothAdapter.getDefaultAdapter().startDiscovery();
else if (action.equals(BluetoothDevice.ACTION_FOUND)) {
BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
deviceAdapter.addDevice(bluetoothDevice);
}
}
};
private class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.ViewHolder> {
private List<BluetoothDevice> bluetoothDevices = new ArrayList<>();
public void addDevice(BluetoothDevice bluetoothDevice) {
if (!bluetoothDevices.contains(bluetoothDevice)) {
bluetoothDevices.add(bluetoothDevice);
notifyDataSetChanged();
}
}
public void clear() {
bluetoothDevices.clear();
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.bluetooth_device, parent, false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
BluetoothDevice bluetoothDevice = bluetoothDevices.get(position);
holder.deviceName.setText(bluetoothDevice.getName() == null ? bluetoothDevice.getAddress() : bluetoothDevice.getName());
holder.deviceName.setOnClickListener((v) -> deviceSelected(bluetoothDevice));
}
@Override
public int getItemCount() {
return bluetoothDevices.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView deviceName;
public ViewHolder(View itemView) {
super(itemView);
deviceName = (TextView) itemView;
}
}
}
}

View file

@ -0,0 +1,88 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.activities;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.PumpInsightLocal.connection_service.InsightConnectionService;
public class InsightPairingInformationActivity extends AppCompatActivity {
private InsightConnectionService connectionService;
private TextView serialNumber;
private TextView releaseSWVersion;
private TextView uiProcSWVersion;
private TextView pcProcSWVersion;
private TextView mdTelSWVersion;
private TextView safetyProcSWVersion;
private TextView btInfoPageVersion;
private TextView bluetoothAddress;
private TextView systemIdAppendix;
private TextView manufacturingDate;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
connectionService = ((InsightConnectionService.LocalBinder) binder).getService();
if (!connectionService.isPaired()) {
overridePendingTransition(0, 0);
finish();
startActivity(new Intent(InsightPairingInformationActivity.this, InsightPairingActivity.class));
} else {
serialNumber.setText(connectionService.getPumpSystemIdentification().getSerialNumber());
manufacturingDate.setText(connectionService.getPumpSystemIdentification().getManufacturingDate());
systemIdAppendix.setText(connectionService.getPumpSystemIdentification().getSystemIdAppendix() + "");
releaseSWVersion.setText(connectionService.getPumpFirmwareVersions().getReleaseSWVersion());
uiProcSWVersion.setText(connectionService.getPumpFirmwareVersions().getUiProcSWVersion());
pcProcSWVersion.setText(connectionService.getPumpFirmwareVersions().getPcProcSWVersion());
mdTelSWVersion.setText(connectionService.getPumpFirmwareVersions().getMdTelProcSWVersion());
safetyProcSWVersion.setText(connectionService.getPumpFirmwareVersions().getSafetyProcSWVersion());
btInfoPageVersion.setText(connectionService.getPumpFirmwareVersions().getBtInfoPageVersion());
bluetoothAddress.setText(connectionService.getBluetoothAddress());
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
connectionService = null;
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_insight_pairing_information);
serialNumber = findViewById(R.id.serial_number);
releaseSWVersion = findViewById(R.id.release_sw_version);
uiProcSWVersion = findViewById(R.id.ui_proc_sw_version);
pcProcSWVersion = findViewById(R.id.pc_proc_sw_version);
mdTelSWVersion = findViewById(R.id.md_tel_sw_version);
safetyProcSWVersion = findViewById(R.id.safety_proc_sw_version);
btInfoPageVersion = findViewById(R.id.bt_info_page_version);
bluetoothAddress = findViewById(R.id.bluetooth_address);
systemIdAppendix = findViewById(R.id.system_id_appendix);
manufacturingDate = findViewById(R.id.manufacturing_date);
bindService(new Intent(this, InsightConnectionService.class), serviceConnection, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(serviceConnection);
super.onDestroy();
}
public void deletePairing(View view) {
if (connectionService != null) {
connectionService.reset();
finish();
}
}
}

View file

@ -0,0 +1,91 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.exceptions.IncompatibleAppVersionException;
import info.nightscout.androidaps.plugins.PumpInsightLocal.exceptions.InvalidAppCRCException;
import info.nightscout.androidaps.plugins.PumpInsightLocal.exceptions.UnknownAppCommandException;
import info.nightscout.androidaps.plugins.PumpInsightLocal.exceptions.UnknownServiceException;
import info.nightscout.androidaps.plugins.PumpInsightLocal.exceptions.app_layer_errors.AppLayerErrorException;
import info.nightscout.androidaps.plugins.PumpInsightLocal.exceptions.app_layer_errors.UnknownAppLayerErrorCodeException;
import info.nightscout.androidaps.plugins.PumpInsightLocal.ids.AppCommandIDs;
import info.nightscout.androidaps.plugins.PumpInsightLocal.ids.AppErrorIDs;
import info.nightscout.androidaps.plugins.PumpInsightLocal.ids.ServiceIDs;
import info.nightscout.androidaps.plugins.PumpInsightLocal.satl.DataMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.crypto.Cryptograph;
public class AppLayerMessage implements Comparable<AppLayerMessage> {
private static final byte VERSION = 0x20;
private final MessagePriority messagePriority;
private final boolean inCRC;
private final boolean outCRC;
private final Service service;
public AppLayerMessage(MessagePriority messagePriority, boolean inCRC, boolean outCRC, Service service) {
this.messagePriority = messagePriority;
this.inCRC = inCRC;
this.outCRC = outCRC;
this.service = service;
}
protected ByteBuf getData() {
return new ByteBuf(0);
}
protected void parse(ByteBuf byteBuf) throws Exception {
}
public ByteBuf serialize(Class<? extends AppLayerMessage> clazz) {
byte[] data = getData().getBytes();
ByteBuf byteBuf = new ByteBuf(4 + data.length + (outCRC ? 2 : 0));
byteBuf.putByte(VERSION);
byteBuf.putByte(ServiceIDs.IDS.getID(getService()));
byteBuf.putUInt16LE(AppCommandIDs.IDS.getID(clazz));
byteBuf.putBytes(data);
if (outCRC) byteBuf.putUInt16LE(Cryptograph.calculateCRC(data));
return byteBuf;
}
public static AppLayerMessage deserialize(ByteBuf byteBuf) throws Exception {
byte version = byteBuf.readByte();
byte service = byteBuf.readByte();
int command = byteBuf.readUInt16LE();
int error = byteBuf.readUInt16LE();
Class<? extends AppLayerMessage> clazz = AppCommandIDs.IDS.getType(command);
if (clazz == null) throw new UnknownAppCommandException();
if (version != VERSION) throw new IncompatibleAppVersionException();
AppLayerMessage message = clazz.newInstance();
if (ServiceIDs.IDS.getType(service) == null) throw new UnknownServiceException();
if (error != 0) {
Class<? extends AppLayerErrorException> exceptionClass = AppErrorIDs.IDS.getType(error);
if (exceptionClass == null) throw new UnknownAppLayerErrorCodeException(error);
else throw exceptionClass.getConstructor(int.class).newInstance(error);
}
byte[] data = byteBuf.readBytes(byteBuf.getSize() - (message.inCRC ? 2 : 0));
if (message.inCRC && Cryptograph.calculateCRC(data) != byteBuf.readUInt16LE()) throw new InvalidAppCRCException();
message.parse(ByteBuf.from(data));
return message;
}
public static DataMessage wrap(AppLayerMessage message) {
DataMessage dataMessage = new DataMessage();
dataMessage.setData(message.serialize(message.getClass()));
return dataMessage;
}
public static AppLayerMessage unwrap(DataMessage dataMessage) throws Exception {
return deserialize(dataMessage.getData());
}
@Override
public int compareTo(AppLayerMessage o) {
return messagePriority.compareTo(o.messagePriority);
}
public Service getService() {
return this.service;
}
}

View file

@ -0,0 +1,48 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.parameter_blocks.ParameterBlock;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.ids.ParameterBlockIDs;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class ReadParameterBlockMessage extends AppLayerMessage {
private Class<? extends ParameterBlock> parameterBlockId;
private ParameterBlock parameterBlock;
private Service service;
public ReadParameterBlockMessage() {
super(MessagePriority.NORMAL, true, false, null);
}
@Override
public Service getService() {
return service;
}
public void setService(Service service) {
this.service = service;
}
@Override
protected ByteBuf getData() {
ByteBuf byteBuf = new ByteBuf(2);
byteBuf.putUInt16LE(ParameterBlockIDs.IDS.getID(parameterBlockId));
return byteBuf;
}
@Override
protected void parse(ByteBuf byteBuf) throws Exception {
parameterBlock = ParameterBlockIDs.IDS.getType(byteBuf.readUInt16LE()).newInstance();
byteBuf.shift(2); //Restriction level
parameterBlock.parse(byteBuf);
}
public ParameterBlock getParameterBlock() {
return this.parameterBlock;
}
public void setParameterBlockId(Class<? extends ParameterBlock> configurationBlockId) {
this.parameterBlockId = configurationBlockId;
}
}

View file

@ -0,0 +1,31 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer;
public enum Service {
CONNECTION((short) 0x0000, null),
STATUS((short) 0x0100, null),
HISTORY((short) 0x0200, null),
CONFIGURATION((short) 0x0200, "u+5Fhz6Gw4j1Kkas"),
PARAMETER((short) 0x0200, null),
REMOTE_CONTROL((short) 0x0100, "MAbcV2X6PVjxuz+R");
private short version;
private String servicePassword;
Service(short version, String servicePassword) {
this.version = version;
this.servicePassword = servicePassword;
}
public short getVersion() {
return this.version;
}
public String getServicePassword() {
return this.servicePassword;
}
public void setServicePassword(String servicePassword) {
this.servicePassword = servicePassword;
}
}

View file

@ -0,0 +1,12 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.configuration;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.AppLayerMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service;
public class CloseConfigurationWriteSessionMessage extends AppLayerMessage {
public CloseConfigurationWriteSessionMessage() {
super(MessagePriority.NORMAL, false, false, Service.CONFIGURATION);
}
}

View file

@ -0,0 +1,12 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.configuration;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.AppLayerMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service;
public class OpenConfigurationWriteSessionMessage extends AppLayerMessage {
public OpenConfigurationWriteSessionMessage() {
super(MessagePriority.NORMAL, false, false, Service.CONFIGURATION);
}
}

View file

@ -0,0 +1,41 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.configuration;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.AppLayerMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.parameter_blocks.ParameterBlock;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.ids.ParameterBlockIDs;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class WriteConfigurationBlockMessage extends AppLayerMessage {
private ParameterBlock parameterBlock;
private Class<? extends ParameterBlock> configurationBlockId;
public WriteConfigurationBlockMessage() {
super(MessagePriority.NORMAL, false, true, Service.CONFIGURATION);
}
@Override
protected ByteBuf getData() {
ByteBuf configBlockData = parameterBlock.getData();
ByteBuf data = new ByteBuf(4 + configBlockData.getSize());
data.putUInt16LE(ParameterBlockIDs.IDS.getID(parameterBlock.getClass()));
data.putUInt16LE(31);
data.putByteBuf(configBlockData);
return data;
}
@Override
protected void parse(ByteBuf byteBuf) throws Exception {
configurationBlockId = ParameterBlockIDs.IDS.getType(byteBuf.readUInt16LE());
}
public Class<? extends ParameterBlock> getConfigurationBlockId() {
return this.configurationBlockId;
}
public void setParameterBlock(ParameterBlock parameterBlock) {
this.parameterBlock = parameterBlock;
}
}

View file

@ -0,0 +1,51 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.connection;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.AppLayerMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class ActivateServiceMessage extends AppLayerMessage {
private byte serviceID;
private short version;
private byte[] servicePassword;
public ActivateServiceMessage() {
super(MessagePriority.NORMAL, false, false, Service.CONNECTION);
}
protected void parse(ByteBuf byteBuf) {
serviceID = byteBuf.readByte();
version = byteBuf.readShort();
}
@Override
protected ByteBuf getData() {
ByteBuf byteBuf = new ByteBuf(19);
byteBuf.putByte(serviceID);
byteBuf.putShort(version);
byteBuf.putBytes(servicePassword);
return byteBuf;
}
public byte getServiceID() {
return this.serviceID;
}
public short getVersion() {
return this.version;
}
public void setServiceID(byte serviceID) {
this.serviceID = serviceID;
}
public void setVersion(short version) {
this.version = version;
}
public void setServicePassword(byte[] servicePassword) {
this.servicePassword = servicePassword;
}
}

View file

@ -0,0 +1,20 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.connection;
import org.spongycastle.util.encoders.Hex;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.AppLayerMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class BindMessage extends AppLayerMessage {
public BindMessage() {
super(MessagePriority.NORMAL, false, false, Service.CONNECTION);
}
@Override
protected ByteBuf getData() {
return ByteBuf.from(Hex.decode("3438310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"));
}
}

View file

@ -0,0 +1,20 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.connection;
import org.spongycastle.util.encoders.Hex;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.AppLayerMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class ConnectMessage extends AppLayerMessage {
public ConnectMessage() {
super(MessagePriority.NORMAL, false, false, Service.CONNECTION);
}
@Override
protected ByteBuf getData() {
return ByteBuf.from(Hex.decode("0000080100196000"));
}
}

View file

@ -0,0 +1,20 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.connection;
import org.spongycastle.util.encoders.Hex;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.AppLayerMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class DisconnectMessage extends AppLayerMessage {
public DisconnectMessage() {
super(MessagePriority.NORMAL, false, false, Service.CONNECTION);
}
@Override
protected ByteBuf getData() {
return ByteBuf.from(Hex.decode("0360"));
}
}

View file

@ -0,0 +1,42 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.connection;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.AppLayerMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class ServiceChallengeMessage extends AppLayerMessage {
private byte serviceID;
private byte[] randomData;
private short version;
public ServiceChallengeMessage() {
super(MessagePriority.NORMAL, false, false, Service.CONNECTION);
}
@Override
protected void parse(ByteBuf byteBuf) {
randomData = byteBuf.getBytes(16);
}
@Override
protected ByteBuf getData() {
ByteBuf byteBuf = new ByteBuf(3);
byteBuf.putByte(serviceID);
byteBuf.putShort(version);
return byteBuf;
}
public byte[] getRandomData() {
return this.randomData;
}
public void setServiceID(byte serviceID) {
this.serviceID = serviceID;
}
public void setVersion(short version) {
this.version = version;
}
}

View file

@ -0,0 +1,8 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history;
public enum HistoryReadingDirection {
FORWARD,
BACKWARD;
}

View file

@ -0,0 +1,34 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.AppLayerMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events.HistoryEvent;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class ReadHistoryEventsMessage extends AppLayerMessage {
private List<HistoryEvent> historyEvents;
public ReadHistoryEventsMessage() {
super(MessagePriority.NORMAL, true, false, Service.HISTORY);
}
@Override
protected void parse(ByteBuf byteBuf) throws Exception {
historyEvents = new ArrayList<>();
byteBuf.shift(2);
int frameCount = byteBuf.readUInt16LE();
for (int i = 0; i < frameCount; i++) {
int length = byteBuf.readUInt16LE();
historyEvents.add(HistoryEvent.deserialize(ByteBuf.from(byteBuf.readBytes(length))));
}
}
public List<HistoryEvent> getHistoryEvents() {
return historyEvents;
}
}

View file

@ -0,0 +1,34 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.AppLayerMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.ids.HistoryReadingDirectionIDs;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class StartReadingHistoryMessage extends AppLayerMessage {
private long offset;
private HistoryReadingDirection direction;
public StartReadingHistoryMessage() {
super(MessagePriority.NORMAL, false, true, Service.HISTORY);
}
@Override
protected ByteBuf getData() {
ByteBuf byteBuf = new ByteBuf(8);
byteBuf.putUInt16LE(31);
byteBuf.putUInt16LE(HistoryReadingDirectionIDs.IDS.getID(direction));
byteBuf.putUInt32LE(offset);
return byteBuf;
}
public void setOffset(long offset) {
this.offset = offset;
}
public void setDirection(HistoryReadingDirection direction) {
this.direction = direction;
}
}

View file

@ -0,0 +1,13 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.AppLayerMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.MessagePriority;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class StopReadingHistoryMessage extends AppLayerMessage {
public StopReadingHistoryMessage() {
super(MessagePriority.NORMAL, false, false, Service.HISTORY);
}
}

View file

@ -0,0 +1,23 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class BasalDeliveryChangedEvent extends HistoryEvent {
private double oldBasalRate;
private double newBasalRate;
@Override
public void parse(ByteBuf byteBuf) {
oldBasalRate = byteBuf.readUInt32Decimal1000();
newBasalRate = byteBuf.readUInt32Decimal1000();
}
public double getOldBasalRate() {
return oldBasalRate;
}
public double getNewBasalRate() {
return newBasalRate;
}
}

View file

@ -0,0 +1,64 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.BolusType;
import info.nightscout.androidaps.plugins.PumpInsightLocal.ids.BolusTypeIDs;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.BOCUtil;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class BolusDeliveredEvent extends HistoryEvent {
private BolusType bolusType;
private int startHour;
private int startMinute;
private int startSecond;
private double immediateAmount;
private double extendedAmount;
private int duration;
private int bolusID;
@Override
public void parse(ByteBuf byteBuf) {
bolusType = BolusTypeIDs.IDS.getType(byteBuf.readUInt16LE());
byteBuf.shift(1);
startHour = BOCUtil.parseBOC(byteBuf.readByte());
startMinute = BOCUtil.parseBOC(byteBuf.readByte());
startSecond = BOCUtil.parseBOC(byteBuf.readByte());
immediateAmount = byteBuf.readUInt16Decimal();
extendedAmount = byteBuf.readUInt16Decimal();
duration = byteBuf.readUInt16LE();
byteBuf.shift(2);
bolusID = byteBuf.readUInt16LE();
}
public BolusType getBolusType() {
return bolusType;
}
public int getStartHour() {
return startHour;
}
public int getStartMinute() {
return startMinute;
}
public int getStartSecond() {
return startSecond;
}
public double getImmediateAmount() {
return immediateAmount;
}
public double getExtendedAmount() {
return extendedAmount;
}
public int getDuration() {
return duration;
}
public int getBolusID() {
return bolusID;
}
}

View file

@ -0,0 +1,45 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.BolusType;
import info.nightscout.androidaps.plugins.PumpInsightLocal.ids.BolusTypeIDs;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class BolusProgrammedEvent extends HistoryEvent {
private BolusType bolusType;
private double immediateAmount;
private double extendedAmount;
private int duration;
private int bolusID;
@Override
public void parse(ByteBuf byteBuf) {
bolusType = BolusTypeIDs.IDS.getType(byteBuf.readUInt16LE());
immediateAmount = byteBuf.readUInt16Decimal();
extendedAmount = byteBuf.readUInt16Decimal();
duration = byteBuf.readUInt16LE();
byteBuf.shift(4);
bolusID = byteBuf.readUInt16LE();
}
public BolusType getBolusType() {
return bolusType;
}
public double getImmediateAmount() {
return immediateAmount;
}
public double getExtendedAmount() {
return extendedAmount;
}
public int getDuration() {
return duration;
}
public int getBolusID() {
return bolusID;
}
}

View file

@ -0,0 +1,17 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class CannulaFilledEvent extends HistoryEvent {
private double amount;
@Override
public void parse(ByteBuf byteBuf) {
amount = byteBuf.readUInt16Decimal();
}
public double getAmount() {
return amount;
}
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
public class CartridgeInsertedEvent extends HistoryEvent {
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
public class CartridgeRemovedEvent extends HistoryEvent {
}

View file

@ -0,0 +1,49 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.BOCUtil;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class DateTimeChangedEvent extends HistoryEvent {
private int beforeYear;
private int beforeMonth;
private int beforeDay;
private int beforeHour;
private int beforeMinute;
private int beforeSecond;
@Override
public void parse(ByteBuf byteBuf) {
beforeYear = BOCUtil.parseBOC(byteBuf.readByte()) * 100 + BOCUtil.parseBOC(byteBuf.readByte());
beforeMonth = BOCUtil.parseBOC(byteBuf.readByte());
beforeDay = BOCUtil.parseBOC(byteBuf.readByte());
byteBuf.shift(1);
beforeHour = BOCUtil.parseBOC(byteBuf.readByte());
beforeMinute = BOCUtil.parseBOC(byteBuf.readByte());
beforeSecond = BOCUtil.parseBOC(byteBuf.readByte());
}
public int getBeforeYear() {
return beforeYear;
}
public int getBeforeMonth() {
return beforeMonth;
}
public int getBeforeDay() {
return beforeDay;
}
public int getBeforeHour() {
return beforeHour;
}
public int getBeforeMinute() {
return beforeMinute;
}
public int getBeforeSecond() {
return beforeSecond;
}
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
public class DefaultDateTimeSetEvent extends HistoryEvent {
}

View file

@ -0,0 +1,43 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.BOCUtil;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class EndOfTBREvent extends HistoryEvent {
private int startHour;
private int startMinute;
private int startSecond;
private int amount;
private int duration;
@Override
public void parse(ByteBuf byteBuf) {
byteBuf.shift(1);
startHour = BOCUtil.parseBOC(byteBuf.readByte());
startMinute = BOCUtil.parseBOC(byteBuf.readByte());
startSecond = BOCUtil.parseBOC(byteBuf.readByte());
amount = byteBuf.readUInt16LE();
duration = byteBuf.readUInt16LE();
}
public int getStartHour() {
return startHour;
}
public int getStartMinute() {
return startMinute;
}
public int getStartSecond() {
return startSecond;
}
public int getAmount() {
return amount;
}
public int getDuration() {
return duration;
}
}

View file

@ -0,0 +1,83 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.ids.HistoryEventIDs;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.BOCUtil;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class HistoryEvent implements Comparable<HistoryEvent> {
private int eventYear;
private int eventMonth;
private int eventDay;
private int eventHour;
private int eventMinute;
private int eventSecond;
private long eventPosition;
public static HistoryEvent deserialize(ByteBuf byteBuf) {
int eventID = byteBuf.readUInt16LE();
Class<? extends HistoryEvent> eventClass = HistoryEventIDs.IDS.getType(eventID);
HistoryEvent event = null;
if (eventClass == null) event = new HistoryEvent();
else {
try {
event = eventClass.newInstance();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
event.parseHeader(byteBuf);
event.parse(byteBuf);
return event;
}
public final void parseHeader(ByteBuf byteBuf) {
eventYear = BOCUtil.parseBOC(byteBuf.readByte()) * 100 + BOCUtil.parseBOC(byteBuf.readByte());
eventMonth = BOCUtil.parseBOC(byteBuf.readByte());
eventDay = BOCUtil.parseBOC(byteBuf.readByte());
byteBuf.shift(1);
eventHour = BOCUtil.parseBOC(byteBuf.readByte());
eventMinute = BOCUtil.parseBOC(byteBuf.readByte());
eventSecond = BOCUtil.parseBOC(byteBuf.readByte());
eventPosition = byteBuf.readUInt32LE();
}
public void parse(ByteBuf byteBuf) {
}
public int getEventYear() {
return eventYear;
}
public int getEventMonth() {
return eventMonth;
}
public int getEventDay() {
return eventDay;
}
public int getEventHour() {
return eventHour;
}
public int getEventMinute() {
return eventMinute;
}
public int getEventSecond() {
return eventSecond;
}
public long getEventPosition() {
return eventPosition;
}
@Override
public int compareTo(HistoryEvent historyEvent) {
return (int) (eventPosition - historyEvent.eventPosition);
}
}

View file

@ -0,0 +1,25 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.AlertType;
import info.nightscout.androidaps.plugins.PumpInsightLocal.ids.AlertTypeIncrementalIDs;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public abstract class OccurrenceOfAlertEvent extends HistoryEvent {
private AlertType alertType;
private int alertID;
@Override
public void parse(ByteBuf byteBuf) {
alertType = AlertTypeIncrementalIDs.IDS.getType(byteBuf.readUInt16LE());
alertID = byteBuf.readUInt16LE();
}
public AlertType getAlertType() {
return alertType;
}
public int getAlertID() {
return alertID;
}
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
public class OccurrenceOfErrorEvent extends OccurrenceOfAlertEvent {
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
public class OccurrenceOfMaintenanceEvent extends OccurrenceOfAlertEvent {
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
public class OccurrenceOfWarningEvent extends OccurrenceOfAlertEvent {
}

View file

@ -0,0 +1,26 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.OperatingMode;
import info.nightscout.androidaps.plugins.PumpInsightLocal.ids.OperatingModeIDs;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class OperatingModeChangedEvent extends HistoryEvent {
private OperatingMode oldValue;
private OperatingMode newValue;
@Override
public void parse(ByteBuf byteBuf) {
oldValue = OperatingModeIDs.IDS.getType(byteBuf.readUInt16LE());
newValue = OperatingModeIDs.IDS.getType(byteBuf.readUInt16LE());
}
public OperatingMode getOldValue() {
return oldValue;
}
public OperatingMode getNewValue() {
return newValue;
}
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
public class PowerDownEvent extends HistoryEvent {
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
public class PowerUpEvent extends HistoryEvent {
}

View file

@ -0,0 +1,18 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class SniffingDoneEvent extends HistoryEvent {
private double amount;
@Override
public void parse(ByteBuf byteBuf) {
amount = byteBuf.readUInt16Decimal();
}
public double getAmount() {
return amount;
}
}

View file

@ -0,0 +1,23 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class StartOfTBREvent extends HistoryEvent {
private int amount;
private int duration;
@Override
public void parse(ByteBuf byteBuf) {
amount = byteBuf.readUInt16LE();
duration = byteBuf.readUInt16LE();
}
public int getAmount() {
return amount;
}
public int getDuration() {
return duration;
}
}

View file

@ -0,0 +1,42 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.BOCUtil;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class TotalDailyDoseEvent extends HistoryEvent {
private double basalTotal;
private double bolusTotal;
private int totalYear;
private int totalMonth;
private int totalDay;
@Override
public void parse(ByteBuf byteBuf) {
basalTotal = byteBuf.readUInt32Decimal100();
bolusTotal = byteBuf.readUInt32Decimal100();
totalYear = BOCUtil.parseBOC(byteBuf.readByte()) * 100 + BOCUtil.parseBOC(byteBuf.readByte());
totalMonth = BOCUtil.parseBOC(byteBuf.readByte());
totalDay = BOCUtil.parseBOC(byteBuf.readByte());
}
public double getBasalTotal() {
return basalTotal;
}
public double getBolusTotal() {
return bolusTotal;
}
public int getTotalYear() {
return totalYear;
}
public int getTotalMonth() {
return totalMonth;
}
public int getTotalDay() {
return totalDay;
}
}

View file

@ -0,0 +1,17 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.history.history_events;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class TubeFilledEvent extends HistoryEvent {
private double amount;
@Override
public void parse(ByteBuf byteBuf) {
amount = byteBuf.readUInt16Decimal();
}
public double getAmount() {
return amount;
}
}

View file

@ -0,0 +1,30 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.parameter_blocks;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.BasalProfile;
import info.nightscout.androidaps.plugins.PumpInsightLocal.ids.ActiveBasalProfileIDs;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ByteBuf;
public class ActiveBRProfileBlock extends ParameterBlock {
private BasalProfile activeBasalProfile;
@Override
public void parse(ByteBuf byteBuf) {
activeBasalProfile = ActiveBasalProfileIDs.IDS.getType(byteBuf.readUInt16LE());
}
@Override
public ByteBuf getData() {
ByteBuf byteBuf = new ByteBuf(2);
byteBuf.putUInt16LE(ActiveBasalProfileIDs.IDS.getID(activeBasalProfile));
return byteBuf;
}
public BasalProfile getActiveBasalProfile() {
return activeBasalProfile;
}
public void setActiveBasalProfile(BasalProfile activeBasalProfile) {
this.activeBasalProfile = activeBasalProfile;
}
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.parameter_blocks;
public class BRProfile1Block extends BRProfileBlock {
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.parameter_blocks;
public class BRProfile1NameBlock extends NameBlock {
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.parameter_blocks;
public class BRProfile2Block extends BRProfileBlock {
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.parameter_blocks;
public class BRProfile2NameBlock extends NameBlock {
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.parameter_blocks;
public class BRProfile3Block extends BRProfileBlock {
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.parameter_blocks;
public class BRProfile3NameBlock extends NameBlock {
}

View file

@ -0,0 +1,4 @@
package info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.parameter_blocks;
public class BRProfile4Block extends BRProfileBlock {
}

Some files were not shown because too many files have changed in this diff Show more