Medtronic 0.8.1-SNAPSHOT

- wear changes
- refactoring of decoder
- started work on bolus, tbr, resumes
This commit is contained in:
Andy Rozman 2019-03-10 19:08:54 +00:00
parent 5a8b5f3e7b
commit 6fcb1ce230
29 changed files with 1665 additions and 654 deletions

View file

@ -64,7 +64,7 @@ android {
multiDexEnabled true
versionCode 1500
// dev_version: 2.1
version "medtronic-0.8.0"
version "medtronic-0.8.1-SNAPSHOT"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
@ -72,6 +72,7 @@ android {
buildConfigField "String", "DEV_DATE", '"2.3.2019"'
buildConfigField "String", "DEV_CHECKIN", '"f28d763ada9e6a8d7621b972e03edd980767e076"'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// if you change minSdkVersion to less than 11, you need to change executeTask for wear
ndk {
moduleName "BleCommandUtil"
@ -81,7 +82,7 @@ android {
// TODO remove once wear dependency com.google.android.gms:play-services-wearable:7.3.0
// has been upgraded (requiring significant code changes), which currently fails release
// build with a deprecation warning
abortOnError false
// abortOnError false
// (disabled entirely to avoid reports on the error, which would still be displayed
// and it's easy to overlook that it's ignored)
checkReleaseBuilds false
@ -103,9 +104,9 @@ android {
applicationId "info.nightscout.androidaps"
dimension "standard"
resValue "string", "app_name", "AndroidAPS"
versionName version + "-pumpcontrol"
versionName version
manifestPlaceholders = [
appIcon: "@mipmap/ic_launcher",
appIcon : "@mipmap/ic_launcher",
appIconRound: "@mipmap/ic_launcher_round"
]
}
@ -125,7 +126,7 @@ android {
resValue "string", "app_name", "NSClient"
versionName version + "-nsclient"
manifestPlaceholders = [
appIcon: "@mipmap/ic_yellowowl",
appIcon : "@mipmap/yellowowl",
appIconRound: "@null"
]
}
@ -135,7 +136,7 @@ android {
resValue "string", "app_name", "NSClient2"
versionName version + "-nsclient"
manifestPlaceholders = [
appIcon: "@mipmap/ic_yellowowl",
appIcon : "@mipmap/yellowowl",
appIconRound: "@null"
]
}
@ -198,7 +199,7 @@ dependencies {
implementation "org.slf4j:slf4j-api:1.7.12"
implementation "com.jjoe64:graphview:4.0.1"
implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.1.1"
implementation "com.google.android.gms:play-services-wearable:7.5.0"
implementation 'com.google.android.gms:play-services-wearable:10.2.1'
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'
@ -232,6 +233,8 @@ dependencies {
testImplementation "com.google.truth:truth:0.39"
testImplementation 'org.robolectric:robolectric:3.8'
testImplementation "org.skyscreamer:jsonassert:1.5.0"
testImplementation "org.hamcrest:hamcrest-all:1.3"
testImplementation "uk.org.lidalia:slf4j-test:1.2.0"
androidTestImplementation "org.mockito:mockito-core:2.7.22"
androidTestImplementation "com.google.dexmaker:dexmaker:${dexmakerVersion}"

View file

@ -174,7 +174,63 @@
android:name=".plugins.general.wear.wearintegration.WatchUpdaterService"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
<!-- <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> -->
<!-- listeners receive events that match the action and data filters -->
<action android:name="com.google.android.gms.wearable.CAPABILITY_CHANGED" />
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_data" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_data_resend" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_cancel_bolus" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_confirmactionstring" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_initiateactionstring" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/openwearsettings" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/sendstatustowear" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/sendpreferencestowear" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_basal" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_bolusprogress" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_actionconfirmationrequest" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_changeconfirmationrequest" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_cancelnotificationrequest" />
</intent-filter>
</service>
<service

View file

@ -1,24 +1,5 @@
package info.nightscout.androidaps.db;
import android.content.Context;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.Nullable;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.CloseableIterator;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
@ -30,6 +11,26 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.content.Context;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.Nullable;
import android.util.Log;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.CloseableIterator;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.OverlappingIntervals;
@ -48,9 +49,9 @@ import info.nightscout.androidaps.events.EventTempTargetChange;
import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRNSHistorySync;
import info.nightscout.androidaps.plugins.pump.danaR.comm.RecordTypes;
import info.nightscout.androidaps.plugins.pump.insight.database.InsightBolusID;
@ -65,9 +66,9 @@ import info.nightscout.androidaps.utils.ToastUtils;
* This Helper contains all resource to provide a central DB management functionality. Only methods handling
* data-structure (and not the DB content) should be contained in here (meaning DDL and not SQL).
* <p>
* This class can safely be called from Services, but should not call Services to avoid circular dependencies.
* One major issue with this (right now) are the scheduled events, which are put into the service. Therefor all
* direct calls to the corresponding methods (eg. resetDatabases) should be done by a central service.
* This class can safely be called from Services, but should not call Services to avoid circular dependencies. One major
* issue with this (right now) are the scheduled events, which are put into the service. Therefor all direct calls to
* the corresponding methods (eg. resetDatabases) should be done by a central service.
*/
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
@ -106,7 +107,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final ScheduledExecutorService careportalEventWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledCareportalEventPost = null;
private static final ScheduledExecutorService profileSwitchEventWorker = Executors.newSingleThreadScheduledExecutor();
private static final ScheduledExecutorService profileSwitchEventWorker = Executors
.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledProfileSwitchEventPost = null;
private int oldVersion = 0;
@ -116,7 +118,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
onCreate(getWritableDatabase(), getConnectionSource());
//onUpgrade(getWritableDatabase(), getConnectionSource(), 1,1);
// onUpgrade(getWritableDatabase(), getConnectionSource(), 1,1);
}
@ -241,15 +243,13 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
scheduleTemporaryTargetChange();
scheduleCareportalEventChange();
scheduleProfileSwitchChange();
new java.util.Timer().schedule(
new java.util.TimerTask() {
@Override
public void run() {
MainApp.bus().post(new EventRefreshOverview("resetDatabases"));
}
},
3000
);
new java.util.Timer().schedule(new java.util.TimerTask() {
@Override
public void run() {
MainApp.bus().post(new EventRefreshOverview("resetDatabases"));
}
}, 3000);
}
@ -367,18 +367,22 @@ 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)
@ -434,6 +438,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void run() {
if (L.isEnabled(L.DATABASE))
log.debug("Firing EventNewBg");
Log.d("DatabaseHelper", "WR: Firing EventNewBg");
MainApp.bus().post(new EventNewBG(bgReading));
scheduledBgPost = null;
}
@ -703,7 +708,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
old.copyFrom(tempTarget);
getDaoTempTargets().create(old);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPTARGET: Updating record by date from: " + Source.getString(tempTarget.source) + " " + old.toString());
log.debug("TEMPTARGET: Updating record by date from: "
+ Source.getString(tempTarget.source) + " " + old.toString());
scheduleTemporaryTargetChange();
return true;
}
@ -723,7 +729,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
old.copyFrom(tempTarget);
getDaoTempTargets().create(old);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPTARGET: Updating record by _id from: " + Source.getString(tempTarget.source) + " " + old.toString());
log.debug("TEMPTARGET: Updating record by _id from: "
+ Source.getString(tempTarget.source) + " " + old.toString());
scheduleTemporaryTargetChange();
return true;
}
@ -731,14 +738,16 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
getDaoTempTargets().create(tempTarget);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPTARGET: New record from: " + Source.getString(tempTarget.source) + " " + tempTarget.toString());
log.debug("TEMPTARGET: New record from: " + Source.getString(tempTarget.source) + " "
+ tempTarget.toString());
scheduleTemporaryTargetChange();
return true;
}
if (tempTarget.source == Source.USER) {
getDaoTempTargets().create(tempTarget);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPTARGET: New record from: " + Source.getString(tempTarget.source) + " " + tempTarget.toString());
log.debug("TEMPTARGET: New record from: " + Source.getString(tempTarget.source) + " "
+ tempTarget.toString());
scheduleTemporaryTargetChange();
return true;
}
@ -798,14 +807,11 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void createTemptargetFromJsonIfNotExists(JSONObject trJson) {
try {
String units = JsonHelper.safeGetString(trJson, "units", Constants.MGDL);
TempTarget tempTarget = new TempTarget()
.date(trJson.getLong("mills"))
.duration(trJson.getInt("duration"))
.low(Profile.toMgdl(trJson.getDouble("targetBottom"), units))
.high(Profile.toMgdl(trJson.getDouble("targetTop"), units))
.reason(JsonHelper.safeGetString(trJson, "reason", ""))
._id(trJson.getString("_id"))
.source(Source.NIGHTSCOUT);
TempTarget tempTarget = new TempTarget().date(trJson.getLong("mills")).duration(trJson.getInt("duration"))
.low(Profile.toMgdl(trJson.getDouble("targetBottom"), units))
.high(Profile.toMgdl(trJson.getDouble("targetTop"), units))
.reason(JsonHelper.safeGetString(trJson, "reason", ""))._id(trJson.getString("_id"))
.source(Source.NIGHTSCOUT);
createOrUpdate(tempTarget);
} catch (JSONException e) {
log.error("Unhandled exception: " + trJson.toString(), e);
@ -849,7 +855,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
try {
getDaoDanaRHistory().createOrUpdate(record);
//If it is a TDD, store it for stats also.
// If it is a TDD, store it for stats also.
if (record.recordCode == RecordTypes.RECORD_TYPE_DAILY) {
createOrUpdateTDD(new TDD(record.recordDate, record.recordDailyBolus, record.recordDailyBasal, 0));
}
@ -906,7 +912,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// ------------ TemporaryBasal handling ---------------
//return true if new record was created
// return true if new record was created
public boolean createOrUpdate(TemporaryBasal tempBasal) {
try {
TemporaryBasal old;
@ -922,12 +928,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (trList.size() > 0) {
// do nothing, pump history record cannot be changed
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: Already exists from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
log.debug("TEMPBASAL: Already exists from: " + Source.getString(tempBasal.source) + " "
+ tempBasal.toString());
return false;
}
getDaoTemporaryBasal().create(tempBasal);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " "
+ tempBasal.toString());
updateEarliestDataChange(tempBasal.date);
scheduleTemporaryBasalChange();
return true;
@ -945,7 +953,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
old.copyFrom(tempBasal);
getDaoTemporaryBasal().create(old);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: Updating record by date from: " + Source.getString(tempBasal.source) + " " + old.toString());
log.debug("TEMPBASAL: Updating record by date from: " + Source.getString(tempBasal.source)
+ " " + old.toString());
updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date);
scheduleTemporaryBasalChange();
@ -968,7 +977,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
old.copyFrom(tempBasal);
getDaoTemporaryBasal().create(old);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: Updating record by _id from: " + Source.getString(tempBasal.source) + " " + old.toString());
log.debug("TEMPBASAL: Updating record by _id from: "
+ Source.getString(tempBasal.source) + " " + old.toString());
updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date);
scheduleTemporaryBasalChange();
@ -978,7 +988,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
getDaoTemporaryBasal().create(tempBasal);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " "
+ tempBasal.toString());
updateEarliestDataChange(tempBasal.date);
scheduleTemporaryBasalChange();
return true;
@ -986,7 +997,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (tempBasal.source == Source.USER) {
getDaoTemporaryBasal().create(tempBasal);
if (L.isEnabled(L.DATABASE))
log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " " + tempBasal.toString());
log.debug("TEMPBASAL: New record from: " + Source.getString(tempBasal.source) + " "
+ tempBasal.toString());
updateEarliestDataChange(tempBasal.date);
scheduleTemporaryBasalChange();
return true;
@ -1052,31 +1064,28 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
/*
{
"_id": "59232e1ddd032d04218dab00",
"eventType": "Temp Basal",
"duration": 60,
"percent": -50,
"created_at": "2017-05-22T18:29:57Z",
"enteredBy": "AndroidAPS",
"notes": "Basal Temp Start 50% 60.0 min",
"NSCLIENT_ID": 1495477797863,
"mills": 1495477797000,
"mgdl": 194.5,
"endmills": 1495481397000
}
*/
* {
* "_id": "59232e1ddd032d04218dab00",
* "eventType": "Temp Basal",
* "duration": 60,
* "percent": -50,
* "created_at": "2017-05-22T18:29:57Z",
* "enteredBy": "AndroidAPS",
* "notes": "Basal Temp Start 50% 60.0 min",
* "NSCLIENT_ID": 1495477797863,
* "mills": 1495477797000,
* "mgdl": 194.5,
* "endmills": 1495481397000
* }
*/
public void createTempBasalFromJsonIfNotExists(JSONObject trJson) {
try {
if (trJson.has("originalExtendedAmount")) { // extended bolus uploaded as temp basal
ExtendedBolus extendedBolus = new ExtendedBolus()
.source(Source.NIGHTSCOUT)
.date(trJson.getLong("mills"))
.pumpId(trJson.has("pumpId") ? trJson.getLong("pumpId") : 0)
.durationInMinutes(trJson.getInt("duration"))
.insulin(trJson.getDouble("originalExtendedAmount"))
._id(trJson.getString("_id"));
ExtendedBolus extendedBolus = new ExtendedBolus().source(Source.NIGHTSCOUT)
.date(trJson.getLong("mills")).pumpId(trJson.has("pumpId") ? trJson.getLong("pumpId") : 0)
.durationInMinutes(trJson.getInt("duration")).insulin(trJson.getDouble("originalExtendedAmount"))
._id(trJson.getString("_id"));
// if faking found in NS, adapt AAPS to use it too
if (!VirtualPumpPlugin.getPlugin().getFakingStatus()) {
VirtualPumpPlugin.getPlugin().setFakingStatus(true);
@ -1100,10 +1109,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
createOrUpdate(extendedBolus);
} else {
TemporaryBasal tempBasal = new TemporaryBasal()
.date(trJson.getLong("mills"))
.source(Source.NIGHTSCOUT)
.pumpId(trJson.has("pumpId") ? trJson.getLong("pumpId") : 0);
TemporaryBasal tempBasal = new TemporaryBasal().date(trJson.getLong("mills")).source(Source.NIGHTSCOUT)
.pumpId(trJson.has("pumpId") ? trJson.getLong("pumpId") : 0);
if (trJson.has("duration")) {
tempBasal.durationInMinutes = trJson.getInt("duration");
}
@ -1162,7 +1169,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public boolean createOrUpdate(ExtendedBolus extendedBolus) {
try {
if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: createOrUpdate: " + Source.getString(extendedBolus.source) + " " + extendedBolus.log());
log.debug("EXTENDEDBOLUS: createOrUpdate: " + Source.getString(extendedBolus.source) + " "
+ extendedBolus.log());
ExtendedBolus old;
extendedBolus.date = roundDateToSec(extendedBolus.date);
@ -1187,7 +1195,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
getDaoExtendedBolus().createOrUpdate(extendedBolus);
}
if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " " + extendedBolus.log());
log.debug("EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " "
+ extendedBolus.log());
updateEarliestDataChange(extendedBolus.date);
scheduleExtendedBolusChange();
return true;
@ -1201,7 +1210,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
old.copyFrom(extendedBolus);
getDaoExtendedBolus().create(old);
if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: Updating record by date from: " + Source.getString(extendedBolus.source) + " " + old.log());
log.debug("EXTENDEDBOLUS: Updating record by date from: "
+ Source.getString(extendedBolus.source) + " " + old.log());
updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date);
scheduleExtendedBolusChange();
@ -1224,7 +1234,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
old.copyFrom(extendedBolus);
getDaoExtendedBolus().create(old);
if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: Updating record by _id from: " + Source.getString(extendedBolus.source) + " " + old.log());
log.debug("EXTENDEDBOLUS: Updating record by _id from: "
+ Source.getString(extendedBolus.source) + " " + old.log());
updateEarliestDataChange(oldDate);
updateEarliestDataChange(old.date);
scheduleExtendedBolusChange();
@ -1234,7 +1245,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
getDaoExtendedBolus().create(extendedBolus);
if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " " + extendedBolus.log());
log.debug("EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " "
+ extendedBolus.log());
updateEarliestDataChange(extendedBolus.date);
scheduleExtendedBolusChange();
return true;
@ -1242,7 +1254,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (extendedBolus.source == Source.USER) {
getDaoExtendedBolus().create(extendedBolus);
if (L.isEnabled(L.DATABASE))
log.debug("EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " " + extendedBolus.log());
log.debug("EXTENDEDBOLUS: New record from: " + Source.getString(extendedBolus.source) + " "
+ extendedBolus.log());
updateEarliestDataChange(extendedBolus.date);
scheduleExtendedBolusChange();
return true;
@ -1253,17 +1266,17 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return false;
}
public ExtendedBolus getExtendedBolusByPumpId(long pumpId) {
try {
return getDaoExtendedBolus().queryBuilder()
.where().eq("pumpId", pumpId)
.queryForFirst();
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);
@ -1326,20 +1339,20 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
/*
{
"_id": "5924898d577eb0880e355337",
"eventType": "Combo Bolus",
"duration": 120,
"splitNow": 0,
"splitExt": 100,
"enteredinsulin": 1,
"relative": 1,
"created_at": "2017-05-23T19:12:14Z",
"enteredBy": "AndroidAPS",
"NSCLIENT_ID": 1495566734628,
"mills": 1495566734000,
"mgdl": 106
}
* {
* "_id": "5924898d577eb0880e355337",
* "eventType": "Combo Bolus",
* "duration": 120,
* "splitNow": 0,
* "splitExt": 100,
* "enteredinsulin": 1,
* "relative": 1,
* "created_at": "2017-05-23T19:12:14Z",
* "enteredBy": "AndroidAPS",
* "NSCLIENT_ID": 1495566734628,
* "mills": 1495566734000,
* "mgdl": 106
* }
*/
public void createExtendedBolusFromJsonIfNotExists(JSONObject json) {
@ -1450,7 +1463,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
OverlappingIntervals offlineEvents = new OverlappingIntervals();
for (int i = 0; i < list.size(); i++) {
CareportalEvent event = list.get(i);
if (!event.eventType.equals(CareportalEvent.OPENAPSOFFLINE)) continue;
if (!event.eventType.equals(CareportalEvent.OPENAPSOFFLINE))
continue;
offlineEvents.add(event);
}
@ -1618,11 +1632,13 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (old != null) {
if (!old.isEqual(profileSwitch)) {
profileSwitch.source = old.source;
profileSwitch.profileName = old.profileName; // preserver profileName to prevent multiple CPP extension
profileSwitch.profileName = old.profileName; // preserver profileName to prevent multiple CPP
// extension
getDaoProfileSwitch().delete(old); // need to delete/create because date may change too
getDaoProfileSwitch().create(profileSwitch);
if (L.isEnabled(L.DATABASE))
log.debug("PROFILESWITCH: Updating record by date from: " + Source.getString(profileSwitch.source) + " " + old.toString());
log.debug("PROFILESWITCH: Updating record by date from: "
+ Source.getString(profileSwitch.source) + " " + old.toString());
scheduleProfileSwitchChange();
return true;
}
@ -1642,7 +1658,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
old.copyFrom(profileSwitch);
getDaoProfileSwitch().create(old);
if (L.isEnabled(L.DATABASE))
log.debug("PROFILESWITCH: Updating record by _id from: " + Source.getString(profileSwitch.source) + " " + old.toString());
log.debug("PROFILESWITCH: Updating record by _id from: "
+ Source.getString(profileSwitch.source) + " " + old.toString());
scheduleProfileSwitchChange();
return true;
}
@ -1652,14 +1669,16 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
profileSwitch.profileName = PercentageSplitter.pureName(profileSwitch.profileName);
getDaoProfileSwitch().create(profileSwitch);
if (L.isEnabled(L.DATABASE))
log.debug("PROFILESWITCH: New record from: " + Source.getString(profileSwitch.source) + " " + profileSwitch.toString());
log.debug("PROFILESWITCH: New record from: " + Source.getString(profileSwitch.source) + " "
+ profileSwitch.toString());
scheduleProfileSwitchChange();
return true;
}
if (profileSwitch.source == Source.USER) {
getDaoProfileSwitch().create(profileSwitch);
if (L.isEnabled(L.DATABASE))
log.debug("PROFILESWITCH: New record from: " + Source.getString(profileSwitch.source) + " " + profileSwitch.toString());
log.debug("PROFILESWITCH: New record from: " + Source.getString(profileSwitch.source) + " "
+ profileSwitch.toString());
scheduleProfileSwitchChange();
return true;
}
@ -1701,17 +1720,18 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
/*
{
"_id":"592fa43ed97496a80da913d2",
"created_at":"2017-06-01T05:20:06Z",
"eventType":"Profile Switch",
"profile":"2016 +30%",
"units":"mmol",
"enteredBy":"sony",
"NSCLIENT_ID":1496294454309,
}
*/
/*
* {
* "_id":"592fa43ed97496a80da913d2",
* "created_at":"2017-06-01T05:20:06Z",
* "eventType":"Profile Switch",
* "profile":"2016 +30%",
* "units":"mmol",
* "enteredBy":"sony",
* "NSCLIENT_ID":1496294454309,
* }
*/
public void createProfileSwitchFromJsonIfNotExists(JSONObject trJson) {
try {
@ -1796,6 +1816,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return null;
}
// ---------------- Insight history handling ---------------
public void createOrUpdate(InsightHistoryOffset offset) {
@ -1806,6 +1827,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
}
public InsightHistoryOffset getInsightHistoryOffset(String pumpSerial) {
try {
return getDaoInsightHistoryOffset().queryForId(pumpSerial);
@ -1815,6 +1837,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return null;
}
public void createOrUpdate(InsightBolusID bolusID) {
try {
getDaoInsightBolusID().createOrUpdate(bolusID);
@ -1823,19 +1846,19 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
}
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();
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);
@ -1844,14 +1867,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
}
public InsightPumpID getPumpStoppedEvent(String pumpSerial, long before) {
try {
return getDaoInsightPumpID().queryBuilder()
.orderBy("timestamp", false)
.where().eq("pumpSerial", pumpSerial)
.and().in("eventType", "PumpStopped", "PumpPaused")
.and().lt("timestamp", before)
.queryForFirst();
return getDaoInsightPumpID().queryBuilder().orderBy("timestamp", false).where()
.eq("pumpSerial", pumpSerial).and().in("eventType", "PumpStopped", "PumpPaused").and()
.lt("timestamp", before).queryForFirst();
} catch (SQLException e) {
log.error("Unhandled exception", e);
}

View file

@ -3,16 +3,16 @@ package info.nightscout.androidaps.interfaces;
import java.util.List;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Intervals;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileIntervals;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.plugins.treatments.Treatment;
import info.nightscout.androidaps.data.Intervals;
import info.nightscout.androidaps.data.ProfileIntervals;
/**
* Created by mike on 14.06.2016.
@ -20,47 +20,94 @@ import info.nightscout.androidaps.data.ProfileIntervals;
public interface TreatmentsInterface {
void updateTotalIOBTreatments();
void updateTotalIOBTempBasals();
IobTotal getLastCalculationTreatments();
IobTotal getCalculationToTimeTreatments(long time);
IobTotal getLastCalculationTempBasals();
IobTotal getCalculationToTimeTempBasals(long time, Profile profile);
MealData getMealData();
List<Treatment> getTreatmentsFromHistory();
List<Treatment> getTreatments5MinBackFromHistory(long time);
long getLastBolusTime();
// real basals (not faked by extended bolus)
boolean isInHistoryRealTempBasalInProgress();
TemporaryBasal getRealTempBasalFromHistory(long time);
boolean addToHistoryTempBasal(TemporaryBasal tempBasal);
// basal that can be faked by extended boluses
boolean isTempBasalInProgress();
TemporaryBasal getTempBasalFromHistory(long time);
Intervals<TemporaryBasal> getTemporaryBasalsFromHistory();
boolean isInHistoryExtendedBoluslInProgress();
ExtendedBolus getExtendedBolusFromHistory(long time);
Intervals<ExtendedBolus> getExtendedBolusesFromHistory();
boolean addToHistoryExtendedBolus(ExtendedBolus extendedBolus);
boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo, boolean allowUpdate);
TempTarget getTempTargetFromHistory();
TempTarget getTempTargetFromHistory(long time);
Intervals<TempTarget> getTempTargetsFromHistory();
void addToHistoryTempTarget(TempTarget tempTarget);
ProfileSwitch getProfileSwitchFromHistory(long time);
ProfileIntervals<ProfileSwitch> getProfileSwitchesFromHistory();
void addToHistoryProfileSwitch(ProfileSwitch profileSwitch);
long oldestDataAvailable();
List<Treatment> getTreatmentsFromHistoryXMinutesAgo(int minutesAgo);
}

View file

@ -1712,12 +1712,12 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
public int getBackgroundColor(OverviewColorScheme scheme) {
return MainApp.gc(scheme.getBackground(isNewColor));
return MainApp.gc(scheme.getBackground(useNewRibbonColors));
}
public int getTextColor(OverviewColorScheme scheme) {
return MainApp.gc(scheme.getTextColor(isNewColor));
return MainApp.gc(scheme.getTextColor(useNewRibbonColors));
}

View file

@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.general.wear;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.squareup.otto.Subscribe;
@ -35,11 +36,14 @@ public class WearPlugin extends PluginBase {
private final Context ctx;
private static WearPlugin wearPlugin;
private static String TAG = "WearPlugin";
public static WearPlugin getPlugin() {
return wearPlugin;
}
public static WearPlugin initPlugin(Context ctx) {
if (wearPlugin == null) {
@ -49,18 +53,15 @@ public class WearPlugin extends PluginBase {
return wearPlugin;
}
WearPlugin(Context ctx) {
super(new PluginDescription()
.mainType(PluginType.GENERAL)
.fragmentClass(WearFragment.class.getName())
.pluginName(R.string.wear)
.shortName(R.string.wear_shortname)
.preferencesId(R.xml.pref_wear)
.description(R.string.description_wear)
);
super(new PluginDescription().mainType(PluginType.GENERAL).fragmentClass(WearFragment.class.getName())
.pluginName(R.string.wear).shortName(R.string.wear_shortname).preferencesId(R.xml.pref_wear)
.description(R.string.description_wear));
this.ctx = ctx;
}
@Override
protected void onStart() {
MainApp.bus().register(this);
@ -70,38 +71,53 @@ public class WearPlugin extends PluginBase {
super.onStart();
}
@Override
protected void onStop() {
MainApp.bus().unregister(this);
}
private void sendDataToWatch(boolean status, boolean basals, boolean bgValue) {
if (isEnabled(getType())) { //only start service when this plugin is enabled
//Log.d(TAG, "WR: WearPlugin:sendDataToWatch (status=" + status + ",basals=" + basals + ",bgValue=" + bgValue + ")");
if (isEnabled(getType())) { // only start service when this plugin is enabled
if (bgValue) {
ctx.startService(new Intent(ctx, WatchUpdaterService.class));
}
if (basals) {
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_BASALS));
ctx.startService(new Intent(ctx, WatchUpdaterService.class)
.setAction(WatchUpdaterService.ACTION_SEND_BASALS));
}
if (status) {
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_STATUS));
ctx.startService(new Intent(ctx, WatchUpdaterService.class)
.setAction(WatchUpdaterService.ACTION_SEND_STATUS));
}
}
}
void resendDataToWatch() {
//Log.d(TAG, "WR: WearPlugin:resendDataToWatch");
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_RESEND));
}
void openSettings() {
//Log.d(TAG, "WR: WearPlugin:openSettings");
ctx.startService(new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_OPEN_SETTINGS));
}
void requestNotificationCancel(String actionstring) {
Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_CANCEL_NOTIFICATION);
//Log.d(TAG, "WR: WearPlugin:requestNotificationCancel");
Intent intent = new Intent(ctx, WatchUpdaterService.class)
.setAction(WatchUpdaterService.ACTION_CANCEL_NOTIFICATION);
intent.putExtra("actionstring", actionstring);
ctx.startService(intent);
}
@ -115,36 +131,43 @@ public class WearPlugin extends PluginBase {
sendDataToWatch(true, false, false);
}
@Subscribe
public void onStatusEvent(final EventTreatmentChange ev) {
sendDataToWatch(true, true, false);
}
@Subscribe
public void onStatusEvent(final EventTempBasalChange ev) {
sendDataToWatch(true, true, false);
}
@Subscribe
public void onStatusEvent(final EventOpenAPSUpdateGui ev) {
sendDataToWatch(true, true, false);
}
@Subscribe
public void onStatusEvent(final EventExtendedBolusChange ev) {
sendDataToWatch(true, true, false);
}
@Subscribe
public void onStatusEvent(final EventNewBG ev) {
sendDataToWatch(true, true, true);
}
@Subscribe
public void onStatusEvent(final EventNewBasalProfile ev) {
sendDataToWatch(false, true, false);
}
@Subscribe
public void onStatusEvent(final EventRefreshOverview ev) {
if (WatchUpdaterService.shouldReportLoopStatus(LoopPlugin.getPlugin().isEnabled(PluginType.LOOP))) {
@ -156,26 +179,31 @@ public class WearPlugin extends PluginBase {
@Subscribe
public void onStatusEvent(final EventOverviewBolusProgress ev) {
if (!ev.isSMB() || SP.getBoolean("wear_notifySMB", true)) {
Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS);
Intent intent = new Intent(ctx, WatchUpdaterService.class)
.setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS);
intent.putExtra("progresspercent", ev.percent);
intent.putExtra("progressstatus", ev.status);
ctx.startService(intent);
}
}
@Subscribe
public void onStatusEvent(final EventBolusRequested ev) {
String status = String.format(MainApp.gs(R.string.bolusrequested), ev.getAmount());
Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS);
Intent intent = new Intent(ctx, WatchUpdaterService.class)
.setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS);
intent.putExtra("progresspercent", 0);
intent.putExtra("progressstatus", status);
ctx.startService(intent);
}
@Subscribe
public void onStatusEvent(final EventDismissBolusprogressIfRunning ev) {
if (ev.result == null) return;
if (ev.result == null)
return;
String status;
if (ev.result.success) {
@ -183,34 +211,41 @@ public class WearPlugin extends PluginBase {
} else {
status = MainApp.gs(R.string.nosuccess);
}
Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS);
Intent intent = new Intent(ctx, WatchUpdaterService.class)
.setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS);
intent.putExtra("progresspercent", 100);
intent.putExtra("progressstatus", status);
ctx.startService(intent);
}
public void requestActionConfirmation(String title, String message, String actionstring) {
Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_ACTIONCONFIRMATIONREQUEST);
Intent intent = new Intent(ctx, WatchUpdaterService.class)
.setAction(WatchUpdaterService.ACTION_SEND_ACTIONCONFIRMATIONREQUEST);
intent.putExtra("title", title);
intent.putExtra("message", message);
intent.putExtra("actionstring", actionstring);
ctx.startService(intent);
}
public void requestChangeConfirmation(String title, String message, String actionstring) {
Intent intent = new Intent(ctx, WatchUpdaterService.class).setAction(WatchUpdaterService.ACTION_SEND_CHANGECONFIRMATIONREQUEST);
Intent intent = new Intent(ctx, WatchUpdaterService.class)
.setAction(WatchUpdaterService.ACTION_SEND_CHANGECONFIRMATIONREQUEST);
intent.putExtra("title", title);
intent.putExtra("message", message);
intent.putExtra("actionstring", actionstring);
ctx.startService(intent);
}
public static void registerWatchUpdaterService(WatchUpdaterService wus) {
watchUS = wus;
}
public static void unRegisterWatchUpdaterService() {
watchUS = null;
}

View file

@ -1,5 +1,8 @@
package info.nightscout.androidaps.plugins.general.wear.wearintegration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import android.os.AsyncTask;
import android.util.Log;
@ -12,41 +15,126 @@ import com.google.android.gms.wearable.PutDataMapRequest;
import com.google.android.gms.wearable.PutDataRequest;
import com.google.android.gms.wearable.Wearable;
import java.util.concurrent.TimeUnit;
/**
* Created by emmablack on 12/26/14.
*/
class SendToDataLayerThread extends AsyncTask<DataMap,Void,Void> {
class SendToDataLayerThread extends AsyncTask<DataMap, Void, Void> {
private GoogleApiClient googleApiClient;
private static final String TAG = "SendDataThread";
String path;
private static final String TAG = "SendToDataLayerThread";
private String path;
private String logPrefix = ""; // "WR: ";
private static int concurrency = 0;
private static int state = 0;
private static final ReentrantLock lock = new ReentrantLock();
private static long lastlock = 0;
private static final boolean testlockup = false; // always false in production
SendToDataLayerThread(String path, GoogleApiClient pGoogleApiClient) {
// Log.d(TAG, logPrefix + "SendToDataLayerThread: " + path);
this.path = path;
googleApiClient = pGoogleApiClient;
}
@Override
protected void onPreExecute() {
concurrency++;
if ((concurrency > 12) || ((concurrency > 3 && (lastlock != 0) && (tsl() - lastlock) > 300000))) {
// error if 9 concurrent threads or lock held for >5 minutes with concurrency of 4
final String err = "Wear Integration deadlock detected!! " + ((lastlock != 0) ? "locked" : "") + " state:"
+ state + " @" + hourMinuteString(tsl());
// Home.toaststaticnext(err);
Log.e(TAG, logPrefix + err);
}
if (concurrency < 0)
Log.d(TAG, logPrefix + "Wear Integration impossible concurrency!!");
Log.d(TAG, logPrefix + "SendDataToLayerThread pre-execute concurrency: " + concurrency);
}
@Override
protected Void doInBackground(DataMap... params) {
try {
final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await(15, TimeUnit.SECONDS);
for (Node node : nodes.getNodes()) {
for (DataMap dataMap : params) {
PutDataMapRequest putDMR = PutDataMapRequest.create(path);
putDMR.getDataMap().putAll(dataMap);
PutDataRequest request = putDMR.asPutDataRequest();
DataApi.DataItemResult result = Wearable.DataApi.putDataItem(googleApiClient, request).await(15, TimeUnit.SECONDS);
if (result.getStatus().isSuccess()) {
Log.d(TAG, "DataMap: " + dataMap + " sent to: " + node.getDisplayName());
} else {
Log.d(TAG, "ERROR: failed to send DataMap");
}
}
if (testlockup) {
try {
Log.e(TAG, logPrefix + "WARNING RUNNING TEST LOCK UP CODE - NEVER FOR PRODUCTION");
Thread.sleep(1000000); // DEEEBBUUGGGG
} catch (Exception e) {
}
} catch (Exception e) {
Log.e(TAG, "Got exception sending data to wear: " + e.toString());
}
sendToWear(params);
concurrency--;
Log.d(TAG, logPrefix + "SendDataToLayerThread post-execute concurrency: " + concurrency);
return null;
}
// Debug function to expose where it might be locking up
private synchronized void sendToWear(final DataMap... params) {
if (!lock.tryLock()) {
Log.d(TAG, logPrefix + "Concurrent access - waiting for thread unlock");
lock.lock(); // enforce single threading
Log.d(TAG, logPrefix + "Thread unlocked - proceeding");
}
lastlock = tsl();
try {
if (state != 0) {
Log.e(TAG, logPrefix + "WEAR STATE ERROR: state=" + state);
}
state = 1;
final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await(15,
TimeUnit.SECONDS);
Log.d(TAG, logPrefix + "Nodes: " + nodes);
state = 2;
for (Node node : nodes.getNodes()) {
state = 3;
for (DataMap dataMap : params) {
state = 4;
PutDataMapRequest putDMR = PutDataMapRequest.create(path);
state = 5;
putDMR.getDataMap().putAll(dataMap);
putDMR.setUrgent();
state = 6;
PutDataRequest request = putDMR.asPutDataRequest();
state = 7;
DataApi.DataItemResult result = Wearable.DataApi.putDataItem(googleApiClient, request).await(15,
TimeUnit.SECONDS);
state = 8;
if (result.getStatus().isSuccess()) {
Log.d(TAG, logPrefix + "DataMap: " + dataMap + " sent to: " + node.getDisplayName());
} else {
Log.e(TAG, logPrefix + "ERROR: failed to send DataMap");
result = Wearable.DataApi.putDataItem(googleApiClient, request).await(30, TimeUnit.SECONDS);
if (result.getStatus().isSuccess()) {
Log.d(TAG, logPrefix + "DataMap retry: " + dataMap + " sent to: " + node.getDisplayName());
} else {
Log.e(TAG, logPrefix + "ERROR on retry: failed to send DataMap: "
+ result.getStatus().toString());
}
}
state = 9;
}
}
state = 0;
} catch (Exception e) {
Log.e(TAG, logPrefix + "Got exception in sendToWear: " + e.toString());
} finally {
lastlock = 0;
lock.unlock();
}
}
private static long tsl() {
return System.currentTimeMillis();
}
private static String hourMinuteString(long timestamp) {
return android.text.format.DateFormat.format("kk:mm", timestamp).toString();
}
}

View file

@ -1,9 +1,17 @@
package info.nightscout.androidaps.plugins.general.wear.wearintegration;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Handler;
@ -14,19 +22,16 @@ import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.CapabilityApi;
import com.google.android.gms.wearable.CapabilityInfo;
import com.google.android.gms.wearable.DataMap;
import com.google.android.gms.wearable.MessageEvent;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.PutDataMapRequest;
import com.google.android.gms.wearable.PutDataRequest;
import com.google.android.gms.wearable.Wearable;
import com.google.android.gms.wearable.WearableListenerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
@ -37,36 +42,42 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.treatments.Treatment;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.treatments.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.SafeParse;
import info.nightscout.androidaps.utils.ToastUtils;
public class WatchUpdaterService extends WearableListenerService implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private static final Logger log = LoggerFactory.getLogger(WatchUpdaterService.class);
private static final String TAG = "WatchUpdaterService";
// ACTIONS
public static final String ACTION_RESEND = WatchUpdaterService.class.getName().concat(".Resend");
public static final String ACTION_OPEN_SETTINGS = WatchUpdaterService.class.getName().concat(".OpenSettings");
public static final String ACTION_SEND_STATUS = WatchUpdaterService.class.getName().concat(".SendStatus");
public static final String ACTION_SEND_BASALS = WatchUpdaterService.class.getName().concat(".SendBasals");
public static final String ACTION_SEND_BOLUSPROGRESS = WatchUpdaterService.class.getName().concat(".BolusProgress");
public static final String ACTION_SEND_ACTIONCONFIRMATIONREQUEST = WatchUpdaterService.class.getName().concat(".ActionConfirmationRequest");
public static final String ACTION_SEND_CHANGECONFIRMATIONREQUEST = WatchUpdaterService.class.getName().concat(".ChangeConfirmationRequest");
public static final String ACTION_CANCEL_NOTIFICATION = WatchUpdaterService.class.getName().concat(".CancelNotification");
public static final String ACTION_SEND_ACTIONCONFIRMATIONREQUEST = WatchUpdaterService.class.getName().concat(
".ActionConfirmationRequest");
public static final String ACTION_SEND_CHANGECONFIRMATIONREQUEST = WatchUpdaterService.class.getName().concat(
".ChangeConfirmationRequest");
public static final String ACTION_CANCEL_NOTIFICATION = WatchUpdaterService.class.getName().concat(
".CancelNotification");
private GoogleApiClient googleApiClient;
// PATHS
public static final String WEARABLE_DATA_PATH = "/nightscout_watch_data";
public static final String WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend";
private static final String WEARABLE_CANCELBOLUS_PATH = "/nightscout_watch_cancel_bolus";
@ -81,16 +92,25 @@ public class WatchUpdaterService extends WearableListenerService implements
public static final String ACTION_CONFIRMATION_REQUEST_PATH = "/nightscout_watch_actionconfirmationrequest";
public static final String ACTION_CHANGECONFIRMATION_REQUEST_PATH = "/nightscout_watch_changeconfirmationrequest";
public static final String ACTION_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest";
// Phone - Capabilites
private static final String CAPABILITY_PHONE_APP = "phone_app_sync_bgs";
private static final String MESSAGE_PATH_PHONE = "/phone_message_path";
// Wear - Capabilites
private static final String CAPABILITY_WEAR_APP = "wear_app_sync_bgs";
private static final String MESSAGE_PATH_WEAR = "/wear_message_path";
private GoogleApiClient googleApiClient;
boolean wear_integration = false;
SharedPreferences mPrefs;
private static boolean lastLoopStatus;
private static Logger log = LoggerFactory.getLogger(WatchUpdaterService.class);
private Handler handler;
private String mWearNodeId = null;
private String localnode = null;
private String logPrefix = ""; // "WR: "
@Override
public void onCreate() {
mPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
@ -106,38 +126,43 @@ public class WatchUpdaterService extends WearableListenerService implements
}
}
public void listenForChangeInSettings() {
WearPlugin.registerWatchUpdaterService(this);
}
public void setSettings() {
wear_integration = WearPlugin.getPlugin().isEnabled(PluginType.GENERAL);
// Log.d(TAG, "WR: wear_integration=" + wear_integration);
if (wear_integration) {
googleApiConnect();
}
}
public void googleApiConnect() {
private void googleApiConnect() {
if (googleApiClient != null && (googleApiClient.isConnected() || googleApiClient.isConnecting())) {
googleApiClient.disconnect();
}
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Wearable.API)
.build();
googleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).addApi(Wearable.API).build();
Wearable.MessageApi.addListener(googleApiClient, this);
if (googleApiClient.isConnected()) {
Log.d("WatchUpdater", "API client is connected");
Log.d(TAG, logPrefix + "API client is connected");
} else {
// Log.d("WatchUpdater", logPrefix + "API client is not connected and is trying to connect");
googleApiClient.connect();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent != null ? intent.getAction() : null;
// Log.d(TAG, logPrefix + "onStartCommand: " + action);
if (wear_integration) {
handler.post(() -> {
if (googleApiClient.isConnected()) {
@ -150,7 +175,8 @@ public class WatchUpdaterService extends WearableListenerService implements
} else if (ACTION_SEND_BASALS.equals(action)) {
sendBasals();
} else if (ACTION_SEND_BOLUSPROGRESS.equals(action)) {
sendBolusProgress(intent.getIntExtra("progresspercent", 0), intent.hasExtra("progressstatus") ? intent.getStringExtra("progressstatus") : "");
sendBolusProgress(intent.getIntExtra("progresspercent", 0),
intent.hasExtra("progressstatus") ? intent.getStringExtra("progressstatus") : "");
} else if (ACTION_SEND_ACTIONCONFIRMATIONREQUEST.equals(action)) {
String title = intent.getStringExtra("title");
String message = intent.getStringExtra("message");
@ -177,13 +203,63 @@ public class WatchUpdaterService extends WearableListenerService implements
}
private void updateWearSyncBgsCapability(CapabilityInfo capabilityInfo) {
Log.d("WatchUpdaterService", logPrefix + "CabilityInfo: " + capabilityInfo);
Set<Node> connectedNodes = capabilityInfo.getNodes();
mWearNodeId = pickBestNodeId(connectedNodes);
}
private String pickBestNodeId(Set<Node> nodes) {
String bestNodeId = null;
// Find a nearby node or pick one arbitrarily
for (Node node : nodes) {
if (node.isNearby()) {
return node.getId();
}
bestNodeId = node.getId();
}
return bestNodeId;
}
@Override
public void onConnected(Bundle connectionHint) {
CapabilityApi.CapabilityListener capabilityListener = capabilityInfo -> {
updateWearSyncBgsCapability(capabilityInfo);
// Log.d(TAG, logPrefix + "onConnected onCapabilityChanged mWearNodeID:" + mWearNodeId);
// new CheckWearableConnected().execute();
};
Wearable.CapabilityApi.addCapabilityListener(googleApiClient, capabilityListener, CAPABILITY_WEAR_APP);
sendData();
}
@Override
public void onPeerConnected(com.google.android.gms.wearable.Node peer) {// KS
super.onPeerConnected(peer);
String id = peer.getId();
String name = peer.getDisplayName();
// Log.d(TAG, logPrefix + "onPeerConnected peer name & ID: " + name + "|" + id);
}
@Override
public void onPeerDisconnected(com.google.android.gms.wearable.Node peer) {// KS
super.onPeerDisconnected(peer);
String id = peer.getId();
String name = peer.getDisplayName();
// Log.d(TAG, logPrefix + "onPeerDisconnected peer name & ID: " + name + "|" + id);
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
}
@Override
public void onMessageReceived(MessageEvent event) {
// Log.d(TAG, logPrefix + "onMessageRecieved: " + event);
if (wear_integration) {
if (event != null && event.getPath().equals(WEARABLE_RESEND_PATH)) {
resendData();
@ -207,13 +283,16 @@ public class WatchUpdaterService extends WearableListenerService implements
}
}
private void cancelBolus() {
ConfigBuilderPlugin.getPlugin().getActivePump().stopBolusDelivering();
}
private void sendData() {
BgReading lastBG = DatabaseHelper.lastBg();
// Log.d(TAG, logPrefix + "LastBg=" + lastBG);
if (lastBG != null) {
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
@ -228,18 +307,19 @@ public class WatchUpdaterService extends WearableListenerService implements
return;
}
new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient).execute(dataMap);
executeTask(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient), dataMap);
}
}
}
private DataMap dataMapSingleBG(BgReading lastBG, GlucoseStatus glucoseStatus) {
String units = ProfileFunctions.getInstance().getProfileUnits();
Double lowLine = SafeParse.stringToDouble(mPrefs.getString("low_mark", "0"));
Double highLine = SafeParse.stringToDouble(mPrefs.getString("high_mark", "0"));
//convert to mg/dl
// convert to mg/dl
if (!units.equals(Constants.MGDL)) {
lowLine *= Constants.MMOLL_TO_MGDL;
highLine *= Constants.MMOLL_TO_MGDL;
@ -271,8 +351,10 @@ public class WatchUpdaterService extends WearableListenerService implements
dataMap.putString("avgDelta", "--");
} else {
dataMap.putString("slopeArrow", slopeArrow(glucoseStatus.delta));
dataMap.putString("delta", deltastring(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units));
dataMap.putString("avgDelta", deltastring(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units));
dataMap.putString("delta",
deltastring(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units));
dataMap.putString("avgDelta",
deltastring(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units));
}
dataMap.putLong("sgvLevel", sgvLevel);
dataMap.putDouble("sgvDouble", lastBG.value);
@ -281,13 +363,13 @@ public class WatchUpdaterService extends WearableListenerService implements
return dataMap;
}
private String deltastring(double deltaMGDL, double deltaMMOL, String units) {
String deltastring = "";
if (deltaMGDL >= 0) {
deltastring += "+";
} else {
deltastring += "-";
}
boolean detailed = SP.getBoolean("wear_detailed_delta", false);
@ -307,6 +389,7 @@ public class WatchUpdaterService extends WearableListenerService implements
return deltastring;
}
private String slopeArrow(double delta) {
if (delta <= (-3.5 * 5)) {
return "\u21ca";
@ -330,10 +413,11 @@ public class WatchUpdaterService extends WearableListenerService implements
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
googleApiConnect();
}
long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5);
long startTime = System.currentTimeMillis() - (long)(60000 * 60 * 5.5);
BgReading last_bg = DatabaseHelper.lastBg();
if (last_bg == null) return;
if (last_bg == null)
return;
List<BgReading> graph_bgs = MainApp.getDbHelper().getBgreadingsDataFromTime(startTime, true);
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(true);
@ -352,28 +436,29 @@ public class WatchUpdaterService extends WearableListenerService implements
}
}
entries.putDataMapArrayList("entries", dataMaps);
new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient).execute(entries);
executeTask(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient), entries);
// Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
}
sendPreferences();
sendPreferences(); // DMR
sendBasals();
sendStatus();
sendStatus(); // DMR
}
private void sendBasals() {
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
googleApiConnect();
}
long now = System.currentTimeMillis();
final long startTimeWindow = now - (long) (60000 * 60 * 5.5);
final long startTimeWindow = now - (long)(60000 * 60 * 5.5);
ArrayList<DataMap> basals = new ArrayList<>();
ArrayList<DataMap> temps = new ArrayList<>();
ArrayList<DataMap> boluses = new ArrayList<>();
ArrayList<DataMap> predictions = new ArrayList<>();
Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile == null) {
@ -401,33 +486,32 @@ public class WatchUpdaterService extends WearableListenerService implements
}
}
for (; runningTime < now; runningTime += 5 * 60 * 1000) {
Profile profileTB = ProfileFunctions.getInstance().getProfile(runningTime);
//basal rate
// basal rate
endBasalValue = profile.getBasal(runningTime);
if (endBasalValue != beginBasalValue) {
//push the segment we recently left
// push the segment we recently left
basals.add(basalMap(beginBasalSegmentTime, runningTime, beginBasalValue));
//begin new Basal segment
// begin new Basal segment
beginBasalSegmentTime = runningTime;
beginBasalValue = endBasalValue;
}
//temps
// temps
tb2 = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(runningTime);
if (tb1 == null && tb2 == null) {
//no temp stays no temp
// no temp stays no temp
} else if (tb1 != null && tb2 == null) {
//temp is over -> push it
// temp is over -> push it
temps.add(tempDatamap(tb_start, tb_before, runningTime, endBasalValue, tb_amount));
tb1 = null;
} else if (tb1 == null && tb2 != null) {
//temp begins
// temp begins
tb1 = tb2;
tb_start = runningTime;
tb_before = endBasalValue;
@ -445,16 +529,16 @@ public class WatchUpdaterService extends WearableListenerService implements
}
}
if (beginBasalSegmentTime != runningTime) {
//push the remaining segment
// push the remaining segment
basals.add(basalMap(beginBasalSegmentTime, runningTime, beginBasalValue));
}
if (tb1 != null) {
tb2 = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(now); //use "now" to express current situation
tb2 = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(now); // use "now" to express current situation
if (tb2 == null) {
//express the cancelled temp by painting it down one minute early
// express the cancelled temp by painting it down one minute early
temps.add(tempDatamap(tb_start, tb_before, now - 1 * 60 * 1000, endBasalValue, tb_amount));
} else {
//express currently running temp by painting it a bit into the future
// express currently running temp by painting it a bit into the future
Profile profileNow = ProfileFunctions.getInstance().getProfile(now);
double currentAmount = tb2.tempBasalConvertedToAbsolute(now, profileNow);
if (currentAmount != tb_amount) {
@ -465,45 +549,49 @@ public class WatchUpdaterService extends WearableListenerService implements
}
}
} else {
tb2 = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(now); //use "now" to express current situation
tb2 = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(now); // use "now" to express current situation
if (tb2 != null) {
//onset at the end
// onset at the end
Profile profileTB = ProfileFunctions.getInstance().getProfile(runningTime);
double currentAmount = tb2.tempBasalConvertedToAbsolute(runningTime, profileTB);
temps.add(tempDatamap(now - 1 * 60 * 1000, endBasalValue, runningTime + 5 * 60 * 1000, currentAmount, currentAmount));
temps.add(tempDatamap(now - 1 * 60 * 1000, endBasalValue, runningTime + 5 * 60 * 1000, currentAmount,
currentAmount));
}
}
List<Treatment> treatments = TreatmentsPlugin.getPlugin().getTreatmentsFromHistory();
for (Treatment treatment : treatments) {
if (treatment.date > startTimeWindow) {
boluses.add(treatmentMap(treatment.date, treatment.insulin, treatment.carbs, treatment.isSMB, treatment.isValid));
boluses.add(treatmentMap(treatment.date, treatment.insulin, treatment.carbs, treatment.isSMB,
treatment.isValid));
}
}
final LoopPlugin.LastRun finalLastRun = LoopPlugin.lastRun;
if (SP.getBoolean("wear_predictions", true) && finalLastRun != null && finalLastRun.request.hasPredictions && finalLastRun.constraintsProcessed != null) {
if (SP.getBoolean("wear_predictions", true) && finalLastRun != null && finalLastRun.request.hasPredictions
&& finalLastRun.constraintsProcessed != null) {
List<BgReading> predArray = finalLastRun.constraintsProcessed.getPredictions();
if (!predArray.isEmpty()) {
for (BgReading bg : predArray) {
if (bg.value < 40) continue;
if (bg.value < 40)
continue;
predictions.add(predictionMap(bg.date, bg.value, bg.getPredectionColor()));
}
}
}
DataMap dm = new DataMap();
dm.putDataMapArrayList("basals", basals);
dm.putDataMapArrayList("temps", temps);
dm.putDataMapArrayList("boluses", boluses);
dm.putDataMapArrayList("predictions", predictions);
new SendToDataLayerThread(BASAL_DATA_PATH, googleApiClient).execute(dm);
executeTask(new SendToDataLayerThread(BASAL_DATA_PATH, googleApiClient), dm);
}
private DataMap tempDatamap(long startTime, double startBasal, long to, double toBasal, double amount) {
DataMap dm = new DataMap();
dm.putLong("starttime", startTime);
@ -514,6 +602,7 @@ public class WatchUpdaterService extends WearableListenerService implements
return dm;
}
private DataMap basalMap(long startTime, long endTime, double amount) {
DataMap dm = new DataMap();
dm.putLong("starttime", startTime);
@ -522,6 +611,7 @@ public class WatchUpdaterService extends WearableListenerService implements
return dm;
}
private DataMap treatmentMap(long date, double bolus, double carbs, boolean isSMB, boolean isValid) {
DataMap dm = new DataMap();
dm.putLong("date", date);
@ -532,6 +622,7 @@ public class WatchUpdaterService extends WearableListenerService implements
return dm;
}
private DataMap predictionMap(long timestamp, double sgv, int color) {
DataMap dm = new DataMap();
dm.putLong("timestamp", timestamp);
@ -544,35 +635,39 @@ public class WatchUpdaterService extends WearableListenerService implements
private void sendNotification() {
if (googleApiClient.isConnected()) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(OPEN_SETTINGS_PATH);
//unique content
// unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putString("openSettings", "openSettings");
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
debugData("sendNotification", putDataRequest);
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("OpenSettings", "No connection to wearable available!");
}
}
private void sendBolusProgress(int progresspercent, String status) {
if (googleApiClient.isConnected()) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(BOLUS_PROGRESS_PATH);
//unique content
// unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putString("bolusProgress", "bolusProgress");
dataMapRequest.getDataMap().putString("progressstatus", status);
dataMapRequest.getDataMap().putInt("progresspercent", progresspercent);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
debugData("sendBolusProgress", putDataRequest);
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("BolusProgress", "No connection to wearable available!");
}
}
private void sendActionConfirmationRequest(String title, String message, String actionstring) {
if (googleApiClient.isConnected()) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(ACTION_CONFIRMATION_REQUEST_PATH);
//unique content
// unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putString("actionConfirmationRequest", "actionConfirmationRequest");
dataMapRequest.getDataMap().putString("title", title);
@ -582,16 +677,18 @@ public class WatchUpdaterService extends WearableListenerService implements
log.debug("Requesting confirmation from wear: " + actionstring);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
debugData("sendActionConfirmationRequest", putDataRequest);
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("confirmationRequest", "No connection to wearable available!");
}
}
private void sendChangeConfirmationRequest(String title, String message, String actionstring) {
if (googleApiClient.isConnected()) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(ACTION_CHANGECONFIRMATION_REQUEST_PATH);
//unique content
// unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putString("changeConfirmationRequest", "changeConfirmationRequest");
dataMapRequest.getDataMap().putString("title", title);
@ -601,16 +698,18 @@ public class WatchUpdaterService extends WearableListenerService implements
log.debug("Requesting confirmation from wear: " + actionstring);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
debugData("sendChangeConfirmationRequest", putDataRequest);
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("changeConfirmRequest", "No connection to wearable available!");
}
}
private void sendCancelNotificationRequest(String actionstring) {
if (googleApiClient.isConnected()) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(ACTION_CANCELNOTIFICATION_REQUEST_PATH);
//unique content
// unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putString("cancelNotificationRequest", "cancelNotificationRequest");
dataMapRequest.getDataMap().putString("actionstring", actionstring);
@ -618,12 +717,14 @@ public class WatchUpdaterService extends WearableListenerService implements
log.debug("Canceling notification on wear: " + actionstring);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
debugData("sendCancelNotificationRequest", putDataRequest);
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("cancelNotificationRequest", "No connection to wearable available!");
Log.e("cancelNotificationReq", "No connection to wearable available!");
}
}
private void sendStatus() {
if (googleApiClient.isConnected()) {
@ -639,12 +740,13 @@ public class WatchUpdaterService extends WearableListenerService implements
IobTotal basalIob = treatmentsInterface.getLastCalculationTempBasals().round();
iobSum = DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob);
iobDetail = "(" + DecimalFormatter.to2Decimal(bolusIob.iob) + "|" + DecimalFormatter.to2Decimal(basalIob.basaliob) + ")";
cobString = IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "WatcherUpdaterService").generateCOBString();
iobDetail = "(" + DecimalFormatter.to2Decimal(bolusIob.iob) + "|"
+ DecimalFormatter.to2Decimal(basalIob.basaliob) + ")";
cobString = IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "WatcherUpdaterService")
.generateCOBString();
currentBasal = generateBasalString(treatmentsInterface);
//bgi
// bgi
double bgi = -(bolusIob.activity + basalIob.activity) * 5 * profile.getIsf();
bgiString = "" + ((bgi >= 0) ? "+" : "") + DecimalFormatter.to1Decimal(bgi);
@ -652,24 +754,23 @@ public class WatchUpdaterService extends WearableListenerService implements
status = generateStatusString(profile, currentBasal, iobSum, iobDetail, bgiString);
}
//batteries
// batteries
int phoneBattery = getBatteryLevel(getApplicationContext());
String rigBattery = NSDeviceStatus.getInstance().getUploaderStatus().trim();
long openApsStatus = -1;
//OpenAPS status
// OpenAPS status
if (Config.APS) {
//we are AndroidAPS
openApsStatus = LoopPlugin.lastRun != null && LoopPlugin.lastRun.lastEnact != null && LoopPlugin.lastRun.lastEnact.getTime() != 0 ? LoopPlugin.lastRun.lastEnact.getTime() : -1;
// we are AndroidAPS
openApsStatus = LoopPlugin.lastRun != null && LoopPlugin.lastRun.lastEnact != null
&& LoopPlugin.lastRun.lastEnact.getTime() != 0 ? LoopPlugin.lastRun.lastEnact.getTime() : -1;
} else {
//NSClient or remote
// NSClient or remote
openApsStatus = NSDeviceStatus.getOpenApsTimestamp();
}
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(NEW_STATUS_PATH);
//unique content
// unique content
dataMapRequest.getDataMap().putString("externalStatusString", status);
dataMapRequest.getDataMap().putString("iobSum", iobSum);
dataMapRequest.getDataMap().putString("iobDetail", iobDetail);
@ -683,30 +784,50 @@ public class WatchUpdaterService extends WearableListenerService implements
dataMapRequest.getDataMap().putBoolean("showBgi", mPrefs.getBoolean("wear_showbgi", false));
dataMapRequest.getDataMap().putInt("batteryLevel", (phoneBattery >= 30) ? 1 : 0);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
debugData("sendStatus", putDataRequest);
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("SendStatus", "No connection to wearable available!");
}
}
private void sendPreferences() {
if (googleApiClient.isConnected()) {
boolean wearcontrol = SP.getBoolean("wearcontrol", false);
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(NEW_PREFERENCES_PATH);
//unique content
// unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putBoolean("wearcontrol", wearcontrol);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
debugData("sendPreferences", putDataRequest);
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("SendStatus", "No connection to wearable available!");
}
}
private void debugData(String source, Object data) {
// Log.d(TAG, "WR: " + source + " " + data);
}
private void executeTask(AsyncTask task, DataMap... parameters) {
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[])parameters);
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
// } else {
// task.execute();
// }
}
@NonNull
private String generateStatusString(Profile profile, String currentBasal, String iobSum, String iobDetail, String bgiString) {
private String generateStatusString(Profile profile, String currentBasal, String iobSum, String iobDetail,
String bgiString) {
String status = "";
@ -733,7 +854,7 @@ public class WatchUpdaterService extends WearableListenerService implements
status += currentBasal + " " + iobString;
//add BGI if shown, otherwise return
// add BGI if shown, otherwise return
if (mPrefs.getBoolean("wear_showbgi", false)) {
status += " " + bgiString;
}
@ -741,6 +862,7 @@ public class WatchUpdaterService extends WearableListenerService implements
return status;
}
@NonNull
private String generateBasalString(TreatmentsInterface treatmentsInterface) {
@ -763,6 +885,7 @@ public class WatchUpdaterService extends WearableListenerService implements
return basalStringResult;
}
@Override
public void onDestroy() {
if (googleApiClient != null && googleApiClient.isConnected()) {
@ -771,18 +894,22 @@ public class WatchUpdaterService extends WearableListenerService implements
WearPlugin.unRegisterWatchUpdaterService();
}
@Override
public void onConnectionSuspended(int cause) {
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
public static boolean shouldReportLoopStatus(boolean enabled) {
return (lastLoopStatus != enabled);
}
public static int getBatteryLevel(Context context) {
Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
if (batteryIntent != null) {
@ -791,7 +918,7 @@ public class WatchUpdaterService extends WearableListenerService implements
if (level == -1 || scale == -1) {
return 50;
}
return (int) (((float) level / (float) scale) * 100.0f);
return (int)(((float)level / (float)scale) * 100.0f);
}
return 50;
}

View file

@ -198,6 +198,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
// TODO remove
private void migrateSettings() {
if ("US (916 MHz)".equals(SP.getString(MedtronicConst.Prefs.PumpFrequency, null))) {
@ -457,6 +458,10 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
this.pumpState = PumpDriverState.Connected;
// time (1h)
medtronicUIComm.executeCommand(MedtronicCommandType.RealTimeClock);
scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, 30);
readPumpHistory();
// TODO rewrite reading of data to be done in background or different thread perhaps ??
@ -472,10 +477,6 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
// configuration (once and then if history shows config changes)
medtronicUIComm.executeCommand(MedtronicCommandType.getSettings(MedtronicUtil.getMedtronicPumpModel()));
// time (1h)
medtronicUIComm.executeCommand(MedtronicCommandType.RealTimeClock);
scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, 30);
// read profile (once, later its controlled by isThisProfileSet method)
medtronicUIComm.executeCommand(MedtronicCommandType.GetBasalProfileSTD);
@ -511,86 +512,12 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override
public boolean isThisProfileSet(Profile profile) {
return isThisProfileSet_New(profile);
}
@Deprecated
public boolean isThisProfileSet_Old(Profile profile) {
if (!this.isInitialized) {
return true;
}
// LOG.info("isThisProfileSet: check");
LOG.info("isThisProfileSet: check [basalProfileChanged={}, basalByHourSet={}, isBasalProfileInvalid={}",
basalProfileChanged, getMDTPumpStatus().basalsByHour != null, isBasalProfileInvalid);
if (!basalProfileChanged && getMDTPumpStatus().basalsByHour != null && !isBasalProfileInvalid) {
if (isLoggingEnabled())
LOG.debug("isThisProfileSet: profile has not changed and is not invalid.");
return isProfileSame(profile);
}
setRefreshButtonEnabled(false);
if (isPumpNotReachable()) {
MedtronicUtil.sendNotification(MedtronicNotificationType.PumpUnreachable);
setRefreshButtonEnabled(true);
return true; // we don't won't setting profile if pump unreachable
}
MedtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable);
if (isLoggingEnabled())
LOG.debug("isThisProfileSet: profile possible changed, reading from Pump.");
MedtronicUITask responseTask = medtronicUIComm.executeCommand(MedtronicCommandType.GetBasalProfileSTD);
boolean valid = false;
boolean noData = false;
LOG.debug("isThisProfileSet: haveData={}", responseTask.hasData());
if (responseTask.hasData()) {
valid = isProfileSame(profile);
LOG.debug("isThisProfileSet: valid={}", valid);
if (valid) {
basalProfileChanged = false;
}
} else {
noData = true;
if (isLoggingEnabled())
LOG.debug("Basal profile NO DATA");
}
isBasalProfileInvalid = !valid;
setRefreshButtonEnabled(true);
// we don't want to force set profile if we couldn't read the profile (noData)
return (noData || valid);
}
public boolean isThisProfileSet_New(Profile profile) {
LOG.debug("isThisProfileSet: basalInitalized={}", getMDTPumpStatus().basalProfileStatus);
if (getMDTPumpStatus().basalProfileStatus != BasalProfileStatus.ProfileOK)
return true;
return isProfileSame(profile);
}

View file

@ -560,8 +560,8 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
rawHistoryPage.dumpToDebug();
List<PumpHistoryEntry> medtronicHistoryEntries = pumpHistoryDecoder.processPageAndCreateRecords(
rawHistoryPage, false, PumpHistoryEntry.class);
List<PumpHistoryEntry> medtronicHistoryEntries = pumpHistoryDecoder
.processPageAndCreateRecords(rawHistoryPage);
LOG.debug("getPumpHistory: Found {} history entries.", medtronicHistoryEntries.size());

View file

@ -34,7 +34,7 @@ import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil;
* <p>
* Author: Andy {andy@atech-software.com}
*/
public abstract class MedtronicHistoryDecoder {
public abstract class MedtronicHistoryDecoder<T extends MedtronicHistoryEntry> implements MedtronicHistoryDecoderInterface<T> {
private static final Logger LOG = LoggerFactory.getLogger(MedtronicHistoryDecoder.class);
@ -51,8 +51,9 @@ public abstract class MedtronicHistoryDecoder {
}
public abstract RecordDecodeStatus decodeRecord(MedtronicHistoryEntry record);
// public abstract <E extends MedtronicHistoryEntry> Class<E> getHistoryEntryClass();
// public abstract RecordDecodeStatus decodeRecord(T record);
public abstract void postProcess();
@ -92,7 +93,7 @@ public abstract class MedtronicHistoryDecoder {
// TODO_ extend this to also use bigger pages (for now we support only 1024
// pages)
public List<Byte> checkPage(RawHistoryPage page, boolean partial) throws RuntimeException {
private List<Byte> checkPage(RawHistoryPage page, boolean partial) throws RuntimeException {
List<Byte> byteList = new ArrayList<Byte>();
// if (!partial && page.getData().length != 1024 /* page.commandType.getRecordLength() */) {
@ -120,9 +121,8 @@ public abstract class MedtronicHistoryDecoder {
// public abstract List<? extends MedtronicHistoryEntry> processPageAndCreateRecords(RawHistoryPage page,
// boolean partial) throws Exception;
public <E extends MedtronicHistoryEntry> List<E> processPageAndCreateRecords(RawHistoryPage rawHistoryPage,
Class<E> clazz) throws Exception {
return processPageAndCreateRecords(rawHistoryPage, false, clazz);
public List<T> processPageAndCreateRecords(RawHistoryPage rawHistoryPage) {
return processPageAndCreateRecords(rawHistoryPage, false);
}
@ -213,12 +213,19 @@ public abstract class MedtronicHistoryDecoder {
}
public <E extends MedtronicHistoryEntry> List<E> processPageAndCreateRecords(RawHistoryPage rawHistoryPage,
boolean partial, Class<E> clazz) {
List<Byte> dataClear = checkPage(rawHistoryPage, partial);
List<E> records = createRecords(dataClear, clazz);
// public List<T> processPageAndCreateRecords(RawHistoryPage rawHistoryPage) {
// return processPageAndCreateRecords(rawHistoryPage, false, getHistoryEntryClass());
// }
for (MedtronicHistoryEntry record : records) {
// public List<T> processPageAndCreateRecords(RawHistoryPage rawHistoryPage, boolean partial) {
// return processPageAndCreateRecords(rawHistoryPage, partial, getHistoryEntryClass());
// }
private List<T> processPageAndCreateRecords(RawHistoryPage rawHistoryPage, boolean partial) {
List<Byte> dataClear = checkPage(rawHistoryPage, partial);
List<T> records = createRecords(dataClear);
for (T record : records) {
decodeRecord(record);
}
@ -227,7 +234,6 @@ public abstract class MedtronicHistoryDecoder {
return records;
}
protected abstract <E extends MedtronicHistoryEntry> List<E> createRecords(List<Byte> dataClear, Class<E> clazz);
// public abstract List<T> createRecords(List<Byte> dataClear);
}

View file

@ -0,0 +1,16 @@
package info.nightscout.androidaps.plugins.pump.medtronic.comm.history;
import java.util.List;
/**
* Created by andy on 3/10/19.
*/
public interface MedtronicHistoryDecoderInterface<T> {
RecordDecodeStatus decodeRecord(T record);
List<T> createRecords(List<Byte> dataClear);
}

View file

@ -10,7 +10,6 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil;
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryDecoder;
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryEntry;
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RecordDecodeStatus;
/**
@ -35,7 +34,7 @@ import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RecordDeco
* Author: Andy {andy@atech-software.com}
*/
public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder {
public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder<CGMSHistoryEntry> {
private static final Logger LOG = LoggerFactory.getLogger(MedtronicCGMSHistoryDecoder.class);
@ -46,7 +45,17 @@ public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder {
}
public RecordDecodeStatus decodeRecord(MedtronicHistoryEntry entryIn) {
// @Override
// public Class<CGMSHistoryEntry> getHistoryEntryClass() {
// return CGMSHistoryEntry.class;
// }
// @Override
// public Class getHistoryEntryClass() {
// return CGMSHistoryEntry.class;
// }
public RecordDecodeStatus decodeRecord(CGMSHistoryEntry entryIn) {
CGMSHistoryEntry precord = (CGMSHistoryEntry)entryIn;
try {
return decodeRecord(precord, false);
@ -110,7 +119,7 @@ public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder {
}
protected <E extends MedtronicHistoryEntry> List<E> createRecords(List<Byte> dataClearInput, Class<E> clazz) {
public List<CGMSHistoryEntry> createRecords(List<Byte> dataClearInput) {
// List<MinimedHistoryEntry> listRecords = new
// ArrayList<MinimedHistoryEntry>();
@ -126,7 +135,7 @@ public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder {
int counter = 0;
int record = 0;
List<E> outList = new ArrayList<E>();
List<CGMSHistoryEntry> outList = new ArrayList<CGMSHistoryEntry>();
// create CGMS entries (without dates)
do {
@ -156,7 +165,7 @@ public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder {
// System.out.println("Record: " + pe);
outList.add((E)pe);
outList.add(pe);
} else {
List<Byte> listRawData = new ArrayList<Byte>();
listRawData.add((byte)opCode);
@ -174,7 +183,7 @@ public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder {
// System.out.println("Record: " + pe);
outList.add((E)pe);
outList.add(pe);
}
} else {
CGMSHistoryEntry pe = new CGMSHistoryEntry();
@ -188,7 +197,7 @@ public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder {
// System.out.println("Record: " + pe);
outList.add((E)pe);
outList.add(pe);
}
} while (counter < dataClear.size());

View file

@ -46,7 +46,7 @@ import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil;
* Author: Andy {andy@atech-software.com}
*/
public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder<PumpHistoryEntry> {
private static final Logger LOG = LoggerFactory.getLogger(MedtronicPumpHistoryDecoder.class);
@ -64,7 +64,12 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
}
protected <E extends MedtronicHistoryEntry> List<E> createRecords(List<Byte> dataClear, Class<E> clazz) {
// @Override
// public Class<PumpHistoryEntry> getHistoryEntryClass() {
// return PumpHistoryEntry.class;
// }
public List<PumpHistoryEntry> createRecords(List<Byte> dataClear) {
prepareStatistics();
int counter = 0;
@ -72,7 +77,7 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
boolean incompletePacket = false;
deviceType = MedtronicUtil.getMedtronicPumpModel();
List<E> outList = new ArrayList<E>();
List<PumpHistoryEntry> outList = new ArrayList<PumpHistoryEntry>();
String skipped = null;
int elementStart = 0;
@ -193,7 +198,7 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
if (decoded == RecordDecodeStatus.OK) // we add only OK records, all others are ignored
{
outList.add((E)pe);
outList.add(pe);
}
}
@ -203,7 +208,7 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
}
public RecordDecodeStatus decodeRecord(MedtronicHistoryEntry entryIn) {
public RecordDecodeStatus decodeRecord(PumpHistoryEntry entryIn) {
PumpHistoryEntry precord = (PumpHistoryEntry)entryIn;
try {
return decodeRecord(entryIn, false);
@ -214,19 +219,6 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
}
public <E extends MedtronicHistoryEntry> List<E> getTypedList(List<? extends MedtronicHistoryEntry> list,
Class<E> clazz) {
List<E> listOut = new ArrayList<>();
for (MedtronicHistoryEntry medtronicHistoryEntry : list) {
listOut.add((E)medtronicHistoryEntry);
}
return listOut;
}
public RecordDecodeStatus decodeRecord(MedtronicHistoryEntry entryIn, boolean x) {
// FIXME
// TODO
@ -245,6 +237,7 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
case DailyTotals522:
case DailyTotals523:
case DailyTotals515:
case EndResultTotals:
return decodeDailyTotals(entry); // Not supported at the moment
case ChangeBasalPattern:
@ -380,9 +373,9 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
decodeBolus(entry);
return RecordDecodeStatus.OK;
case EndResultTotals:
decodeEndResultTotals(entry);
return RecordDecodeStatus.OK;
// case EndResultTotals:
// decodeEndResultTotals(entry);
// return RecordDecodeStatus.OK;
case BatteryChange:
decodeBatteryActivity(entry);

View file

@ -137,7 +137,7 @@ public class MedtronicUIPostprocessor {
Duration dur = new Duration(clockDTO.localDeviceTime.toDateTime(DateTimeZone.UTC),
clockDTO.pumpTime.toDateTime(DateTimeZone.UTC));
clockDTO.timeDifference = dur.getStandardSeconds();
clockDTO.timeDifference = (int)dur.getStandardSeconds();
MedtronicUtil.setPumpTime(clockDTO);

View file

@ -7,6 +7,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.joda.time.LocalDateTime;
import org.joda.time.Minutes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -22,10 +24,10 @@ import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpH
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntryType;
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryResult;
import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile;
import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.ClockDTO;
import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.DailyTotalsDTO;
import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus;
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
//import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin;
@ -49,6 +51,7 @@ public class MedtronicHistoryData {
private int basalProfileChangedInternally = 0;
private Gson gsonPretty;
private List<PumpHistoryEntry> fakeTBRs;
public MedtronicHistoryData() {
@ -120,7 +123,7 @@ public class MedtronicHistoryData {
}
TBRs = processTBRs(TBRs);
TBRs = preProcessTBRs(TBRs);
newHistory2.addAll(TBRs);
@ -204,9 +207,6 @@ public class MedtronicHistoryData {
// TODO This logic might not be working correctly
public boolean isPumpSuspended(Boolean wasPumpSuspended) {
// if (true)
// return false;
List<PumpHistoryEntry> newAndAll = new ArrayList<>();
if (!isCollectionEmpty(this.allHistory)) {
@ -222,6 +222,8 @@ public class MedtronicHistoryData {
this.sort(newAndAll);
List<PumpHistoryEntry> newAndAll2 = filterPumpSuspend(newAndAll);
List<PumpHistoryEntry> items = getFilteredItems(newAndAll, //
PumpHistoryEntryType.Bolus, //
PumpHistoryEntryType.TempBasalCombined, //
@ -244,83 +246,32 @@ public class MedtronicHistoryData {
pumpHistoryEntryType == PumpHistoryEntryType.PumpResume || //
pumpHistoryEntryType == PumpHistoryEntryType.Prime);
// if (wasPumpSuspended == null) { // suspension status not known
//
// List<PumpHistoryEntry> items = getFilteredItems(PumpHistoryEntryType.Bolus, //
// PumpHistoryEntryType.TempBasalCombined, //
// PumpHistoryEntryType.Prime, //
// PumpHistoryEntryType.PumpSuspend, //
// PumpHistoryEntryType.PumpResume, //
// PumpHistoryEntryType.Rewind, //
// PumpHistoryEntryType.NoDeliveryAlarm, //
// PumpHistoryEntryType.BasalProfileStart);
//
// if (items.size() == 0)
// return wasPumpSuspended == null ? false : wasPumpSuspended;
//
// PumpHistoryEntry pumpHistoryEntry = items.get(0);
//
// return !(pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.TempBasalCombined || //
// pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.BasalProfileStart || //
// pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.Bolus || //
// pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.PumpResume);
//
// } else {
//
// List<PumpHistoryEntry> items = getFilteredItems(PumpHistoryEntryType.Bolus, //
// PumpHistoryEntryType.TempBasalCombined, //
// PumpHistoryEntryType.Prime, //
// PumpHistoryEntryType.PumpSuspend, //
// PumpHistoryEntryType.PumpResume, //
// PumpHistoryEntryType.Rewind, //
// PumpHistoryEntryType.NoDeliveryAlarm, //
// PumpHistoryEntryType.BasalProfileStart);
//
// if (wasPumpSuspended) {
//
// if (items.size() == 0)
// return wasPumpSuspended == null ? false : wasPumpSuspended;
//
// PumpHistoryEntry pumpHistoryEntry = items.get(0);
//
// if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.TempBasalCombined || //
// pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.BasalProfileStart || //
// pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.Bolus || //
// pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.PumpResume)
// return false;
// else
// return true;
//
// } else {
//
// if (items.size() == 0)
// return wasPumpSuspended == null ? false : wasPumpSuspended;
//
// PumpHistoryEntry pumpHistoryEntry = items.get(0);
//
// if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.NoDeliveryAlarm || //
// pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.PumpSuspend || //
// pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.Prime)
// return true;
//
// }
//
// }
}
// FIXME
// return false;
private List<PumpHistoryEntry> filterPumpSuspend(List<PumpHistoryEntry> newAndAll) {
if (newAndAll.size() < 11) {
return newAndAll;
}
List<PumpHistoryEntry> newAndAllOut = new ArrayList<>();
for (int i = 0; i < 10; i++) {
newAndAllOut.add(newAndAll.get(i));
}
return newAndAllOut;
}
/**
* Process History Data: Boluses(Treatments), TDD, TBRs, Suspend-Resume (or other pump stops: battery, prime)
*/
public void processNewHistoryData() {
// TDD
List<PumpHistoryEntry> tdds = getFilteredListByLastRecord(getTDDType());
List<PumpHistoryEntry> tdds = getFilteredListByLastRecord(PumpHistoryEntryType.EndResultTotals, getTDDType());
LOG.debug("ProcessHistoryData: TDD [count={}, items={}]", tdds.size(), gsonPretty.toJson(tdds));
@ -331,11 +282,11 @@ public class MedtronicHistoryData {
// Bolus
List<PumpHistoryEntry> treatments = getFilteredListByLastRecord(PumpHistoryEntryType.Bolus);
LOG.debug("ProcessHistoryData: Bolus [count={}, items=", treatments.size());
LOG.debug("ProcessHistoryData: Bolus [count={}, itemsCount={}]", treatments.size());
showLogs(null, gsonPretty.toJson(treatments));
if (treatments.size() > 0) {
// processTreatments(treatments);
// processBoluses(treatments);
}
// TBR
@ -345,14 +296,28 @@ public class MedtronicHistoryData {
showLogs(null, gsonPretty.toJson(tbrs));
if (tbrs.size() > 0) {
// processTreatments(treatments);
// processTBRs(tbrs);
}
// Fake TBR
// Suspends (for suspends/resume, fakeTBR)
List<PumpHistoryEntry> suspends = getSuspends();
LOG.debug("ProcessHistoryData: FakeTBRs (suspend/resume) [count={}, items=", suspends.size());
showLogs(null, gsonPretty.toJson(suspends));
if (suspends.size() > 0) {
// processSuspends(treatments);
}
}
ClockDTO pumpTime;
public void processTDDs(List<PumpHistoryEntry> tdds) {
public void processTDDs(List<PumpHistoryEntry> tddsIn) {
List<PumpHistoryEntry> tdds = filterTDDs(tddsIn);
pumpTime = MedtronicUtil.getPumpTime();
LOG.error(getLogPrefix() + "TDDs found: {}. Not processed.\n{}", tdds.size(), gsonPretty.toJson(tdds));
@ -390,6 +355,66 @@ public class MedtronicHistoryData {
}
// TODO needs to be implemented
public void processBoluses(List<PumpHistoryEntry> boluses) {
int dateDifference = getOldestDateDifference(boluses);
// List<Treatment> treatmentsFromHistory = TreatmentsPlugin.getPlugin().getTreatmentsFromHistoryXMinutesAgo(
// dateDifference);
for (PumpHistoryEntry treatment : boluses) {
LOG.debug("TOE. Treatment: " + treatment);
long inLocalTime = tryToGetByLocalTime(treatment.atechDateTime);
}
}
// TODO needs to be implemented
public void processTBRs(List<PumpHistoryEntry> treatments) {
int dateDifference = getOldestDateDifference(treatments);
// List<Treatment> treatmentsFromHistory = TreatmentsPlugin.getPlugin().getTreatmentsFromHistoryXMinutesAgo(
// dateDifference);
for (PumpHistoryEntry treatment : treatments) {
LOG.debug("TOE. Treatment: " + treatment);
long inLocalTime = tryToGetByLocalTime(treatment.atechDateTime);
}
}
// TODO needs to be implemented
public void processSuspends(List<PumpHistoryEntry> treatments) {
}
// TODO needs to be implemented
public List<PumpHistoryEntry> getSuspends() {
return new ArrayList<>();
}
private List<PumpHistoryEntry> filterTDDs(List<PumpHistoryEntry> tdds) {
List<PumpHistoryEntry> tddsOut = new ArrayList<>();
for (PumpHistoryEntry tdd : tdds) {
if (tdd.getEntryType() != PumpHistoryEntryType.EndResultTotals) {
tddsOut.add(tdd);
}
}
return tddsOut.size() == 0 ? tdds : tddsOut;
}
private TDD findTDD(long atechDateTime, List<TDD> tddsDb) {
for (TDD tdd : tddsDb) {
@ -403,9 +428,42 @@ public class MedtronicHistoryData {
}
private void processTreatments(List<PumpHistoryEntry> treatments) {
private long tryToGetByLocalTime(long atechDateTime) {
TreatmentsPlugin.getPlugin().getTreatmentsFromHistory();
LocalDateTime ldt = DateTimeUtil.toLocalDateTime(atechDateTime);
LOG.debug("TOE. Time of Entry: " + atechDateTime);
LOG.debug("TOE. Clock Pump: " + pumpTime.pumpTime.toString("HH:mm:ss"));
LOG.debug("TOE. LocalTime: " + pumpTime.localDeviceTime.toString("HH:mm:ss"));
LOG.debug("TOE. Difference(s): " + pumpTime.timeDifference);
ldt.plusSeconds(pumpTime.timeDifference);
LOG.debug("TOE. New Time Of Entry: " + ldt.toString("HH:mm:ss"));
return ldt.toDate().getTime();
// return 0;
}
private int getOldestDateDifference(List<PumpHistoryEntry> treatments) {
long dt = Long.MAX_VALUE;
for (PumpHistoryEntry treatment : treatments) {
if (treatment.atechDateTime < dt) {
dt = treatment.atechDateTime;
}
}
LocalDateTime d = DateTimeUtil.toLocalDateTime(dt);
d.minusMinutes(5);
Minutes minutes = Minutes.minutesBetween(d, new LocalDateTime());
return minutes.getMinutes();
}
@ -422,12 +480,6 @@ public class MedtronicHistoryData {
//
// }
// public List<PumpHistoryEntry> getTDDs() {
//
// return getFilteredListByLastRecord(getTDDType());
//
// }
private PumpHistoryEntryType getTDDType() {
switch (MedtronicUtil.getMedtronicPumpModel()) {
@ -454,15 +506,6 @@ public class MedtronicHistoryData {
}
public List<PumpHistoryEntry> getTreatments() {
return getFilteredListByLastRecord( //
PumpHistoryEntryType.Bolus, //
PumpHistoryEntryType.TempBasalCombined);
}
/*
* entryType == PumpHistoryEntryType.Bolus || // Treatments
* entryType == PumpHistoryEntryType.TempBasalRate || //
@ -589,7 +632,7 @@ public class MedtronicHistoryData {
}
private List<PumpHistoryEntry> processTBRs(List<PumpHistoryEntry> TBRs_Input) {
private List<PumpHistoryEntry> preProcessTBRs(List<PumpHistoryEntry> TBRs_Input) {
List<PumpHistoryEntry> TBRs = new ArrayList<>();
Map<String, PumpHistoryEntry> map = new HashMap<>();

View file

@ -12,5 +12,7 @@ public class ClockDTO {
public LocalDateTime pumpTime;
public long timeDifference; // s
//public Duration timeDifference;
public int timeDifference; // s
}

View file

@ -1,18 +1,18 @@
package info.nightscout.androidaps.plugins.treatments;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.content.Intent;
import android.support.annotation.Nullable;
import com.crashlytics.android.answers.CustomEvent;
import com.squareup.otto.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
@ -41,16 +41,16 @@ import info.nightscout.androidaps.interfaces.TreatmentsInterface;
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.iob.iobCobCalculator.AutosensData;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.general.overview.Dialogs.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
@ -58,10 +58,12 @@ import info.nightscout.androidaps.utils.T;
* Created by mike on 05.08.2016.
*/
public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface {
private Logger log = LoggerFactory.getLogger(L.DATATREATMENTS);
private static TreatmentsPlugin treatmentsPlugin;
public static TreatmentsPlugin getPlugin() {
if (treatmentsPlugin == null)
treatmentsPlugin = new TreatmentsPlugin();
@ -79,18 +81,15 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
private final Intervals<TempTarget> tempTargets = new OverlappingIntervals<>();
private final ProfileIntervals<ProfileSwitch> profiles = new ProfileIntervals<>();
public TreatmentsPlugin() {
super(new PluginDescription()
.mainType(PluginType.TREATMENT)
.fragmentClass(TreatmentsFragment.class.getName())
.pluginName(R.string.treatments)
.shortName(R.string.treatments_shortname)
.alwaysEnabled(true)
.description(R.string.description_treatments)
);
super(new PluginDescription().mainType(PluginType.TREATMENT).fragmentClass(TreatmentsFragment.class.getName())
.pluginName(R.string.treatments).shortName(R.string.treatments_shortname).alwaysEnabled(true)
.description(R.string.description_treatments));
this.service = new TreatmentService();
}
@Override
protected void onStart() {
MainApp.bus().register(this);
@ -102,35 +101,39 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
super.onStart();
}
@Override
protected void onStop() {
MainApp.bus().register(this);
}
public TreatmentService getService() {
return this.service;
}
private void initializeTreatmentData() {
if (L.isEnabled(L.DATATREATMENTS))
log.debug("initializeTreatmentData");
double dia = Constants.defaultDIA;
if (ConfigBuilderPlugin.getPlugin() != null && ProfileFunctions.getInstance().getProfile() != null)
dia = ProfileFunctions.getInstance().getProfile().getDia();
long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia));
long fromMills = (long)(System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia));
synchronized (treatments) {
treatments.clear();
treatments.addAll(getService().getTreatmentDataFromTime(fromMills, false));
}
}
private void initializeTempBasalData() {
if (L.isEnabled(L.DATATREATMENTS))
log.debug("initializeTempBasalData");
double dia = Constants.defaultDIA;
if (ConfigBuilderPlugin.getPlugin() != null && ProfileFunctions.getInstance().getProfile() != null)
dia = ProfileFunctions.getInstance().getProfile().getDia();
long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia));
long fromMills = (long)(System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia));
synchronized (tempBasals) {
tempBasals.reset().add(MainApp.getDbHelper().getTemporaryBasalsDataFromTime(fromMills, false));
@ -138,13 +141,14 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
private void initializeExtendedBolusData() {
if (L.isEnabled(L.DATATREATMENTS))
log.debug("initializeExtendedBolusData");
double dia = Constants.defaultDIA;
if (ConfigBuilderPlugin.getPlugin() != null && ProfileFunctions.getInstance().getProfile() != null)
dia = ProfileFunctions.getInstance().getProfile().getDia();
long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia));
long fromMills = (long)(System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia));
synchronized (extendedBoluses) {
extendedBoluses.reset().add(MainApp.getDbHelper().getExtendedBolusDataFromTime(fromMills, false));
@ -152,6 +156,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
private void initializeTempTargetData() {
if (L.isEnabled(L.DATATREATMENTS))
log.debug("initializeTempTargetData");
@ -161,6 +166,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
private void initializeProfileSwitchData() {
if (L.isEnabled(L.DATATREATMENTS))
log.debug("initializeProfileSwitchData");
@ -169,11 +175,13 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
@Override
public IobTotal getLastCalculationTreatments() {
return lastTreatmentCalculation;
}
@Override
public IobTotal getCalculationToTimeTreatments(long time) {
IobTotal total = new IobTotal(time);
@ -184,15 +192,17 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin();
if (insulinInterface == null)
return total;
return total;
double dia = profile.getDia();
synchronized (treatments) {
for (Integer pos = 0; pos < treatments.size(); pos++) {
Treatment t = treatments.get(pos);
if (!t.isValid) continue;
if (t.date > time) continue;
if (!t.isValid)
continue;
if (t.date > time)
continue;
Iob tIOB = t.iobCalc(time, dia);
total.iob += tIOB.iobContrib;
total.activity += tIOB.activityContrib;
@ -202,7 +212,9 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
// instead of dividing the DIA that only worked on the bilinear curves,
// multiply the time the treatment is seen active.
long timeSinceTreatment = time - t.date;
long snoozeTime = t.date + (long) (timeSinceTreatment * SP.getDouble(R.string.key_openapsama_bolussnooze_dia_divisor, 2.0));
long snoozeTime = t.date
+ (long)(timeSinceTreatment * SP
.getDouble(R.string.key_openapsama_bolussnooze_dia_divisor, 2.0));
Iob bIOB = t.iobCalc(snoozeTime, dia);
total.bolussnooze += bIOB.iobContrib;
}
@ -213,7 +225,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
synchronized (extendedBoluses) {
for (Integer pos = 0; pos < extendedBoluses.size(); pos++) {
ExtendedBolus e = extendedBoluses.get(pos);
if (e.date > time) continue;
if (e.date > time)
continue;
IobTotal calc = e.iobCalc(time);
total.plus(calc);
}
@ -221,23 +234,27 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
return total;
}
@Override
public void updateTotalIOBTreatments() {
lastTreatmentCalculation = getCalculationToTimeTreatments(System.currentTimeMillis());
}
@Override
public MealData getMealData() {
MealData result = new MealData();
Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile == null) return result;
if (profile == null)
return result;
long now = System.currentTimeMillis();
long dia_ago = now - (Double.valueOf(profile.getDia() * T.hours(1).msecs())).longValue();
double maxAbsorptionHours = Constants.DEFAULT_MAX_ABSORPTION_TIME;
if (SensitivityAAPSPlugin.getPlugin().isEnabled(PluginType.SENSITIVITY) || SensitivityWeightedAveragePlugin.getPlugin().isEnabled(PluginType.SENSITIVITY)) {
if (SensitivityAAPSPlugin.getPlugin().isEnabled(PluginType.SENSITIVITY)
|| SensitivityWeightedAveragePlugin.getPlugin().isEnabled(PluginType.SENSITIVITY)) {
maxAbsorptionHours = SP.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME);
} else {
maxAbsorptionHours = SP.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME);
@ -259,7 +276,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
if (t > absorptionTime_ago && t <= now) {
if (treatment.carbs >= 1) {
result.carbs += treatment.carbs;
if(t > result.lastCarbTime)
if (t > result.lastCarbTime)
result.lastCarbTime = t;
}
}
@ -277,6 +294,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
return result;
}
@Override
public List<Treatment> getTreatmentsFromHistory() {
synchronized (treatments) {
@ -284,6 +302,24 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
@Override
public List<Treatment> getTreatmentsFromHistoryXMinutesAgo(int minutesAgo) {
List<Treatment> in5minback = new ArrayList<>();
long time = System.currentTimeMillis();
synchronized (treatments) {
for (Integer pos = 0; pos < treatments.size(); pos++) {
Treatment t = treatments.get(pos);
if (!t.isValid)
continue;
if (t.date <= time && t.date > (time - minutesAgo * 60 * 1000))
in5minback.add(t);
}
return in5minback;
}
}
@Override
public List<Treatment> getTreatments5MinBackFromHistory(long time) {
List<Treatment> in5minback = new ArrayList<>();
@ -299,6 +335,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
@Override
public long getLastBolusTime() {
long now = System.currentTimeMillis();
@ -312,15 +349,17 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
if (L.isEnabled(L.DATATREATMENTS))
log.debug("Last bolus time: " + new Date(last).toLocaleString());
log.debug("Last bolus time: " + new Date(last).toLocaleString());
return last;
}
@Override
public boolean isInHistoryRealTempBasalInProgress() {
return getRealTempBasalFromHistory(System.currentTimeMillis()) != null;
}
@Override
public TemporaryBasal getRealTempBasalFromHistory(long time) {
synchronized (tempBasals) {
@ -328,58 +367,66 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
@Override
public boolean isTempBasalInProgress() {
return getTempBasalFromHistory(System.currentTimeMillis()) != null;
}
@Override
public boolean isInHistoryExtendedBoluslInProgress() {
return getExtendedBolusFromHistory(System.currentTimeMillis()) != null; //TODO: crosscheck here
return getExtendedBolusFromHistory(System.currentTimeMillis()) != null; // TODO: crosscheck here
}
@Subscribe
public void onStatusEvent(final EventReloadTreatmentData ev) {
if (L.isEnabled(L.DATATREATMENTS))
log.debug("EventReloadTreatmentData");
log.debug("EventReloadTreatmentData");
initializeTreatmentData();
initializeExtendedBolusData();
updateTotalIOBTreatments();
MainApp.bus().post(ev.next);
}
@Subscribe
@SuppressWarnings("unused")
public void onStatusEvent(final EventReloadTempBasalData ev) {
if (L.isEnabled(L.DATATREATMENTS))
log.debug("EventReloadTempBasalData");
log.debug("EventReloadTempBasalData");
initializeTempBasalData();
updateTotalIOBTempBasals();
}
@Override
public IobTotal getLastCalculationTempBasals() {
return lastTempBasalsCalculation;
}
@Override
public IobTotal getCalculationToTimeTempBasals(long time, Profile profile) {
return getCalculationToTimeTempBasals(time, profile, false, 0);
}
public IobTotal getCalculationToTimeTempBasals(long time, Profile profile, boolean truncate, long truncateTime) {
IobTotal total = new IobTotal(time);
InsulinInterface insulinInterface = ConfigBuilderPlugin.getPlugin().getActiveInsulin();
if (insulinInterface == null)
return total;
return total;
synchronized (tempBasals) {
for (Integer pos = 0; pos < tempBasals.size(); pos++) {
TemporaryBasal t = tempBasals.get(pos);
if (t.date > time) continue;
if (t.date > time)
continue;
IobTotal calc;
if(truncate && t.end() > truncateTime){
if (truncate && t.end() > truncateTime) {
TemporaryBasal dummyTemp = new TemporaryBasal();
dummyTemp.copyFrom(t);
dummyTemp.cutEndTo(truncateTime);
@ -387,7 +434,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
} else {
calc = t.iobCalc(time, profile);
}
//log.debug("BasalIOB " + new Date(time) + " >>> " + calc.basaliob);
// log.debug("BasalIOB " + new Date(time) + " >>> " + calc.basaliob);
total.plus(calc);
}
}
@ -396,9 +443,10 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
synchronized (extendedBoluses) {
for (Integer pos = 0; pos < extendedBoluses.size(); pos++) {
ExtendedBolus e = extendedBoluses.get(pos);
if (e.date > time) continue;
if (e.date > time)
continue;
IobTotal calc;
if(truncate && e.end() > truncateTime){
if (truncate && e.end() > truncateTime) {
ExtendedBolus dummyExt = new ExtendedBolus();
dummyExt.copyFrom(e);
dummyExt.cutEndTo(truncateTime);
@ -419,6 +467,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
return total;
}
@Override
public void updateTotalIOBTempBasals() {
Profile profile = ProfileFunctions.getInstance().getProfile();
@ -426,6 +475,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
lastTempBasalsCalculation = getCalculationToTimeTempBasals(DateUtil.now(), profile);
}
@Nullable
@Override
public TemporaryBasal getTempBasalFromHistory(long time) {
@ -438,6 +488,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
return null;
}
@Override
public ExtendedBolus getExtendedBolusFromHistory(long time) {
synchronized (extendedBoluses) {
@ -445,9 +496,10 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
@Override
public boolean addToHistoryExtendedBolus(ExtendedBolus extendedBolus) {
//log.debug("Adding new ExtentedBolus record" + extendedBolus.log());
// log.debug("Adding new ExtentedBolus record" + extendedBolus.log());
boolean newRecordCreated = MainApp.getDbHelper().createOrUpdate(extendedBolus);
if (newRecordCreated) {
if (extendedBolus.durationInMinutes == 0) {
@ -463,6 +515,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
return newRecordCreated;
}
@Override
public Intervals<ExtendedBolus> getExtendedBolusesFromHistory() {
synchronized (extendedBoluses) {
@ -470,6 +523,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
@Override
public Intervals<TemporaryBasal> getTemporaryBasalsFromHistory() {
synchronized (tempBasals) {
@ -477,9 +531,10 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
@Override
public boolean addToHistoryTempBasal(TemporaryBasal tempBasal) {
//log.debug("Adding new TemporaryBasal record" + tempBasal.toString());
// log.debug("Adding new TemporaryBasal record" + tempBasal.toString());
boolean newRecordCreated = MainApp.getDbHelper().createOrUpdate(tempBasal);
if (newRecordCreated) {
if (tempBasal.durationInMinutes == 0)
@ -492,6 +547,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
return newRecordCreated;
}
// return true if new record is created
@Override
public boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo, boolean allowUpdate) {
@ -509,16 +565,20 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
treatment.boluscalc = detailedBolusInfo.boluscalc != null ? detailedBolusInfo.boluscalc.toString() : null;
TreatmentService.UpdateReturn creatOrUpdateResult = getService().createOrUpdate(treatment);
boolean newRecordCreated = creatOrUpdateResult.newRecord;
//log.debug("Adding new Treatment record" + treatment.toString());
// log.debug("Adding new Treatment record" + treatment.toString());
if (detailedBolusInfo.carbTime != 0) {
Treatment carbsTreatment = new Treatment();
carbsTreatment.source = detailedBolusInfo.source;
carbsTreatment.pumpId = detailedBolusInfo.pumpId; // but this should never happen
carbsTreatment.date = detailedBolusInfo.date + detailedBolusInfo.carbTime * 60 * 1000L + 1000L; // add 1 sec to make them different records
carbsTreatment.date = detailedBolusInfo.date + detailedBolusInfo.carbTime * 60 * 1000L + 1000L; // add 1 sec
// to make
// them
// different
// records
carbsTreatment.carbs = detailedBolusInfo.carbs;
carbsTreatment.source = detailedBolusInfo.source;
getService().createOrUpdate(carbsTreatment);
//log.debug("Adding new Treatment record" + carbsTreatment);
// log.debug("Adding new Treatment record" + carbsTreatment);
}
if (newRecordCreated && detailedBolusInfo.isValid)
NSUpload.uploadTreatmentRecord(detailedBolusInfo);
@ -526,7 +586,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
if (!allowUpdate && !creatOrUpdateResult.success) {
log.error("Treatment could not be added to DB", new Exception());
String status = String.format(MainApp.gs(R.string.error_adding_treatment_message), treatment.insulin, (int) treatment.carbs, DateUtil.dateAndTimeString(treatment.date));
String status = String.format(MainApp.gs(R.string.error_adding_treatment_message), treatment.insulin,
(int)treatment.carbs, DateUtil.dateAndTimeString(treatment.date));
Intent i = new Intent(MainApp.instance(), ErrorHelperActivity.class);
i.putExtra("soundid", R.raw.error);
@ -543,6 +604,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
return newRecordCreated;
}
@Override
public long oldestDataAvailable() {
long oldestTime = System.currentTimeMillis();
@ -562,6 +624,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
return oldestTime;
}
// TempTargets
@Subscribe
@SuppressWarnings("unused")
@ -569,6 +632,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
initializeTempTargetData();
}
@Nullable
@Override
public TempTarget getTempTargetFromHistory() {
@ -577,6 +641,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
@Nullable
@Override
public TempTarget getTempTargetFromHistory(long time) {
@ -585,6 +650,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
@Override
public Intervals<TempTarget> getTempTargetsFromHistory() {
synchronized (tempTargets) {
@ -592,13 +658,15 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
@Override
public void addToHistoryTempTarget(TempTarget tempTarget) {
//log.debug("Adding new TemporaryBasal record" + profileSwitch.log());
// log.debug("Adding new TemporaryBasal record" + profileSwitch.log());
MainApp.getDbHelper().createOrUpdate(tempTarget);
NSUpload.uploadTempTarget(tempTarget);
}
// Profile Switch
@Subscribe
@SuppressWarnings("unused")
@ -606,13 +674,15 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
initializeProfileSwitchData();
}
@Override
public ProfileSwitch getProfileSwitchFromHistory(long time) {
synchronized (profiles) {
return (ProfileSwitch) profiles.getValueToTime(time);
return (ProfileSwitch)profiles.getValueToTime(time);
}
}
@Override
public ProfileIntervals<ProfileSwitch> getProfileSwitchesFromHistory() {
synchronized (profiles) {
@ -620,13 +690,13 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
}
}
@Override
public void addToHistoryProfileSwitch(ProfileSwitch profileSwitch) {
//log.debug("Adding new TemporaryBasal record" + profileSwitch.log());
// log.debug("Adding new TemporaryBasal record" + profileSwitch.log());
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_SWITCH_MISSING));
MainApp.getDbHelper().createOrUpdate(profileSwitch);
NSUpload.uploadProfileSwitch(profileSwitch);
}
}

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2015 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string-array name="android_wear_capabilities">
<item>phone_app_sync_bgs</item>
</string-array>
</resources>

View file

@ -0,0 +1,59 @@
package android.util;
import java.time.LocalDateTime;
/**
* Created by andy on 3/10/19.
*/
public class Log {
// 03-10 13:44:42.847 12790-12888/info.nightscout.androidaps D/MedtronicHistoryData:
static boolean isLoggingEnabled = false;
public static void setLoggingEnabled(boolean enabled) {
isLoggingEnabled = enabled;
}
private void writeLog(String type, String tag, String message) {
if (isLoggingEnabled) {
LocalDateTime ldt = LocalDateTime.now();
System.out.println("DEBUG: " + tag + ": " + message);
}
}
public static int d(String tag, String msg) {
System.out.println("DEBUG: " + tag + ": " + msg);
return 0;
}
public static int v(String tag, String msg) {
System.out.println("VERBOSE: " + tag + ": " + msg);
return 0;
}
public static int i(String tag, String msg) {
System.out.println("INFO: " + tag + ": " + msg);
return 0;
}
public static int w(String tag, String msg) {
System.out.println("WARN: " + tag + ": " + msg);
return 0;
}
public static int e(String tag, String msg) {
System.out.println("ERROR: " + tag + ": " + msg);
return 0;
}
// add other methods if required...
}

View file

@ -0,0 +1,75 @@
package info.nightscout.androidaps.plugins.pump.medtronic.comm;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import uk.org.lidalia.slf4jtest.TestLogger;
import uk.org.lidalia.slf4jtest.TestLoggerFactory;
import android.util.Log;
import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RawHistoryPage;
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.MedtronicPumpHistoryDecoder;
import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry;
/**
* Created by andy on 3/10/19.
*/
public class MedtronicHistoryDataUTest {
TestLogger LOGGER = TestLoggerFactory.getTestLogger(MedtronicHistoryDataUTest.class);
byte[] historyPageData = ByteUtil
.createByteArrayFromString("16 00 12 EC 14 47 13 33 00 14 F2 14 47 13 00 16 01 14 F2 14 47 13 33 00 1C C9 15 47 13 00 16 00 1C C9 15 47 13 33 4E 31 D3 15 47 13 00 16 01 31 D3 15 47 13 33 00 1A F1 15 47 13 00 16 00 1A F1 15 47 13 33 50 1D F1 15 47 13 00 16 01 1D F1 15 47 13 33 50 11 D8 16 47 13 00 16 01 11 D8 16 47 13 33 50 31 FB 16 47 13 00 16 01 31 FB 16 47 13 33 50 12 E3 17 47 13 00 16 01 12 E3 17 47 13 33 00 1E FB 17 47 13 00 16 00 1E FB 17 47 13 33 D8 21 FB 17 47 13 00 16 01 21 FB 17 47 13 07 00 00 05 CC 27 93 6D 27 93 05 0C 00 E8 00 00 00 00 05 CC 05 CC 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0C 00 E8 00 00 00 33 00 36 C4 00 48 13 00 16 00 36 C4 00 48 13 33 D8 29 C9 00 48 13 00 16 01 29 C9 00 48 13 33 00 12 E7 00 48 13 00 16 00 12 E7 00 48 13 33 BC 19 C9 01 48 13 00 16 01 19 C9 01 48 13 33 00 26 CE 01 48 13 00 16 00 26 CE 01 48 13 33 44 29 CE 01 48 13 00 16 01 29 CE 01 48 13 33 00 13 D3 01 48 13 00 16 00 13 D3 01 48 13 33 64 31 F1 01 48 13 00 16 01 31 F1 01 48 13 33 00 0B F7 01 48 13 00 16 00 0B F7 01 48 13 33 00 12 D8 02 48 13 00 16 01 12 D8 02 48 13 33 00 10 F1 02 48 13 00 16 00 10 F1 02 48 13 33 00 30 C4 03 48 13 00 16 01 30 C4 03 48 13 33 00 04 CA 03 48 13 00 16 00 04 CA 03 48 13 33 00 2F D3 03 48 13 00 16 01 2F D3 03 48 13 33 00 30 D8 03 48 13 00 16 00 30 D8 03 48 13 33 00 13 E7 03 48 13 00 16 01 13 E7 03 48 13 33 00 2E FB 03 48 13 00 16 00 2E FB 03 48 13 19 00 00 C1 04 08 13 07 00 00 04 0C 28 93 6D 28 93 05 0C 00 E8 00 00 00 00 04 0C 04 0C 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0C 00 E8 00 00 00 06 3E 03 7A 19 DC 48 49 13 0C 3E 0C E6 08 09 13 07 00 00 01 E4 29 93 6D 29 93 05 0C 00 E8 00 00 00 00 01 E4 01 E4 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0C 00 E8 00 00 00 1A 00 13 D2 0D 0A 13 1A 01 28 D2 0D 0A 13 21 00 2A D8 0D 0A 13 03 00 00 00 0E 2D D9 2D 0A 13 33 98 26 DE 0D 4A 13 00 16 01 26 DE 0D 4A 13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5D 70");
MedtronicPumpHistoryDecoder decoder = new MedtronicPumpHistoryDecoder();
// Logger LOGGER = LoggerFactory.getLogger(MedtronicHistoryDataUTest.class);
@Before
public void setup() {
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "trace");
// final TestAppender appender = new TestAppender();
// final Logger logger = Logger.getRootLogger();
// logger.addAppender(appender);
// try {
// Logger.getLogger(MyTest.class).info("Test");
// } finally {
// logger.removeAppender(appender);
// }
}
@Test
public void testTBR() throws Exception {
RawHistoryPage historyPage = new RawHistoryPage();
historyPage.appendData(historyPageData);
List<PumpHistoryEntry> pumpHistoryEntries = decoder.processPageAndCreateRecords(historyPage,
PumpHistoryEntry.class);
System.out.println("PumpHistoryEntries: " + pumpHistoryEntries.size());
Log.d("Test", "Log.d");
LOGGER.debug("Logger.debug");
for (PumpHistoryEntry pumpHistoryEntry : pumpHistoryEntries) {
Log.d("MedtronicHistoryDataUTest", pumpHistoryEntry.toString());
}
}
public void testBolus() throws Exception {
}
}

View file

@ -1,7 +1,6 @@
package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump;
import org.junit.Before;
import org.junit.Test;
import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil;
@ -90,7 +89,7 @@ public class MedtronicPumpHistoryDecoderUTest {
}
@Test
// @Test
public void decodeDailyTotals515() {
byte[] data = ByteUtil
@ -111,7 +110,7 @@ public class MedtronicPumpHistoryDecoderUTest {
}
@Test
// @Test
public void decodeDailyTotals523() {
byte[] data = new byte[] {

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.plugins.pump.medtronic.data.dto;
import static org.mockito.Mockito.when;
import junit.framework.Assert;
import org.junit.Before;
@ -14,12 +16,12 @@ import info.SPMocker;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.plugins.PumpCommon.defs.PumpType;
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType;
import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus;
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.SP;
import info.nightscout.utils.T;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
/**
* Created by andy on 6/16/18.

View file

@ -0,0 +1,62 @@
package info.nightscout.androidaps.utils;
/**
* Created by andy on 3/10/19.
*/
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
//import ch.qos.logback.core.read.ListAppender;
public class LoggerRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
return null;
}
/*
* private final ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
* private final Logger logger = (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
*
*
* @Override
* public Statement apply(Statement base, Description description) {
* return new Statement() {
*
* @Override
* public void evaluate() throws Throwable {
* setup();
* base.evaluate();
* teardown();
* }
* };
* }
*
*
* private void setup() {
* logger.addAppender(listAppender);
* listAppender.start();
* }
*
*
* private void teardown() {
* listAppender.stop();
* listAppender.list.clear();
* logger.detachAppender(listAppender);
* }
*
*
* public List<String> getMessages() {
* return listAppender.list.stream().map(e -> e.getMessage()).collect(Collectors.toList());
* }
*
*
* public List<String> getFormattedMessages() {
* return listAppender.list.stream().map(e -> e.getFormattedMessage()).collect(Collectors.toList());
* }
*/
}

View file

@ -2,6 +2,7 @@ apply plugin: 'com.android.application'
ext {
wearableVersion = "2.0.1"
playServicesWearable = "10.2.1"
}
def generateGitBuild = { ->
@ -89,8 +90,8 @@ dependencies {
//compile "com.ustwo.android:clockwise-wearable:1.0.2"
compileOnly "com.google.android.wearable:wearable:${wearableVersion}"
implementation "com.google.android.support:wearable:${wearableVersion}"
implementation "com.google.android.gms:play-services-wearable:7.3.0"
implementation(name:"ustwo-clockwise-debug", ext:"aar")
implementation "com.google.android.gms:play-services-wearable:${playServicesWearable}"
implementation(name: "ustwo-clockwise-debug", ext: "aar")
implementation "com.android.support:support-v4:27.0.1"
implementation 'com.android.support:wear:27.0.1'
implementation "me.denley.wearpreferenceactivity:wearpreferenceactivity:0.5.0"

View file

@ -6,7 +6,7 @@
<uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.VIBRATE" />
<application
@ -168,9 +168,66 @@
<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
</intent-filter>
</service>
<service android:name=".data.ListenerService">
<intent-filter>
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
<!-- <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> -->
<!-- listeners receive events that match the action and data filters -->
<action android:name="com.google.android.gms.wearable.CAPABILITY_CHANGED" />
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_data" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_data_resend" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_cancel_bolus" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_confirmactionstring" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_initiateactionstring" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/openwearsettings" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/sendstatustowear" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/sendpreferencestowear" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_basal" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_bolusprogress" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_actionconfirmationrequest" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_changeconfirmationrequest" />
<data
android:scheme="wear"
android:host="*"
android:pathPrefix="/nightscout_watch_cancelnotificationrequest" />
</intent-filter>
</service>

View file

@ -1,5 +1,8 @@
package info.nightscout.androidaps.data;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@ -10,13 +13,18 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.wearable.CapabilityApi;
import com.google.android.gms.wearable.CapabilityInfo;
import com.google.android.gms.wearable.ChannelApi;
import com.google.android.gms.wearable.DataEvent;
import com.google.android.gms.wearable.DataEventBuffer;
import com.google.android.gms.wearable.DataMap;
@ -26,19 +34,18 @@ import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;
import com.google.android.gms.wearable.WearableListenerService;
import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.interaction.AAPSPreferences;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interaction.AAPSPreferences;
import info.nightscout.androidaps.interaction.actions.AcceptActivity;
import info.nightscout.androidaps.interaction.actions.CPPActivity;
import info.nightscout.androidaps.interaction.utils.SafeParse;
import info.nightscout.androidaps.interaction.utils.WearUtil;
/**
* Created by emmablack on 12/26/14.
*/
public class ListenerService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
public class ListenerService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ChannelApi.ChannelListener {
private static final String WEARABLE_DATA_PATH = "/nightscout_watch_data";
private static final String WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend";
private static final String WEARABLE_CANCELBOLUS_PATH = "/nightscout_watch_cancel_bolus";
@ -54,7 +61,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
public static final String NEW_CHANGECONFIRMATIONREQUEST_PATH = "/nightscout_watch_changeconfirmationrequest";
public static final String ACTION_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest";
public static final int BOLUS_PROGRESS_NOTIF_ID = 001;
public static final int CONFIRM_NOTIF_ID = 002;
public static final int CHANGE_NOTIF_ID = 556677;
@ -65,63 +71,181 @@ public class ListenerService extends WearableListenerService implements GoogleAp
private static final String ACTION_CONFIRMCHANGE = "com.dexdrip.stephenblack.nightwatch.CONFIRMCHANGE";
private static final String ACTION_INITIATE_ACTION = "com.dexdrip.stephenblack.nightwatch.INITIATE_ACTION";
private static final String ACTION_RESEND_BULK = "com.dexdrip.stephenblack.nightwatch.RESEND_BULK_DATA";
GoogleApiClient googleApiClient;
private long lastRequest = 0;
private DismissThread confirmThread;
private DismissThread bolusprogressThread;
private static final String TAG = "ListenerService";
private DataRequester mDataRequester = null;
private static final int GET_CAPABILITIES_TIMEOUT_MS = 5000;
// Phone
private static final String CAPABILITY_PHONE_APP = "phone_app_sync_bgs";
private static final String MESSAGE_PATH_PHONE = "/phone_message_path";
// Wear
private static final String CAPABILITY_WEAR_APP = "wear_app_sync_bgs";
private static final String MESSAGE_PATH_WEAR = "/wear_message_path";
private String mPhoneNodeId = null;
private String localnode = null;
private String logPrefix = ""; // "WR: "
public class DataRequester extends AsyncTask<Void, Void, Void> {
Context mContext;
DataRequester(Context context) {
mContext = context;
Context mContext;
String path;
byte[] payload;
DataRequester(Context context, String thispath, byte[] thispayload) {
path = thispath;
payload = thispayload;
// Log.d(TAG, logPrefix + "DataRequester DataRequester: " + thispath + " lastRequest:" + lastRequest);
}
@Override
protected Void doInBackground(Void... params) {
if (googleApiClient.isConnected()) {
if (System.currentTimeMillis() - lastRequest > 20 * 1000) { // enforce 20-second debounce period
lastRequest = System.currentTimeMillis();
// Log.d(TAG, logPrefix + "DataRequester: doInBack: " + params);
NodeApi.GetConnectedNodesResult nodes =
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
for (Node node : nodes.getNodes()) {
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_RESEND_PATH, null);
}
try {
forceGoogleApiConnect();
DataMap datamap;
if (isCancelled()) {
Log.d(TAG, "doInBackground CANCELLED programmatically");
return null;
}
} else {
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
if (googleApiClient.isConnected()) {
if (System.currentTimeMillis() - lastRequest > 20 * 1000) { // enforce 20-second debounce period
if (googleApiClient != null) {
if (!googleApiClient.isConnected())
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
}
// this code might not be needed in this way, but we need to see that later
if ((googleApiClient != null) && (googleApiClient.isConnected())) {
if ((System.currentTimeMillis() - lastRequest > 20 * 1000)) {
// enforce 20-second debounce period
lastRequest = System.currentTimeMillis();
NodeApi.GetConnectedNodesResult nodes =
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
for (Node node : nodes.getNodes()) {
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_RESEND_PATH, null);
// NodeApi.GetConnectedNodesResult nodes =
// Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
if (localnode == null || (localnode != null && localnode.isEmpty()))
setLocalNodeName();
CapabilityInfo capabilityInfo = getCapabilities();
int count = 0;
Node phoneNode = null;
if (capabilityInfo != null) {
phoneNode = updatePhoneSyncBgsCapability(capabilityInfo);
count = capabilityInfo.getNodes().size();
}
Log.d(TAG, "doInBackground connected. CapabilityApi.GetCapabilityResult mPhoneNodeID="
+ (phoneNode != null ? phoneNode.getId() : "") + " count=" + count + " localnode="
+ localnode);// KS
if (count > 0) {
for (Node node : capabilityInfo.getNodes()) {
// Log.d(TAG, "doInBackground path: " + path);
switch (path) {
// simple send as is payloads
case WEARABLE_RESEND_PATH:
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(),
WEARABLE_RESEND_PATH, null);
break;
case WEARABLE_DATA_PATH:
case WEARABLE_CANCELBOLUS_PATH:
case WEARABLE_CONFIRM_ACTIONSTRING_PATH:
case WEARABLE_INITIATE_ACTIONSTRING_PATH:
case OPEN_SETTINGS:
case NEW_STATUS_PATH:
case NEW_PREFERENCES_PATH:
case BASAL_DATA_PATH:
case BOLUS_PROGRESS_PATH:
case ACTION_CONFIRMATION_REQUEST_PATH:
case NEW_CHANGECONFIRMATIONREQUEST_PATH:
case ACTION_CANCELNOTIFICATION_REQUEST_PATH: {
Log.w(TAG, logPrefix + "Unhandled path");
// sendMessagePayload(node, path, path, payload);
}
default:// SYNC_ALL_DATA
// this fall through is messy and non-deterministic for new paths
}
}
} else {
Log.d(TAG, logPrefix + "doInBackground connected but getConnectedNodes returns 0.");
}
} else {
// no resend
Log.d(TAG, logPrefix + "Inside the timeout, will not be executed");
}
} else {
Log.d(TAG, logPrefix + "Not connected for sending: api "
+ ((googleApiClient == null) ? "is NULL!" : "not null"));
if (googleApiClient != null) {
googleApiClient.connect();
} else {
googleApiConnect();
}
}
} catch (Exception ex) {
Log.e(TAG, logPrefix + "Error executing DataRequester in background. Exception: " + ex.getMessage());
}
return null;
}
}
public CapabilityInfo getCapabilities() {
CapabilityApi.GetCapabilityResult capabilityResult = Wearable.CapabilityApi.getCapability(googleApiClient,
CAPABILITY_PHONE_APP, CapabilityApi.FILTER_REACHABLE).await(GET_CAPABILITIES_TIMEOUT_MS,
TimeUnit.MILLISECONDS);
if (!capabilityResult.getStatus().isSuccess()) {
Log.e(TAG, logPrefix + "doInBackground Failed to get capabilities, status: "
+ capabilityResult.getStatus().getStatusMessage());
return null;
}
return capabilityResult.getCapability();
}
public class BolusCancelTask extends AsyncTask<Void, Void, Void> {
Context mContext;
BolusCancelTask(Context context) {
mContext = context;
}
@Override
protected Void doInBackground(Void... params) {
// Log.d(TAG, logPrefix + "BolusCancelTask: doInBack: " + params);
if (googleApiClient.isConnected()) {
NodeApi.GetConnectedNodesResult nodes =
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
for (Node node : nodes.getNodes()) {
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_CANCELBOLUS_PATH, null);
}
@ -129,8 +253,7 @@ public class ListenerService extends WearableListenerService implements GoogleAp
} else {
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
if (googleApiClient.isConnected()) {
NodeApi.GetConnectedNodesResult nodes =
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
for (Node node : nodes.getNodes()) {
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_CANCELBOLUS_PATH, null);
}
@ -142,32 +265,40 @@ public class ListenerService extends WearableListenerService implements GoogleAp
}
public class MessageActionTask extends AsyncTask<Void, Void, Void> {
Context mContext;
String mActionstring;
String mMessagePath;
MessageActionTask(Context context, String messagePath, String actionstring) {
mContext = context;
mActionstring = actionstring;
mMessagePath = messagePath;
}
@Override
protected Void doInBackground(Void... params) {
// Log.d(TAG, logPrefix + "MessageActionTask: doInBack: " + params);
forceGoogleApiConnect();
if (googleApiClient.isConnected()) {
NodeApi.GetConnectedNodesResult nodes =
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
for (Node node : nodes.getNodes()) {
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), mMessagePath, mActionstring.getBytes());
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), mMessagePath,
mActionstring.getBytes());
}
} else {
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
if (googleApiClient.isConnected()) {
NodeApi.GetConnectedNodesResult nodes =
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
for (Node node : nodes.getNodes()) {
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), mMessagePath, mActionstring.getBytes());
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), mMessagePath,
mActionstring.getBytes());
}
}
}
@ -175,72 +306,153 @@ public class ListenerService extends WearableListenerService implements GoogleAp
}
}
public void requestData() {
new DataRequester(this).execute();
sendData(WEARABLE_RESEND_PATH, null);
}
public void cancelBolus() {
new BolusCancelTask(this).execute();
}
private void sendConfirmActionstring(String actionstring) {
new MessageActionTask(this, WEARABLE_CONFIRM_ACTIONSTRING_PATH, actionstring).execute();
}
private void sendInitiateActionstring(String actionstring) {
new MessageActionTask(this, WEARABLE_INITIATE_ACTIONSTRING_PATH, actionstring).execute();
}
public void googleApiConnect() {
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Wearable.API)
.build();
private Node updatePhoneSyncBgsCapability(CapabilityInfo capabilityInfo) {
// Log.d(TAG, "CapabilityInfo: " + capabilityInfo);
Set<Node> connectedNodes = capabilityInfo.getNodes();
return pickBestNode(connectedNodes);
// mPhoneNodeId = pickBestNodeId(connectedNodes);
}
private Node pickBestNode(Set<Node> nodes) {
Node bestNode = null;
// Find a nearby node or pick one arbitrarily
for (Node node : nodes) {
if (node.isNearby()) {
return node;
}
bestNode = node;
}
return bestNode;
}
private synchronized void sendData(String path, byte[] payload) {
// Log.d(TAG, "WR: sendData: path: " + path + ", payload=" + payload);
if (path == null)
return;
if (mDataRequester != null) {
// Log.d(TAG, logPrefix + "sendData DataRequester != null lastRequest:" +
// WearUtil.dateTimeText(lastRequest));
if (mDataRequester.getStatus() != AsyncTask.Status.FINISHED) {
// Log.d(TAG, logPrefix + "sendData Should be canceled? Let run 'til finished.");
// mDataRequester.cancel(true);
}
// mDataRequester = null;
}
Log.d(TAG, logPrefix + "sendData: execute lastRequest:" + WearUtil.dateTimeText(lastRequest));
mDataRequester = (DataRequester)new DataRequester(this, path, payload).execute();
// executeTask(mDataRequester);
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
// Log.d(TAG, "sendData SDK < M call execute lastRequest:" + WearUtil.dateTimeText(lastRequest));
// mDataRequester = (DataRequester) new DataRequester(this, path, payload).execute();
// } else {
// Log.d(TAG, "sendData SDK >= M call executeOnExecutor lastRequest:" + WearUtil.dateTimeText(lastRequest));
// // TODO xdrip executor
// mDataRequester = (DataRequester) new DataRequester(this, path, payload).executeOnExecutor(xdrip.executor);
// }
}
private void googleApiConnect() {
if (googleApiClient != null) {
// Remove old listener(s)
try {
Wearable.ChannelApi.removeListener(googleApiClient, this);
} catch (Exception e) {
//
}
try {
Wearable.MessageApi.removeListener(googleApiClient, this);
} catch (Exception e) {
//
}
}
googleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).addApi(Wearable.API).build();
Wearable.MessageApi.addListener(googleApiClient, this);
}
private void forceGoogleApiConnect() {
if ((googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting())
|| googleApiClient == null) {
try {
Log.d(TAG, "forceGoogleApiConnect: forcing google api reconnection");
googleApiConnect();
Thread.sleep(2000);
} catch (InterruptedException e) {
//
}
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Log.d(TAG, logPrefix + "onStartCommand: Intent: " + intent);
if (intent != null && ACTION_RESEND.equals(intent.getAction())) {
googleApiConnect();
requestData();
} else if(intent != null && ACTION_CANCELBOLUS.equals(intent.getAction())){
} else if (intent != null && ACTION_CANCELBOLUS.equals(intent.getAction())) {
googleApiConnect();
//dismiss notification
NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(ListenerService.this);
// dismiss notification
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(ListenerService.this);
notificationManager.cancel(BOLUS_PROGRESS_NOTIF_ID);
//send cancel-request to phone.
// send cancel-request to phone.
cancelBolus();
} else if(intent != null && ACTION_CONFIRMATION.equals(intent.getAction())){
} else if (intent != null && ACTION_CONFIRMATION.equals(intent.getAction())) {
googleApiConnect();
//dismiss notification
NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(ListenerService.this);
// dismiss notification
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(ListenerService.this);
notificationManager.cancel(CONFIRM_NOTIF_ID);
String actionstring = intent.getStringExtra("actionstring");
sendConfirmActionstring(actionstring);
} else if(intent != null && ACTION_CONFIRMCHANGE.equals(intent.getAction())){
} else if (intent != null && ACTION_CONFIRMCHANGE.equals(intent.getAction())) {
googleApiConnect();
//dismiss notification
NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(ListenerService.this);
// dismiss notification
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(ListenerService.this);
notificationManager.cancel(CHANGE_NOTIF_ID);
String actionstring = intent.getStringExtra("actionstring");
sendConfirmActionstring(actionstring);
} else if(intent != null && ACTION_INITIATE_ACTION.equals(intent.getAction())){
} else if (intent != null && ACTION_INITIATE_ACTION.equals(intent.getAction())) {
googleApiConnect();
String actionstring = intent.getStringExtra("actionstring");
@ -256,31 +468,37 @@ public class ListenerService extends WearableListenerService implements GoogleAp
public void onDataChanged(DataEventBuffer dataEvents) {
DataMap dataMap;
// Log.d(TAG, logPrefix + "onDataChanged: DataEvents=" + dataEvents);
for (DataEvent event : dataEvents) {
if (event.getType() == DataEvent.TYPE_CHANGED) {
String path = event.getDataItem().getUri().getPath();
Log.d(TAG, "WR: onDataChanged: Path: " + path + ", EventDataItem=" + event.getDataItem());
if (path.equals(OPEN_SETTINGS)) {
Intent intent = new Intent(this, AAPSPreferences.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else if (path.equals(BOLUS_PROGRESS_PATH)) {
int progress = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getInt("progresspercent", 0);
String status = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("progressstatus", "");
int progress = DataMapItem.fromDataItem(event.getDataItem()).getDataMap()
.getInt("progresspercent", 0);
String status = DataMapItem.fromDataItem(event.getDataItem()).getDataMap()
.getString("progressstatus", "");
showBolusProgress(progress, status);
} else if (path.equals(ACTION_CONFIRMATION_REQUEST_PATH)) {
String title = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("title");
String message = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("message");
String actionstring = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("actionstring");
String actionstring = DataMapItem.fromDataItem(event.getDataItem()).getDataMap()
.getString("actionstring");
if("opencpp".equals(title) && actionstring.startsWith("opencpp")){
if ("opencpp".equals(title) && actionstring.startsWith("opencpp")) {
String[] act = actionstring.split("\\s+");
Intent intent = new Intent(this, CPPActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//TODO adrian: parse actionstring and add parameters
// TODO adrian: parse actionstring and add parameters
Bundle params = new Bundle();
params.putInt("percentage", SafeParse.stringToInt(act[1]));
params.putInt("timeshift", SafeParse.stringToInt(act[2]));
@ -296,15 +514,15 @@ public class ListenerService extends WearableListenerService implements GoogleAp
messageIntent.setAction(Intent.ACTION_SEND);
messageIntent.putExtra("status", dataMap.toBundle());
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
} else if (path.equals(BASAL_DATA_PATH)){
} else if (path.equals(BASAL_DATA_PATH)) {
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
Intent messageIntent = new Intent();
messageIntent.setAction(Intent.ACTION_SEND);
messageIntent.putExtra("basals", dataMap.toBundle());
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
} else if (path.equals(NEW_PREFERENCES_PATH)){
} else if (path.equals(NEW_PREFERENCES_PATH)) {
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
if(dataMap.containsKey("wearcontrol")) {
if (dataMap.containsKey("wearcontrol")) {
boolean wearcontrol = dataMap.getBoolean("wearcontrol", false);
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = sharedPreferences.edit();
@ -314,10 +532,12 @@ public class ListenerService extends WearableListenerService implements GoogleAp
} else if (path.equals(NEW_CHANGECONFIRMATIONREQUEST_PATH)) {
String title = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("title");
String message = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("message");
String actionstring = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("actionstring");
String actionstring = DataMapItem.fromDataItem(event.getDataItem()).getDataMap()
.getString("actionstring");
notifyChangeRequest(title, message, actionstring);
} else if (path.equals(ACTION_CANCELNOTIFICATION_REQUEST_PATH)) {
String actionstring = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("actionstring");
String actionstring = DataMapItem.fromDataItem(event.getDataItem()).getDataMap()
.getString("actionstring");
cancelNotificationRequest(actionstring);
} else {
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
@ -330,14 +550,12 @@ public class ListenerService extends WearableListenerService implements GoogleAp
}
}
private void notifyChangeRequest(String title, String message, String actionstring) {
Notification.Builder builder =
new Notification.Builder(this); //,"AndroidAPS-Openloop");
builder.setSmallIcon(R.drawable.notif_icon)
.setContentTitle(title)
.setContentText(message)
.setPriority(Notification.PRIORITY_HIGH);
Notification.Builder builder = new Notification.Builder(this); // ,"AndroidAPS-Openloop");
builder.setSmallIcon(R.drawable.notif_icon).setContentTitle(title).setContentText(message)
.setPriority(Notification.PRIORITY_HIGH);
// Creates an explicit intent for an Activity in your app
Intent intent = new Intent(this, AcceptActivity.class);
@ -348,62 +566,56 @@ public class ListenerService extends WearableListenerService implements GoogleAp
params.putString("actionstring", actionstring);
intent.putExtras(params);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultPendingIntent);
builder.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000});
builder.setVibrate(new long[] { 1000, 1000, 1000, 1000, 1000 });
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationManager mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(CHANGE_NOTIF_ID, builder.build());
}
private void cancelNotificationRequest(String actionstring) {
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationManager mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
mNotificationManager.cancel(CHANGE_NOTIF_ID);
}
private void showBolusProgress(int progresspercent, String progresstatus) {
Intent cancelIntent = new Intent(this, ListenerService.class);
cancelIntent.setAction(ACTION_CANCELBOLUS);
PendingIntent cancelPendingIntent = PendingIntent.getService(this, 0, cancelIntent, 0);;
long[] vibratePattern;
boolean vibreate = PreferenceManager
.getDefaultSharedPreferences(this).getBoolean("vibrateOnBolus", true);
if(vibreate){
vibratePattern = new long[]{0, 50, 1000};
boolean vibreate = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("vibrateOnBolus", true);
if (vibreate) {
vibratePattern = new long[] { 0, 50, 1000 };
} else {
vibratePattern = new long[]{0, 1, 1000};
vibratePattern = new long[] { 0, 1, 1000 };
}
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_icon)
.setContentTitle("Bolus Progress")
.setContentText(progresspercent + "% - " + progresstatus)
.setContentIntent(cancelPendingIntent)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setVibrate(vibratePattern)
.addAction(R.drawable.ic_cancel, "CANCEL BOLUS", cancelPendingIntent);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_icon).setContentTitle("Bolus Progress")
.setContentText(progresspercent + "% - " + progresstatus).setContentIntent(cancelPendingIntent)
.setPriority(NotificationCompat.PRIORITY_MAX).setVibrate(vibratePattern)
.addAction(R.drawable.ic_cancel, "CANCEL BOLUS", cancelPendingIntent);
NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(this);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
if(confirmThread != null){
if (confirmThread != null) {
confirmThread.invalidate();
}
notificationManager.notify(BOLUS_PROGRESS_NOTIF_ID, notificationBuilder.build());
notificationManager.cancel(CONFIRM_NOTIF_ID); // multiple watch setup
if (progresspercent == 100){
if (progresspercent == 100) {
scheduleDismissBolusprogress(5);
}
}
private void showConfirmationDialog(String title, String message, String actionstring) {
Intent intent = new Intent(this, AcceptActivity.class);
@ -416,49 +628,54 @@ public class ListenerService extends WearableListenerService implements GoogleAp
startActivity(intent);
}
private void scheduleDismissBolusprogress(final int seconds) {
if(confirmThread != null){
if (confirmThread != null) {
confirmThread.invalidate();
}
bolusprogressThread = new DismissThread(BOLUS_PROGRESS_NOTIF_ID, seconds);
bolusprogressThread.start();
}
private class DismissThread extends Thread {
private class DismissThread extends Thread{
private final int notificationID;
private final int seconds;
private boolean valid = true;
DismissThread(int notificationID, int seconds){
DismissThread(int notificationID, int seconds) {
this.notificationID = notificationID;
this.seconds = seconds;
}
public synchronized void invalidate(){
public synchronized void invalidate() {
valid = false;
}
@Override
public void run() {
SystemClock.sleep(seconds * 1000);
synchronized (this) {
if(valid) {
NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(ListenerService.this);
if (valid) {
NotificationManagerCompat notificationManager = NotificationManagerCompat
.from(ListenerService.this);
notificationManager.cancel(notificationID);
}
}
}
}
public static void requestData(Context context) {
Intent intent = new Intent(context, ListenerService.class);
intent.setAction(ACTION_RESEND);
context.startService(intent);
}
public static void initiateAction(Context context, String actionstring) {
Intent intent = new Intent(context, ListenerService.class);
intent.putExtra("actionstring", actionstring);
@ -466,6 +683,7 @@ public class ListenerService extends WearableListenerService implements GoogleAp
context.startService(intent);
}
public static void confirmAction(Context context, String actionstring) {
Intent intent = new Intent(context, ListenerService.class);
intent.putExtra("actionstring", actionstring);
@ -478,29 +696,71 @@ public class ListenerService extends WearableListenerService implements GoogleAp
context.startService(intent);
}
@Override
public void onConnected(Bundle bundle) {
// Log.d(TAG, logPrefix + "onConnected call requestData");
CapabilityApi.CapabilityListener capabilityListener = new CapabilityApi.CapabilityListener() {
@Override
public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
updatePhoneSyncBgsCapability(capabilityInfo);
Log.d(TAG, logPrefix + "onConnected onCapabilityChanged mPhoneNodeID:" + mPhoneNodeId
+ ", Capability: " + capabilityInfo);
}
};
Wearable.CapabilityApi.addCapabilityListener(googleApiClient, capabilityListener, CAPABILITY_PHONE_APP);
Wearable.ChannelApi.addListener(googleApiClient, this);
requestData();
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
private void setLocalNodeName() {
forceGoogleApiConnect();
PendingResult<NodeApi.GetLocalNodeResult> result = Wearable.NodeApi.getLocalNode(googleApiClient);
result.setResultCallback(new ResultCallback<NodeApi.GetLocalNodeResult>() {
@Override
public void onResult(NodeApi.GetLocalNodeResult getLocalNodeResult) {
if (!getLocalNodeResult.getStatus().isSuccess()) {
Log.e(TAG, "ERROR: failed to getLocalNode Status="
+ getLocalNodeResult.getStatus().getStatusMessage());
} else {
Log.d(TAG, "getLocalNode Status=: " + getLocalNodeResult.getStatus().getStatusMessage());
Node getnode = getLocalNodeResult.getNode();
localnode = getnode != null ? getnode.getDisplayName() + "|" + getnode.getId() : "";
Log.d(TAG, "setLocalNodeName. localnode=" + localnode);
}
}
});
}
@Override
public void onDestroy() {
super.onDestroy();
if (googleApiClient != null && googleApiClient.isConnected()) {
googleApiClient.disconnect();
}
if (googleApiClient != null) {
Wearable.MessageApi.removeListener(googleApiClient, this);
Wearable.ChannelApi.removeListener(googleApiClient, this);
}
}
}

View file

@ -0,0 +1,17 @@
package info.nightscout.androidaps.interaction.utils;
import java.util.Date;
/**
* Created by andy on 3/5/19.
*/
public class WearUtil {
public static String dateTimeText(long timeInMs) {
Date d = new Date(timeInMs);
return "" + d.getDay() + "." + d.getMonth() + "." + d.getYear() + " " + d.getHours() + ":" + d.getMinutes()
+ ":" + d.getSeconds();
}
}

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2015 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string-array name="android_wear_capabilities">
<item>phone_app_sync_bgs</item>
</string-array>
</resources>