Careportal -> Room

This commit is contained in:
Milos Kozak 2021-03-08 20:10:02 +01:00
parent cb29e7a33c
commit 8db8edc3f6
64 changed files with 1169 additions and 1246 deletions

View file

@ -2,22 +2,6 @@
<code_scheme name="Project" version="173"> <code_scheme name="Project" version="173">
<option name="AUTODETECT_INDENTS" value="false" /> <option name="AUTODETECT_INDENTS" value="false" />
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="java.util" alias="false" withSubpackages="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
<package name="io.ktor" alias="false" withSubpackages="true" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" /> <option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="6" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="6" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="6" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="6" />

View file

@ -111,7 +111,7 @@ android {
defaultConfig { defaultConfig {
multiDexEnabled true multiDexEnabled true
versionCode 1500 versionCode 1500
version "2.8.2.1-dev-c" version "2.8.2.1-dev-d"
buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"' buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'

View file

@ -3,9 +3,10 @@ package info.nightscout.androidaps.db
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.interfaces.TraceableDBEntry import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.events.EventNewBG import info.nightscout.androidaps.events.EventNewBG
import info.nightscout.androidaps.events.EventTempTargetChange import info.nightscout.androidaps.events.EventTempTargetChange
import info.nightscout.androidaps.events.EventTherapyEventChange
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
@ -39,5 +40,9 @@ class CompatDBHelper @Inject constructor(
aapsLogger.debug(LTag.DATABASE, "Firing EventTempTargetChange") aapsLogger.debug(LTag.DATABASE, "Firing EventTempTargetChange")
rxBus.send(EventTempTargetChange()) rxBus.send(EventTempTargetChange())
} }
it.filterIsInstance<TherapyEvent>().firstOrNull()?.let {
aapsLogger.debug(LTag.DATABASE, "Firing EventTherapyEventChange")
rxBus.send(EventTherapyEventChange())
}
} }
} }

View file

@ -33,9 +33,7 @@ import java.util.concurrent.TimeUnit;
import javax.inject.Inject; import javax.inject.Inject;
import info.nightscout.androidaps.dana.comm.RecordTypes; import info.nightscout.androidaps.dana.comm.RecordTypes;
import info.nightscout.androidaps.data.NonOverlappingIntervals;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventCareportalEventChange;
import info.nightscout.androidaps.events.EventExtendedBolusChange; import info.nightscout.androidaps.events.EventExtendedBolusChange;
import info.nightscout.androidaps.events.EventProfileNeedsUpdate; import info.nightscout.androidaps.events.EventProfileNeedsUpdate;
import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.events.EventRefreshOverview;
@ -74,7 +72,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public static final String DATABASE_EXTENDEDBOLUSES = "ExtendedBoluses"; public static final String DATABASE_EXTENDEDBOLUSES = "ExtendedBoluses";
public static final String DATABASE_DANARHISTORY = "DanaRHistory"; public static final String DATABASE_DANARHISTORY = "DanaRHistory";
public static final String DATABASE_DBREQUESTS = "DBRequests"; public static final String DATABASE_DBREQUESTS = "DBRequests";
public static final String DATABASE_CAREPORTALEVENTS = "CareportalEvents";
public static final String DATABASE_TDDS = "TDDs"; public static final String DATABASE_TDDS = "TDDs";
private static final int DATABASE_VERSION = 13; private static final int DATABASE_VERSION = 13;
@ -87,9 +84,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final ScheduledExecutorService extendedBolusWorker = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService extendedBolusWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledExtendedBolusPost = null; private static ScheduledFuture<?> scheduledExtendedBolusPost = null;
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 static ScheduledFuture<?> scheduledProfileSwitchEventPost = null;
@ -111,7 +105,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class); TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class); TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class);
TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class); TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class);
TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class);
TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class); TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class);
TableUtils.createTableIfNotExists(connectionSource, TDD.class); TableUtils.createTableIfNotExists(connectionSource, TDD.class);
TableUtils.createTableIfNotExists(connectionSource, InsightHistoryOffset.class); TableUtils.createTableIfNotExists(connectionSource, InsightHistoryOffset.class);
@ -141,7 +134,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.dropTable(connectionSource, DbRequest.class, true); TableUtils.dropTable(connectionSource, DbRequest.class, true);
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true); TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
TableUtils.dropTable(connectionSource, ExtendedBolus.class, true); TableUtils.dropTable(connectionSource, ExtendedBolus.class, true);
TableUtils.dropTable(connectionSource, CareportalEvent.class, true);
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true); TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
onCreate(database, connectionSource); onCreate(database, connectionSource);
} else if (oldVersion < 10) { } else if (oldVersion < 10) {
@ -189,7 +181,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.dropTable(connectionSource, DbRequest.class, true); TableUtils.dropTable(connectionSource, DbRequest.class, true);
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true); TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
TableUtils.dropTable(connectionSource, ExtendedBolus.class, true); TableUtils.dropTable(connectionSource, ExtendedBolus.class, true);
TableUtils.dropTable(connectionSource, CareportalEvent.class, true);
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true); TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
TableUtils.dropTable(connectionSource, TDD.class, true); TableUtils.dropTable(connectionSource, TDD.class, true);
TableUtils.dropTable(connectionSource, OmnipodHistoryRecord.class, true); TableUtils.dropTable(connectionSource, OmnipodHistoryRecord.class, true);
@ -197,7 +188,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class); TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class); TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class);
TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class); TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class);
TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class);
TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class); TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class);
TableUtils.createTableIfNotExists(connectionSource, TDD.class); TableUtils.createTableIfNotExists(connectionSource, TDD.class);
TableUtils.createTableIfNotExists(connectionSource, OmnipodHistoryRecord.class); TableUtils.createTableIfNotExists(connectionSource, OmnipodHistoryRecord.class);
@ -208,7 +198,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
virtualPumpPlugin.setFakingStatus(true); virtualPumpPlugin.setFakingStatus(true);
scheduleTemporaryBasalChange(); scheduleTemporaryBasalChange();
scheduleExtendedBolusChange(); scheduleExtendedBolusChange();
scheduleCareportalEventChange();
scheduleProfileSwitchChange(); scheduleProfileSwitchChange();
new java.util.Timer().schedule( new java.util.Timer().schedule(
new java.util.TimerTask() { new java.util.TimerTask() {
@ -244,16 +233,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
scheduleExtendedBolusChange(); scheduleExtendedBolusChange();
} }
public void resetCareportalEvents() {
try {
TableUtils.dropTable(connectionSource, CareportalEvent.class, true);
TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class);
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
scheduleCareportalEventChange();
}
public void resetProfileSwitch() { public void resetProfileSwitch() {
try { try {
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true); TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
@ -295,10 +274,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return getDao(ExtendedBolus.class); return getDao(ExtendedBolus.class);
} }
private Dao<CareportalEvent, Long> getDaoCareportalEvents() throws SQLException {
return getDao(CareportalEvent.class);
}
private Dao<ProfileSwitch, Long> getDaoProfileSwitch() throws SQLException { private Dao<ProfileSwitch, Long> getDaoProfileSwitch() throws SQLException {
return getDao(ProfileSwitch.class); return getDao(ProfileSwitch.class);
} }
@ -411,14 +386,20 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void deleteDbRequestbyMongoId(String action, String id) { public void deleteDbRequestbyMongoId(String action, String id) {
try { try {
QueryBuilder<DbRequest, String> queryBuilder = getDaoDbRequest().queryBuilder(); QueryBuilder<DbRequest, String> queryBuilder = getDaoDbRequest().queryBuilder();
// By nsID
Where where = queryBuilder.where(); Where where = queryBuilder.where();
where.eq("_id", id).and().eq("action", action); where.eq("_id", id).and().eq("action", action);
queryBuilder.limit(10L); queryBuilder.limit(10L);
PreparedQuery<DbRequest> preparedQuery = queryBuilder.prepare(); PreparedQuery<DbRequest> preparedQuery = queryBuilder.prepare();
List<DbRequest> dbList = getDaoDbRequest().query(preparedQuery); List<DbRequest> dbList = getDaoDbRequest().query(preparedQuery);
for (DbRequest r : dbList) { for (DbRequest r : dbList) delete(r);
delete(r); // By nsClientID
} where = queryBuilder.where();
where.eq("nsClientID", id).and().eq("action", action);
queryBuilder.limit(10L);
preparedQuery = queryBuilder.prepare();
dbList = getDaoDbRequest().query(preparedQuery);
for (DbRequest r : dbList) delete(r);
} catch (SQLException e) { } catch (SQLException e) {
aapsLogger.error("Unhandled exception", e); aapsLogger.error("Unhandled exception", e);
} }
@ -1033,219 +1014,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
// ------------ CareportalEvent handling ---------------
public void createOrUpdate(CareportalEvent careportalEvent) {
careportalEvent.date = careportalEvent.date - careportalEvent.date % 1000;
try {
getDaoCareportalEvents().createOrUpdate(careportalEvent);
openHumansUploader.enqueueCareportalEvent(careportalEvent);
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
scheduleCareportalEventChange();
}
public void delete(CareportalEvent careportalEvent) {
try {
getDaoCareportalEvents().delete(careportalEvent);
openHumansUploader.enqueueCareportalEvent(careportalEvent, true);
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
scheduleCareportalEventChange();
}
public CareportalEvent getCareportalEventFromTimestamp(long timestamp) {
try {
return getDaoCareportalEvents().queryForId(timestamp);
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return null;
}
public List<CareportalEvent> getAllCareportalEvents() {
try {
return getDaoCareportalEvents().queryForAll();
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return Collections.emptyList();
}
@Nullable
public CareportalEvent getLastCareportalEvent(String event) {
try {
List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", false);
Where where = queryBuilder.where();
where.eq("eventType", event).and().isNotNull("json");
queryBuilder.limit(1L);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
if (careportalEvents.size() == 1)
return careportalEvents.get(0);
else
return null;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return null;
}
public List<CareportalEvent> getCareportalEventsFromTime(long mills, boolean ascending) {
try {
List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills).and().isNotNull("json").and().isNotNull("eventType");
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public List<CareportalEvent> getCareportalEvents(long start, long end, boolean ascending) {
try {
List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.between("date", start, end).and().isNotNull("json").and().isNotNull("eventType");
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public List<CareportalEvent> preprocessOpenAPSOfflineEvents(List<CareportalEvent> list) {
NonOverlappingIntervals offlineEvents = new NonOverlappingIntervals();
List<CareportalEvent> other = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
CareportalEvent event = list.get(i);
if (event.eventType.equals(CareportalEvent.OPENAPSOFFLINE)) offlineEvents.add(event);
else other.add(event);
}
other.addAll(offlineEvents.getList());
return other;
}
public List<CareportalEvent> getCareportalEventsFromTime(long mills, String type, boolean ascending) {
try {
List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills).and().eq("eventType", type).and().isNotNull("json");
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public List<CareportalEvent> getCareportalEvents(boolean ascending) {
try {
List<CareportalEvent> careportalEvents;
QueryBuilder<CareportalEvent, Long> queryBuilder = getDaoCareportalEvents().queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.isNotNull("json").and().isNotNull("eventType");
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
careportalEvents = getDaoCareportalEvents().query(preparedQuery);
careportalEvents = preprocessOpenAPSOfflineEvents(careportalEvents);
return careportalEvents;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public void deleteCareportalEventById(String _id) {
try {
QueryBuilder<CareportalEvent, Long> queryBuilder;
queryBuilder = getDaoCareportalEvents().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", _id);
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
List<CareportalEvent> list = getDaoCareportalEvents().query(preparedQuery);
if (list.size() == 1) {
CareportalEvent record = list.get(0);
aapsLogger.debug(LTag.DATABASE, "Removing CareportalEvent record from database: " + record.toString());
delete(record);
} else {
aapsLogger.debug(LTag.DATABASE, "CareportalEvent not found database: " + _id);
}
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
}
public void createCareportalEventFromJsonIfNotExists(JSONObject trJson) {
try {
QueryBuilder<CareportalEvent, Long> queryBuilder;
queryBuilder = getDaoCareportalEvents().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", trJson.getString("_id")).or().eq("date", trJson.getLong("mills"));
PreparedQuery<CareportalEvent> preparedQuery = queryBuilder.prepare();
List<CareportalEvent> list = getDaoCareportalEvents().query(preparedQuery);
CareportalEvent careportalEvent;
if (list.size() == 0) {
careportalEvent = new CareportalEvent(StaticInjector.Companion.getInstance());
careportalEvent.source = Source.NIGHTSCOUT;
aapsLogger.debug(LTag.DATABASE, "Adding CareportalEvent record to database: " + trJson.toString());
// Record does not exists. add
} else if (list.size() == 1) {
careportalEvent = list.get(0);
aapsLogger.debug(LTag.DATABASE, "Updating CareportalEvent record in database: " + trJson.toString());
} else {
aapsLogger.error("Something went wrong");
return;
}
careportalEvent.date = trJson.getLong("mills");
careportalEvent.eventType = trJson.getString("eventType");
careportalEvent.json = trJson.toString();
careportalEvent._id = trJson.getString("_id");
createOrUpdate(careportalEvent);
} catch (SQLException | JSONException e) {
aapsLogger.error("Unhandled exception: " + trJson.toString(), e);
}
}
private void scheduleCareportalEventChange() {
class PostRunnable implements Runnable {
public void run() {
aapsLogger.debug(LTag.DATABASE, "Firing scheduleCareportalEventChange");
rxBus.send(new EventCareportalEventChange());
scheduledCareportalEventPost = null;
}
}
// prepare task for execution in 1 sec
// cancel waiting task to prevent sending multiple posts
if (scheduledCareportalEventPost != null)
scheduledCareportalEventPost.cancel(false);
Runnable task = new PostRunnable();
final int sec = 1;
scheduledCareportalEventPost = careportalEventWorker.schedule(task, sec, TimeUnit.SECONDS);
}
// ---------------- ProfileSwitch handling --------------- // ---------------- ProfileSwitch handling ---------------
public List<ProfileSwitch> getProfileSwitchData(long from, boolean ascending) { public List<ProfileSwitch> getProfileSwitchData(long from, boolean ascending) {
@ -1726,9 +1494,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public long getCountOfAllRows() { public long getCountOfAllRows() {
try { try {
return getDaoCareportalEvents().countOf() return getDaoExtendedBolus().countOf()
+ getDaoExtendedBolus().countOf()
+ getDaoCareportalEvents().countOf()
+ getDaoProfileSwitch().countOf() + getDaoProfileSwitch().countOf()
+ getDaoTDD().countOf() + getDaoTDD().countOf()
+ getDaoTemporaryBasal().countOf(); + getDaoTemporaryBasal().countOf();

View file

@ -24,10 +24,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
@Inject DatabaseHelperProvider() { @Inject DatabaseHelperProvider() {
} }
@Override public void createOrUpdate(@NonNull CareportalEvent careportalEvent) {
MainApp.Companion.getDbHelper().createOrUpdate(careportalEvent);
}
@Override public void createOrUpdate(@NonNull DanaRHistoryRecord record) { @Override public void createOrUpdate(@NonNull DanaRHistoryRecord record) {
MainApp.Companion.getDbHelper().createOrUpdate(record); MainApp.Companion.getDbHelper().createOrUpdate(record);
} }
@ -92,10 +88,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
return MainApp.Companion.getDbHelper().getTemporaryBasalsDataFromTime(mills, ascending); return MainApp.Companion.getDbHelper().getTemporaryBasalsDataFromTime(mills, ascending);
} }
@Override public CareportalEvent getCareportalEventFromTimestamp(long timestamp) {
return MainApp.Companion.getDbHelper().getCareportalEventFromTimestamp(timestamp);
}
@NonNull @Override public List<OmnipodHistoryRecord> getAllOmnipodHistoryRecordsFromTimestamp(long timestamp, boolean ascending) { @NonNull @Override public List<OmnipodHistoryRecord> getAllOmnipodHistoryRecordsFromTimestamp(long timestamp, boolean ascending) {
return MainApp.Companion.getDbHelper().getAllOmnipodHistoryRecordsFromTimeStamp(timestamp, ascending); return MainApp.Companion.getDbHelper().getAllOmnipodHistoryRecordsFromTimeStamp(timestamp, ascending);
} }
@ -168,10 +160,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
MainApp.Companion.getDbHelper().deleteExtendedBolusById(_id); MainApp.Companion.getDbHelper().deleteExtendedBolusById(_id);
} }
@Override public void deleteCareportalEventById(@NonNull String _id) {
MainApp.Companion.getDbHelper().deleteCareportalEventById(_id);
}
@Override public void deleteProfileSwitchById(@NonNull String _id) { @Override public void deleteProfileSwitchById(@NonNull String _id) {
MainApp.Companion.getDbHelper().deleteProfileSwitchById(_id); MainApp.Companion.getDbHelper().deleteProfileSwitchById(_id);
} }
@ -184,10 +172,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
MainApp.Companion.getDbHelper().createExtendedBolusFromJsonIfNotExists(json); MainApp.Companion.getDbHelper().createExtendedBolusFromJsonIfNotExists(json);
} }
@Override public void createCareportalEventFromJsonIfNotExists(@NonNull JSONObject json) {
MainApp.Companion.getDbHelper().createCareportalEventFromJsonIfNotExists(json);
}
@Override public void createProfileSwitchFromJsonIfNotExists(@NonNull ActivePluginProvider activePluginProvider, @NonNull NSUpload nsUpload, @NonNull JSONObject trJson) { @Override public void createProfileSwitchFromJsonIfNotExists(@NonNull ActivePluginProvider activePluginProvider, @NonNull NSUpload nsUpload, @NonNull JSONObject trJson) {
MainApp.Companion.getDbHelper().createProfileSwitchFromJsonIfNotExists(activePluginProvider, nsUpload, trJson); MainApp.Companion.getDbHelper().createProfileSwitchFromJsonIfNotExists(activePluginProvider, nsUpload, trJson);
} }
@ -200,34 +184,10 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
MainApp.Companion.getDbHelper().createOrUpdate(record); MainApp.Companion.getDbHelper().createOrUpdate(record);
} }
@Override public void delete(@NonNull CareportalEvent careportalEvent) {
MainApp.Companion.getDbHelper().delete(careportalEvent);
}
@Override public void delete(@NonNull ProfileSwitch profileSwitch) { @Override public void delete(@NonNull ProfileSwitch profileSwitch) {
MainApp.Companion.getDbHelper().delete(profileSwitch); MainApp.Companion.getDbHelper().delete(profileSwitch);
} }
@Nullable @Override public CareportalEvent getLastCareportalEvent(@NonNull String event) {
return MainApp.Companion.getDbHelper().getLastCareportalEvent(event);
}
@NonNull @Override public List<CareportalEvent> getCareportalEventsFromTime(long mills, boolean ascending) {
return MainApp.Companion.getDbHelper().getCareportalEventsFromTime(mills, ascending);
}
@NonNull @Override public List<CareportalEvent> getCareportalEventsFromTime(long mills, @NonNull String type, boolean ascending) {
return MainApp.Companion.getDbHelper().getCareportalEventsFromTime(mills, type, ascending);
}
@NonNull @Override public List<CareportalEvent> getCareportalEvents(long start, long end, boolean ascending) {
return MainApp.Companion.getDbHelper().getCareportalEvents(start, end, ascending);
}
@NonNull @Override public List<CareportalEvent> getCareportalEvents(boolean ascending) {
return MainApp.Companion.getDbHelper().getCareportalEvents(ascending);
}
@NonNull @Override public List<ProfileSwitch> getProfileSwitchEventsFromTime(long from, long to, boolean ascending) { @NonNull @Override public List<ProfileSwitch> getProfileSwitchEventsFromTime(long from, long to, boolean ascending) {
return MainApp.Companion.getDbHelper().getProfileSwitchEventsFromTime(from, to, ascending); return MainApp.Companion.getDbHelper().getProfileSwitchEventsFromTime(from, to, ascending);
} }
@ -236,10 +196,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
return MainApp.Companion.getDbHelper().getProfileSwitchEventsFromTime(mills, ascending); return MainApp.Companion.getDbHelper().getProfileSwitchEventsFromTime(mills, ascending);
} }
@NonNull @Override public List<CareportalEvent> getAllCareportalEvents() {
return MainApp.Companion.getDbHelper().getAllCareportalEvents();
}
@NonNull @Override public List<ExtendedBolus> getAllExtendedBoluses() { @NonNull @Override public List<ExtendedBolus> getAllExtendedBoluses() {
return MainApp.Companion.getDbHelper().getAllExtendedBoluses(); return MainApp.Companion.getDbHelper().getAllExtendedBoluses();
} }
@ -260,10 +216,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
return MainApp.Companion.getDbHelper().getAllOHQueueItems(maxEntries); return MainApp.Companion.getDbHelper().getAllOHQueueItems(maxEntries);
} }
@Override public void resetCareportalEvents() {
MainApp.Companion.getDbHelper().resetCareportalEvents();
}
@Override public void resetProfileSwitch() { @Override public void resetProfileSwitch() {
MainApp.Companion.getDbHelper().resetProfileSwitch(); MainApp.Companion.getDbHelper().resetProfileSwitch();
} }

View file

@ -13,9 +13,9 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.databinding.DialogCarbsBinding import info.nightscout.androidaps.databinding.DialogCarbsBinding
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
@ -271,11 +271,11 @@ class CarbsDialog : DialogFragmentWithDate() {
if (carbsAfterConstraints > 0) { if (carbsAfterConstraints > 0) {
if (duration == 0) { if (duration == 0) {
uel.log("CARBS", d1 = carbsAfterConstraints.toDouble(), i1 = timeOffset) uel.log("CARBS", d1 = carbsAfterConstraints.toDouble(), i1 = timeOffset)
carbsGenerator.createCarb(carbsAfterConstraints, time, CareportalEvent.CARBCORRECTION, notes) carbsGenerator.createCarb(carbsAfterConstraints, time, TherapyEvent.Type.CARBS_CORRECTION.text, notes)
} else { } else {
uel.log("CARBS", d1 = carbsAfterConstraints.toDouble(), i1 = timeOffset, i2 = duration) uel.log("CARBS", d1 = carbsAfterConstraints.toDouble(), i1 = timeOffset, i2 = duration)
carbsGenerator.generateCarbs(carbsAfterConstraints, time, duration, notes) carbsGenerator.generateCarbs(carbsAfterConstraints, time, duration, notes)
nsUpload.uploadEvent(CareportalEvent.NOTE, DateUtil.now() - 2000, resourceHelper.gs(R.string.generated_ecarbs_note, carbsAfterConstraints, duration, timeOffset)) nsUpload.uploadEvent(TherapyEvent.Type.NOTE.text, DateUtil.now() - 2000, resourceHelper.gs(R.string.generated_ecarbs_note, carbsAfterConstraints, duration, timeOffset))
} }
} }
if (useAlarm && carbs > 0 && timeOffset > 0) { if (useAlarm && carbs > 0 && timeOffset > 0) {

View file

@ -13,20 +13,22 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction
import info.nightscout.androidaps.databinding.DialogCareBinding import info.nightscout.androidaps.databinding.DialogCareBinding
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.Translator import info.nightscout.androidaps.utils.Translator
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.json.JSONObject import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -40,7 +42,9 @@ class CareDialog : DialogFragmentWithDate() {
@Inject lateinit var nsUpload: NSUpload @Inject lateinit var nsUpload: NSUpload
@Inject lateinit var translator: Translator @Inject lateinit var translator: Translator
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var repository: AppRepository
private val disposable = CompositeDisposable()
enum class EventType { enum class EventType {
BGCHECK, BGCHECK,
@ -114,7 +118,7 @@ class CareDialog : DialogFragmentWithDate() {
when (options) { when (options) {
EventType.QUESTION, EventType.QUESTION,
EventType.ANNOUNCEMENT, EventType.ANNOUNCEMENT,
EventType.BGCHECK -> { EventType.BGCHECK -> {
binding.durationLayout.visibility = View.GONE binding.durationLayout.visibility = View.GONE
} }
@ -126,7 +130,7 @@ class CareDialog : DialogFragmentWithDate() {
} }
EventType.NOTE, EventType.NOTE,
EventType.EXERCISE -> { EventType.EXERCISE -> {
binding.bgLayout.visibility = View.GONE binding.bgLayout.visibility = View.GONE
binding.bgsource.visibility = View.GONE binding.bgsource.visibility = View.GONE
} }
@ -163,70 +167,62 @@ class CareDialog : DialogFragmentWithDate() {
} }
override fun submit(): Boolean { override fun submit(): Boolean {
val enteredBy = sp.getString("careportal_enteredby", "") val enteredBy = sp.getString("careportal_enteredby", "AndroidAPS")
val unitResId = if (profileFunction.getUnits() == Constants.MGDL) R.string.mgdl else R.string.mmol val unitResId = if (profileFunction.getUnits() == Constants.MGDL) R.string.mgdl else R.string.mmol
val json = JSONObject() eventTime -= eventTime % 1000
val therapyEvent = TherapyEvent(
timestamp = eventTime,
type = when (options) {
EventType.BGCHECK -> TherapyEvent.Type.FINGER_STICK_BG_VALUE
EventType.SENSOR_INSERT -> TherapyEvent.Type.SENSOR_CHANGE
EventType.BATTERY_CHANGE -> TherapyEvent.Type.PUMP_BATTERY_CHANGE
EventType.NOTE -> TherapyEvent.Type.NOTE
EventType.EXERCISE -> TherapyEvent.Type.EXERCISE
EventType.QUESTION -> TherapyEvent.Type.QUESTION
EventType.ANNOUNCEMENT -> TherapyEvent.Type.ANNOUNCEMENT
},
units = profileFunction.getUnits()
)
val actions: LinkedList<String> = LinkedList() val actions: LinkedList<String> = LinkedList()
if (options == EventType.BGCHECK || options == EventType.QUESTION || options == EventType.ANNOUNCEMENT) { if (options == EventType.BGCHECK || options == EventType.QUESTION || options == EventType.ANNOUNCEMENT) {
val type = val meterType =
when { when {
binding.meter.isChecked -> CareportalEvent.FINGER binding.meter.isChecked -> TherapyEvent.MeterType.FINGER
binding.sensor.isChecked -> CareportalEvent.SENSOR binding.sensor.isChecked -> TherapyEvent.MeterType.SENSOR
else -> CareportalEvent.MANUAL else -> TherapyEvent.MeterType.MANUAL
} }
actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_glucosetype) + ": " + translator.translate(type)) actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_glucosetype) + ": " + translator.translate(meterType.text))
actions.add(resourceHelper.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(profileFunction, binding.bg.value) + " " + resourceHelper.gs(unitResId)) actions.add(resourceHelper.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(profileFunction, binding.bg.value) + " " + resourceHelper.gs(unitResId))
json.put("glucose", binding.bg.value) therapyEvent.glucoseType = meterType
json.put("glucoseType", type) therapyEvent.glucose = binding.bg.value
} }
if (options == EventType.NOTE || options == EventType.EXERCISE) { if (options == EventType.NOTE || options == EventType.EXERCISE) {
actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_duration_label) + ": " + resourceHelper.gs(R.string.format_mins, binding.duration.value.toInt())) actions.add(resourceHelper.gs(R.string.careportal_newnstreatment_duration_label) + ": " + resourceHelper.gs(R.string.format_mins, binding.duration.value.toInt()))
json.put("duration", binding.duration.value.toInt()) therapyEvent.duration = T.mins(binding.duration.value.toLong()).msecs()
} }
val notes = binding.notesLayout.notes.text.toString() val notes = binding.notesLayout.notes.text.toString()
if (notes.isNotEmpty()) { if (notes.isNotEmpty()) {
actions.add(resourceHelper.gs(R.string.notes_label) + ": " + notes) actions.add(resourceHelper.gs(R.string.notes_label) + ": " + notes)
json.put("notes", notes) therapyEvent.note = notes
} }
eventTime -= eventTime % 1000
if (eventTimeChanged) if (eventTimeChanged)
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime)) actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime))
json.put("created_at", DateUtil.toISOString(eventTime)) therapyEvent.enteredBy = enteredBy
json.put("mills", eventTime)
json.put("eventType", when (options) {
EventType.BGCHECK -> CareportalEvent.BGCHECK
EventType.SENSOR_INSERT -> CareportalEvent.SENSORCHANGE
EventType.BATTERY_CHANGE -> CareportalEvent.PUMPBATTERYCHANGE
EventType.NOTE -> CareportalEvent.NOTE
EventType.EXERCISE -> CareportalEvent.EXERCISE
EventType.QUESTION -> CareportalEvent.QUESTION
EventType.ANNOUNCEMENT -> CareportalEvent.ANNOUNCEMENT
})
json.put("units", profileFunction.getUnits())
if (enteredBy.isNotEmpty())
json.put("enteredBy", enteredBy)
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(event), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), { OKDialog.showConfirmation(activity, resourceHelper.gs(event), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
val careportalEvent = CareportalEvent(injector) disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction(therapyEvent)).subscribe({ result ->
careportalEvent.date = eventTime result.inserted.forEach { nsUpload.uploadEvent(it) }
careportalEvent.source = Source.USER }, {
careportalEvent.eventType = when (options) { aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it)
EventType.BGCHECK -> CareportalEvent.BGCHECK })
EventType.SENSOR_INSERT -> CareportalEvent.SENSORCHANGE
EventType.BATTERY_CHANGE -> CareportalEvent.PUMPBATTERYCHANGE uel.log("CAREPORTAL", therapyEvent.type.text)
EventType.NOTE -> CareportalEvent.NOTE
EventType.EXERCISE -> CareportalEvent.EXERCISE
EventType.QUESTION -> CareportalEvent.QUESTION
EventType.ANNOUNCEMENT -> CareportalEvent.ANNOUNCEMENT
}
careportalEvent.json = json.toString()
uel.log("CAREPORTAL", careportalEvent.eventType)
databaseHelper.createOrUpdate(careportalEvent)
nsUpload.uploadCareportalEntryToNS(json, eventTime)
}, null) }, null)
} }
return true return true

View file

@ -9,12 +9,15 @@ import com.google.common.base.Joiner
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction
import info.nightscout.androidaps.databinding.DialogFillBinding import info.nightscout.androidaps.databinding.DialogFillBinding
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
@ -25,6 +28,8 @@ import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.formatColor import info.nightscout.androidaps.utils.extensions.formatColor
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs import kotlin.math.abs
@ -38,6 +43,9 @@ class FillDialog : DialogFragmentWithDate() {
@Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var commandQueue: CommandQueueProvider
@Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var repository: AppRepository
private val disposable = CompositeDisposable()
private var _binding: DialogFillBinding? = null private var _binding: DialogFillBinding? = null
@ -132,12 +140,28 @@ class FillDialog : DialogFragmentWithDate() {
} }
if (siteChange) { if (siteChange) {
uel.log("SITE CHANGE") uel.log("SITE CHANGE")
nsUpload.generateCareportalEvent(CareportalEvent.SITECHANGE, eventTime, notes) disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction(
timestamp = eventTime,
type = TherapyEvent.Type.CANNULA_CHANGE,
note = notes
)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadEvent(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it)
})
} }
if (insulinChange) { if (insulinChange) {
// add a second for case of both checked // add a second for case of both checked
uel.log("INSULIN CHANGE") uel.log("INSULIN CHANGE")
nsUpload.generateCareportalEvent(CareportalEvent.INSULINCHANGE, eventTime + 1000, notes) disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction(
timestamp = eventTime + 1000,
type = TherapyEvent.Type.INSULIN_CHANGE,
note = notes
)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadEvent(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it)
})
} }
}, null) }, null)
} }

View file

@ -16,9 +16,9 @@ import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.databinding.DialogInsulinBinding import info.nightscout.androidaps.databinding.DialogInsulinBinding
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
@ -204,7 +204,7 @@ class InsulinDialog : DialogFragmentWithDate() {
} }
if (insulinAfterConstraints > 0) { if (insulinAfterConstraints > 0) {
val detailedBolusInfo = DetailedBolusInfo() val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS detailedBolusInfo.eventType = TherapyEvent.Type.CORRECTION_BOLUS.text
detailedBolusInfo.insulin = insulinAfterConstraints detailedBolusInfo.insulin = insulinAfterConstraints
detailedBolusInfo.context = context detailedBolusInfo.context = context
detailedBolusInfo.source = Source.USER detailedBolusInfo.source = Source.USER

View file

@ -12,8 +12,8 @@ import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.databinding.DialogTreatmentBinding import info.nightscout.androidaps.databinding.DialogTreatmentBinding
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
@ -131,8 +131,8 @@ class TreatmentDialog : DialogFragmentWithDate() {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
uel.log("TREATMENT", d1 = insulin, i1 = carbs) uel.log("TREATMENT", d1 = insulin, i1 = carbs)
val detailedBolusInfo = DetailedBolusInfo() val detailedBolusInfo = DetailedBolusInfo()
if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = CareportalEvent.CARBCORRECTION if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = TherapyEvent.Type.CARBS_CORRECTION.text
if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = TherapyEvent.Type.CORRECTION_BOLUS.text
detailedBolusInfo.insulin = insulinAfterConstraints detailedBolusInfo.insulin = insulinAfterConstraints
detailedBolusInfo.carbs = carbsAfterConstraints.toDouble() detailedBolusInfo.carbs = carbsAfterConstraints.toDouble()
detailedBolusInfo.context = context detailedBolusInfo.context = context

View file

@ -1,3 +1,3 @@
package info.nightscout.androidaps.events package info.nightscout.androidaps.events
class EventCareportalEventChange : Event() class EventTherapyEventChange : Event()

View file

@ -15,7 +15,9 @@ import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.events.EventAutosensCalculationFinished
@ -50,8 +52,7 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import org.json.JSONException import io.reactivex.rxkotlin.plusAssign
import org.json.JSONObject
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.abs import kotlin.math.abs
@ -76,7 +77,8 @@ open class LoopPlugin @Inject constructor(
private val receiverStatusStore: ReceiverStatusStore, private val receiverStatusStore: ReceiverStatusStore,
private val fabricPrivacy: FabricPrivacy, private val fabricPrivacy: FabricPrivacy,
private val nsUpload: NSUpload, private val nsUpload: NSUpload,
private val databaseHelper: DatabaseHelperInterface private val dateUtil: DateUtil,
private val repository: AppRepository
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.LOOP) .mainType(PluginType.LOOP)
.fragmentClass(LoopFragment::class.java.name) .fragmentClass(LoopFragment::class.java.name)
@ -594,7 +596,7 @@ open class LoopPlugin @Inject constructor(
// deliver SMB // deliver SMB
val detailedBolusInfo = DetailedBolusInfo() val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.lastKnownBolusTime = treatmentsPlugin.lastBolusTime detailedBolusInfo.lastKnownBolusTime = treatmentsPlugin.lastBolusTime
detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS detailedBolusInfo.eventType = TherapyEvent.Type.CORRECTION_BOLUS.text
detailedBolusInfo.insulin = request.smb detailedBolusInfo.insulin = request.smb
detailedBolusInfo.isSMB = true detailedBolusInfo.isSMB = true
detailedBolusInfo.source = Source.USER detailedBolusInfo.source = Source.USER
@ -652,20 +654,16 @@ open class LoopPlugin @Inject constructor(
} }
override fun createOfflineEvent(durationInMinutes: Int) { override fun createOfflineEvent(durationInMinutes: Int) {
val data = JSONObject() disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction(
try { timestamp = dateUtil._now(),
data.put("eventType", CareportalEvent.OPENAPSOFFLINE) type = TherapyEvent.Type.APS_OFFLINE,
data.put("duration", durationInMinutes) duration = T.mins(durationInMinutes.toLong()).msecs(),
} catch (e: JSONException) { enteredBy = "openaps://" + "AndroidAPS"
aapsLogger.error("Unhandled exception", e) )).subscribe({ result ->
} result.inserted.forEach { nsUpload.uploadEvent(it) }
val event = CareportalEvent(injector) }, {
event.date = DateUtil.now() aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it)
event.source = Source.USER })
event.eventType = CareportalEvent.OPENAPSOFFLINE
event.json = data.toString()
databaseHelper.createOrUpdate(event)
nsUpload.uploadOpenAPSOffline(event)
} }
companion object { companion object {

View file

@ -235,7 +235,7 @@ class ActionsFragment : DaggerFragment() {
.observeOn(aapsSchedulers.main) .observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException) .subscribe({ updateGui() }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventCareportalEventChange::class.java) .toObservable(EventTherapyEventChange::class.java)
.observeOn(aapsSchedulers.main) .observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException) .subscribe({ updateGui() }, fabricPrivacy::logException)
updateGui() updateGui()

View file

@ -30,8 +30,9 @@ import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.database.AppRepository; import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.TemporaryTarget; import info.nightscout.androidaps.database.entities.TemporaryTarget;
import info.nightscout.androidaps.database.entities.TherapyEvent;
import info.nightscout.androidaps.database.transactions.SyncTemporaryTargetTransaction; import info.nightscout.androidaps.database.transactions.SyncTemporaryTargetTransaction;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.database.transactions.SyncTherapyEventTransaction;
import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventChargingState; import info.nightscout.androidaps.events.EventChargingState;
import info.nightscout.androidaps.events.EventNetworkChange; import info.nightscout.androidaps.events.EventNetworkChange;
@ -69,6 +70,9 @@ import io.reactivex.disposables.CompositeDisposable;
import static info.nightscout.androidaps.utils.extensions.TemporaryTargetExtensionKt.temporaryTargetFromJson; import static info.nightscout.androidaps.utils.extensions.TemporaryTargetExtensionKt.temporaryTargetFromJson;
import static info.nightscout.androidaps.utils.extensions.TemporaryTargetExtensionKt.temporaryTargetFromNsIdForInvalidating; import static info.nightscout.androidaps.utils.extensions.TemporaryTargetExtensionKt.temporaryTargetFromNsIdForInvalidating;
import static info.nightscout.androidaps.utils.extensions.TherapyEventExtensionKt.therapyEventFromJson;
import static info.nightscout.androidaps.utils.extensions.TherapyEventExtensionKt.therapyEventFromNsIdForInvalidating;
import static info.nightscout.androidaps.utils.extensions.TherapyEventExtensionKt.therapyEventFromNsMbg;
@Singleton @Singleton
public class NSClientPlugin extends PluginBase { public class NSClientPlugin extends PluginBase {
@ -424,14 +428,18 @@ public class NSClientPlugin extends PluginBase {
TemporaryTarget temporaryTarget = temporaryTargetFromNsIdForInvalidating(_id); TemporaryTarget temporaryTarget = temporaryTargetFromNsIdForInvalidating(_id);
disposable.add(repository.runTransactionForResult(new SyncTemporaryTargetTransaction(temporaryTarget)).subscribe( disposable.add(repository.runTransactionForResult(new SyncTemporaryTargetTransaction(temporaryTarget)).subscribe(
result -> result.getInvalidated().forEach(record -> uel.log("TT DELETED FROM NS", record.getReason().getText(), record.getLowTarget(), record.getHighTarget(), (int) record.getDuration(), 0)), result -> result.getInvalidated().forEach(record -> uel.log("TT DELETED FROM NS", record.getReason().getText(), record.getLowTarget(), record.getHighTarget(), (int) record.getDuration(), 0)),
error -> aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", error))); error -> aapsLogger.error(LTag.DATABASE, "Error while removing temporary target", error)));
// room Therapy Event
TherapyEvent therapyEvent = therapyEventFromNsIdForInvalidating(_id);
disposable.add(repository.runTransactionForResult(new SyncTherapyEventTransaction(therapyEvent)).subscribe(
result -> result.getInvalidated().forEach(record -> uel.log("CAREPORTAL EVENT DELETED FROM NS", record.getType().getText(), 0.0, 0.0, 0, 0)),
error -> aapsLogger.error(LTag.DATABASE, "Error while removing therapy event", error)));
// new DB model // new DB model
EventNsTreatment evtTreatment = new EventNsTreatment(EventNsTreatment.Companion.getREMOVE(), json); EventNsTreatment evtTreatment = new EventNsTreatment(EventNsTreatment.Companion.getREMOVE(), json);
rxBus.send(evtTreatment); rxBus.send(evtTreatment);
// old DB model // old DB model
databaseHelper.deleteTempBasalById(_id); databaseHelper.deleteTempBasalById(_id);
databaseHelper.deleteExtendedBolusById(_id); databaseHelper.deleteExtendedBolusById(_id);
databaseHelper.deleteCareportalEventById(_id);
databaseHelper.deleteProfileSwitchById(_id); databaseHelper.deleteProfileSwitchById(_id);
} }
@ -448,40 +456,52 @@ public class NSClientPlugin extends PluginBase {
if (insulin > 0 || carbs > 0) { if (insulin > 0 || carbs > 0) {
EventNsTreatment evtTreatment = new EventNsTreatment(mode, json); EventNsTreatment evtTreatment = new EventNsTreatment(mode, json);
rxBus.send(evtTreatment); rxBus.send(evtTreatment);
} else if (eventType.equals(CareportalEvent.TEMPORARYTARGET)) { } else if (eventType.equals(TherapyEvent.Type.TEMPORARY_TARGET.getText())) {
TemporaryTarget temporaryTarget = temporaryTargetFromJson(json); TemporaryTarget temporaryTarget = temporaryTargetFromJson(json);
if (temporaryTarget != null) { if (temporaryTarget != null) {
disposable.add(repository.runTransactionForResult(new SyncTemporaryTargetTransaction(temporaryTarget)).subscribe( disposable.add(repository.runTransactionForResult(new SyncTemporaryTargetTransaction(temporaryTarget))
result -> { .subscribe(
result.getInserted().forEach(record -> uel.log("TT FROM NS", record.getReason().getText(), record.getLowTarget(), record.getHighTarget(), (int) record.getDuration(), 0)); result -> {
result.getInvalidated().forEach(record -> uel.log("TT DELETED FROM NS", record.getReason().getText(), record.getLowTarget(), record.getHighTarget(), (int) record.getDuration(), 0)); result.getInserted().forEach(record -> uel.log("TT FROM NS", record.getReason().getText(), record.getLowTarget(), record.getHighTarget(), (int) record.getDuration(), 0));
result.getEnded().forEach(record -> uel.log("TT CANCELED FROM NS", record.getReason().getText(), record.getLowTarget(), record.getHighTarget(), (int) record.getDuration(), 0)); result.getInvalidated().forEach(record -> uel.log("TT DELETED FROM NS", record.getReason().getText(), record.getLowTarget(), record.getHighTarget(), (int) record.getDuration(), 0));
}, result.getEnded().forEach(record -> uel.log("TT CANCELED FROM NS", record.getReason().getText(), record.getLowTarget(), record.getHighTarget(), (int) record.getDuration(), 0));
error -> aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", error))); },
error -> aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", error)));
} else { } else {
aapsLogger.error("Error parsing TT json " + json.toString()); aapsLogger.error("Error parsing TT json " + json.toString());
} }
} else if (eventType.equals(CareportalEvent.TEMPBASAL)) { } else if (eventType.equals(TherapyEvent.Type.TEMPORARY_BASAL.getText())) {
databaseHelper.createTempBasalFromJsonIfNotExists(json); databaseHelper.createTempBasalFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.COMBOBOLUS)) { } else if (eventType.equals(TherapyEvent.Type.COMBO_BOLUS.getText())) {
databaseHelper.createExtendedBolusFromJsonIfNotExists(json); databaseHelper.createExtendedBolusFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.PROFILESWITCH)) { } else if (eventType.equals(TherapyEvent.Type.PROFILE_SWITCH.getText())) {
databaseHelper.createProfileSwitchFromJsonIfNotExists(activePlugin, nsUpload, json); databaseHelper.createProfileSwitchFromJsonIfNotExists(activePlugin, nsUpload, json);
} else if (eventType.equals(CareportalEvent.SITECHANGE) || } else if (eventType.equals(TherapyEvent.Type.CANNULA_CHANGE.getText()) ||
eventType.equals(CareportalEvent.INSULINCHANGE) || eventType.equals(TherapyEvent.Type.INSULIN_CHANGE.getText()) ||
eventType.equals(CareportalEvent.SENSORCHANGE) || eventType.equals(TherapyEvent.Type.SENSOR_CHANGE.getText()) ||
eventType.equals(CareportalEvent.BGCHECK) || eventType.equals(TherapyEvent.Type.FINGER_STICK_BG_VALUE.getText()) ||
eventType.equals(CareportalEvent.NOTE) || eventType.equals(TherapyEvent.Type.NOTE.getText()) ||
eventType.equals(CareportalEvent.NONE) || eventType.equals(TherapyEvent.Type.NONE.getText()) ||
eventType.equals(CareportalEvent.ANNOUNCEMENT) || eventType.equals(TherapyEvent.Type.ANNOUNCEMENT.getText()) ||
eventType.equals(CareportalEvent.QUESTION) || eventType.equals(TherapyEvent.Type.QUESTION.getText()) ||
eventType.equals(CareportalEvent.EXERCISE) || eventType.equals(TherapyEvent.Type.EXERCISE.getText()) ||
eventType.equals(CareportalEvent.OPENAPSOFFLINE) || eventType.equals(TherapyEvent.Type.APS_OFFLINE.getText()) ||
eventType.equals(CareportalEvent.PUMPBATTERYCHANGE)) { eventType.equals(TherapyEvent.Type.PUMP_BATTERY_CHANGE.getText())) {
databaseHelper.createCareportalEventFromJsonIfNotExists(json); TherapyEvent therapyEvent = therapyEventFromJson(json);
if (therapyEvent != null) {
disposable.add(repository.runTransactionForResult(new SyncTherapyEventTransaction(therapyEvent))
.subscribe(
result -> {
result.getInserted().forEach(record -> uel.log("CAREPORTAL EVENT NS", record.getType().getText(), 0.0, 0.0, 0, 0));
result.getInvalidated().forEach(record -> uel.log("CAREPORTAL EVENT DELETED FROM NS", record.getType().getText(), 0.0, 0.0, 0, 0));
},
error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error)));
} else {
aapsLogger.error("Error parsing TherapyEvent json " + json.toString());
}
} }
if (eventType.equals(CareportalEvent.ANNOUNCEMENT)) { if (eventType.equals(TherapyEvent.Type.ANNOUNCEMENT.getText())) {
long date = JsonHelper.safeGetLong(json, "mills"); long date = JsonHelper.safeGetLong(json, "mills");
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
String enteredBy = JsonHelper.safeGetString(json, "enteredBy", ""); String enteredBy = JsonHelper.safeGetString(json, "enteredBy", "");
@ -498,9 +518,12 @@ public class NSClientPlugin extends PluginBase {
} }
private void storeMbg(JSONObject mbgJson) { private void storeMbg(JSONObject mbgJson) {
NSMbg nsMbg = new NSMbg(mbgJson); NSMbg nsMbg = new NSMbg(getInjector(), mbgJson);
CareportalEvent careportalEvent = new CareportalEvent(nsMbg); if (nsMbg.mbg != 0.0 && nsMbg.date != 0)
databaseHelper.createOrUpdate(careportalEvent); disposable.add(repository.runTransactionForResult(new SyncTherapyEventTransaction(therapyEventFromNsMbg(nsMbg)))
aapsLogger.debug(LTag.DATASERVICE, "Adding/Updating new MBG: " + careportalEvent.toString()); .subscribe(
result -> aapsLogger.debug(LTag.DATABASE, "Saved therapy event" + result),
error -> aapsLogger.error("Error while saving therapy event", error))
);
} }
} }

View file

@ -18,6 +18,7 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.db.* import info.nightscout.androidaps.db.*
import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
@ -198,23 +199,16 @@ class OpenHumansUploader @Inject constructor(
} }
@JvmOverloads @JvmOverloads
fun enqueueCareportalEvent(careportalEvent: CareportalEvent, deleted: Boolean = false) = insertQueueItem("CareportalEvents") { fun enqueueTherapyEvent(therapyEvent: TherapyEvent, deleted: Boolean = false) = insertQueueItem("TherapyEvents") {
put("date", careportalEvent.date) put("date", therapyEvent.timestamp)
put("isValid", careportalEvent.isValid) put("isValid", therapyEvent.isValid)
put("source", careportalEvent.source) put("nsId", therapyEvent.interfaceIDs.nightscoutId)
put("nsId", careportalEvent._id) put("eventType", therapyEvent.type.text)
put("eventType", careportalEvent.eventType) put("glucose", therapyEvent.glucose)
val data = JSONObject(careportalEvent.json) put("units", therapyEvent.units)
val reducedData = JSONObject() put("glucoseType", therapyEvent.glucoseType?.text)
if (data.has("mgdl")) reducedData.put("mgdl", data.getDouble("mgdl")) put("units", therapyEvent.units)
if (data.has("glucose")) reducedData.put("glucose", data.getDouble("glucose")) put("duration", therapyEvent.duration)
if (data.has("units")) reducedData.put("units", data.getString("units"))
if (data.has("created_at")) reducedData.put("created_at", data.getString("created_at"))
if (data.has("glucoseType")) reducedData.put("glucoseType", data.getString("glucoseType"))
if (data.has("duration")) reducedData.put("duration", data.getInt("duration"))
if (data.has("mills")) reducedData.put("mills", data.getLong("mills"))
if (data.has("eventType")) reducedData.put("eventType", data.getString("eventType"))
put("data", reducedData)
put("isDeletion", deleted) put("isDeletion", deleted)
} }
@ -370,8 +364,8 @@ class OpenHumansUploader @Inject constructor(
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetBgReadingsDataFromTime(0, true).blockingGet()) }) .andThen(Observable.defer { Observable.fromIterable(repository.compatGetBgReadingsDataFromTime(0, true).blockingGet()) })
.map { enqueueBGReading(it); increaseCounter() } .map { enqueueBGReading(it); increaseCounter() }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllCareportalEvents()) }) .andThen(Observable.defer { Observable.fromIterable(repository.compatGetTherapyEventDataFromTime(0, true).blockingGet()) })
.map { enqueueCareportalEvent(it); increaseCounter() } .map { enqueueTherapyEvent(it); increaseCounter() }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllExtendedBoluses()) }) .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllExtendedBoluses()) })
.map { enqueueExtendedBolus(it); increaseCounter() } .map { enqueueExtendedBolus(it); increaseCounter() }

View file

@ -245,7 +245,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventAcceptOpenLoopChange") }, fabricPrivacy::logException)) .subscribe({ scheduleUpdateGUI("EventAcceptOpenLoopChange") }, fabricPrivacy::logException))
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventCareportalEventChange::class.java) .toObservable(EventTherapyEventChange::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventCareportalEventChange") }, fabricPrivacy::logException)) .subscribe({ scheduleUpdateGUI("EventCareportalEventChange") }, fabricPrivacy::logException))
disposable.add(rxBus disposable.add(rxBus

View file

@ -5,14 +5,16 @@ import android.widget.TextView
import androidx.annotation.StringRes import androidx.annotation.StringRes
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.OmnipodConstants import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.OmnipodConstants
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.WarnColors import info.nightscout.androidaps.utils.WarnColors
import info.nightscout.androidaps.utils.extensions.age
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject import javax.inject.Inject
@ -25,7 +27,7 @@ class StatusLightHandler @Inject constructor(
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val warnColors: WarnColors, private val warnColors: WarnColors,
private val config: Config, private val config: Config,
private val databaseHelper: DatabaseHelperInterface private val repository: AppRepository
) { ) {
/** /**
@ -34,11 +36,11 @@ class StatusLightHandler @Inject constructor(
fun updateStatusLights(careportal_cannula_age: TextView?, careportal_insulin_age: TextView?, careportal_reservoir_level: TextView?, careportal_sensor_age: TextView?, careportal_sensor_battery_level: TextView?, careportal_pb_age: TextView?, careportal_battery_level: TextView?) { fun updateStatusLights(careportal_cannula_age: TextView?, careportal_insulin_age: TextView?, careportal_reservoir_level: TextView?, careportal_sensor_age: TextView?, careportal_sensor_battery_level: TextView?, careportal_pb_age: TextView?, careportal_battery_level: TextView?) {
val pump = activePlugin.activePump val pump = activePlugin.activePump
val bgSource = activePlugin.activeBgSource val bgSource = activePlugin.activeBgSource
handleAge(careportal_cannula_age, CareportalEvent.SITECHANGE, R.string.key_statuslights_cage_warning, 48.0, R.string.key_statuslights_cage_critical, 72.0) handleAge(careportal_cannula_age, TherapyEvent.Type.CANNULA_CHANGE, R.string.key_statuslights_cage_warning, 48.0, R.string.key_statuslights_cage_critical, 72.0)
handleAge(careportal_insulin_age, CareportalEvent.INSULINCHANGE, R.string.key_statuslights_iage_warning, 72.0, R.string.key_statuslights_iage_critical, 144.0) handleAge(careportal_insulin_age, TherapyEvent.Type.INSULIN_CHANGE, R.string.key_statuslights_iage_warning, 72.0, R.string.key_statuslights_iage_critical, 144.0)
handleAge(careportal_sensor_age, CareportalEvent.SENSORCHANGE, R.string.key_statuslights_sage_warning, 216.0, R.string.key_statuslights_sage_critical, 240.0) handleAge(careportal_sensor_age, TherapyEvent.Type.SENSOR_CHANGE, R.string.key_statuslights_sage_warning, 216.0, R.string.key_statuslights_sage_critical, 240.0)
if (pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)) { if (pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)) {
handleAge(careportal_pb_age, CareportalEvent.PUMPBATTERYCHANGE, R.string.key_statuslights_bage_warning, 216.0, R.string.key_statuslights_bage_critical, 240.0) handleAge(careportal_pb_age, TherapyEvent.Type.PUMP_BATTERY_CHANGE, R.string.key_statuslights_bage_warning, 216.0, R.string.key_statuslights_bage_critical, 240.0)
} }
if (!config.NSCLIENT) { if (!config.NSCLIENT) {
if (pump.model() == PumpType.Omnipod_Eros || pump.model() == PumpType.Omnipod_Dash) { if (pump.model() == PumpType.Omnipod_Eros || pump.model() == PumpType.Omnipod_Dash) {
@ -67,13 +69,13 @@ class StatusLightHandler @Inject constructor(
} }
} }
private fun handleAge(view: TextView?, eventName: String, @StringRes warnSettings: Int, defaultWarnThreshold: Double, @StringRes urgentSettings: Int, defaultUrgentThreshold: Double) { private fun handleAge(view: TextView?, type: TherapyEvent.Type, @StringRes warnSettings: Int, defaultWarnThreshold: Double, @StringRes urgentSettings: Int, defaultUrgentThreshold: Double) {
val warn = sp.getDouble(warnSettings, defaultWarnThreshold) val warn = sp.getDouble(warnSettings, defaultWarnThreshold)
val urgent = sp.getDouble(urgentSettings, defaultUrgentThreshold) val urgent = sp.getDouble(urgentSettings, defaultUrgentThreshold)
val careportalEvent = databaseHelper.getLastCareportalEvent(eventName) val therapyEvent = repository.getLastTherapyRecord(type).blockingGet()
if (careportalEvent != null) { if (therapyEvent is ValueWrapper.Existing) {
warnColors.setColorByAge(view, careportalEvent, warn, urgent) warnColors.setColorByAge(view, therapyEvent.value, warn, urgent)
view?.text = careportalEvent.age(resourceHelper.shortTextMode(), resourceHelper) view?.text = therapyEvent.value.age(resourceHelper.shortTextMode(), resourceHelper)
} else { } else {
view?.text = if (resourceHelper.shortTextMode()) "-" else resourceHelper.gs(R.string.notavailable) view?.text = if (resourceHelper.shortTextMode()) "-" else resourceHelper.gs(R.string.notavailable)
} }

View file

@ -14,6 +14,7 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.GlucoseValueDataPoint import info.nightscout.androidaps.data.GlucoseValueDataPoint
import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.TherapyEventDataPoint
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.GlucoseValue
@ -268,10 +269,12 @@ class GraphData(
} }
// Careportal // Careportal
databaseHelper.getCareportalEventsFromTime(fromTime - 6 * 60 * 60 * 1000, true) // databaseHelper.getCareportalEventsFromTime(fromTime - 6 * 60 * 60 * 1000, true)
repository.compatGetTherapyEventDataFromToTime(fromTime - 6 * 60 * 60 * 1000, endTime).blockingGet()
.map { TherapyEventDataPoint(injector, it) }
.filterTimeframe(fromTime, endTime) .filterTimeframe(fromTime, endTime)
.forEach { .forEach {
it.y = getNearestBg(it.x.toLong()) if (it.y == 0.0) it.y = getNearestBg(it.x.toLong())
filteredTreatments.add(it) filteredTreatments.add(it)
} }

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.general.tidepool.comm package info.nightscout.androidaps.plugins.general.tidepool.comm
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Intervals import info.nightscout.androidaps.data.Intervals
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
@ -23,10 +22,10 @@ import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.max import kotlin.math.max
import kotlin.math.min
@Singleton @Singleton
class UploadChunk @Inject constructor( class UploadChunk @Inject constructor(
private val injector: HasAndroidInjector,
private val sp: SP, private val sp: SP,
private val rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private val aapsLogger: AAPSLogger, private val aapsLogger: AAPSLogger,
@ -38,19 +37,19 @@ class UploadChunk @Inject constructor(
private val dateUtil: DateUtil private val dateUtil: DateUtil
) { ) {
private val MAX_UPLOAD_SIZE = T.days(7).msecs() // don't change this private val maxUploadSize = T.days(7).msecs() // don't change this
fun getNext(session: Session?): String? { fun getNext(session: Session?): String? {
if (session == null) if (session == null)
return null return null
session.start = getLastEnd() session.start = getLastEnd()
session.end = Math.min(session.start + MAX_UPLOAD_SIZE, DateUtil.now()) session.end = min(session.start + maxUploadSize, DateUtil.now())
val result = get(session.start, session.end) val result = get(session.start, session.end)
if (result.length < 3) { if (result.length < 3) {
aapsLogger.debug(LTag.TIDEPOOL, "No records in this time period, setting start to best end time") aapsLogger.debug(LTag.TIDEPOOL, "No records in this time period, setting start to best end time")
setLastEnd(Math.max(session.end, getOldestRecordTimeStamp())) setLastEnd(max(session.end, getOldestRecordTimeStamp()))
} }
return result return result
} }
@ -62,7 +61,7 @@ class UploadChunk @Inject constructor(
aapsLogger.debug(LTag.TIDEPOOL, "End is <= start: " + dateUtil.dateAndTimeString(start) + " " + dateUtil.dateAndTimeString(end)) aapsLogger.debug(LTag.TIDEPOOL, "End is <= start: " + dateUtil.dateAndTimeString(start) + " " + dateUtil.dateAndTimeString(end))
return "" return ""
} }
if (end - start > MAX_UPLOAD_SIZE) { if (end - start > maxUploadSize) {
aapsLogger.debug(LTag.TIDEPOOL, "More than max range - rejecting") aapsLogger.debug(LTag.TIDEPOOL, "More than max range - rejecting")
return "" return ""
} }
@ -128,7 +127,7 @@ class UploadChunk @Inject constructor(
} }
private fun getBloodTests(start: Long, end: Long): List<BloodGlucoseElement> { private fun getBloodTests(start: Long, end: Long): List<BloodGlucoseElement> {
val readings = databaseHelper.getCareportalEvents(start, end, true) val readings = repository.compatGetTherapyEventDataFromToTime(start, end).blockingGet()
val selection = BloodGlucoseElement.fromCareportalEvents(readings) val selection = BloodGlucoseElement.fromCareportalEvents(readings)
if (selection.isNotEmpty()) if (selection.isNotEmpty())
rxBus.send(EventTidepoolStatus("${selection.size} BGs selected for upload")) rxBus.send(EventTidepoolStatus("${selection.size} BGs selected for upload"))
@ -148,22 +147,22 @@ class UploadChunk @Inject constructor(
private fun fromTemporaryBasals(tbrList: Intervals<TemporaryBasal>, start: Long, end: Long): List<BasalElement> { private fun fromTemporaryBasals(tbrList: Intervals<TemporaryBasal>, start: Long, end: Long): List<BasalElement> {
val results = LinkedList<BasalElement>() val results = LinkedList<BasalElement>()
for (tbr in tbrList.list) { for (tbr in tbrList.list) {
if (tbr.date >= start && tbr.date <= end && tbr.durationInMinutes != 0) if (tbr.date in start..end && tbr.durationInMinutes != 0)
results.add(BasalElement(tbr, profileFunction)) results.add(BasalElement(tbr, profileFunction))
} }
return results return results
} }
private fun getBasals(start: Long, end: Long): List<BasalElement> { private fun getBasals(start: Long, end: Long): List<BasalElement> {
val tbrs = treatmentsPlugin.temporaryBasalsFromHistory val temporaryBasals = treatmentsPlugin.temporaryBasalsFromHistory
tbrs.merge() temporaryBasals.merge()
val selection = fromTemporaryBasals(tbrs, start, end) // TODO do not upload running TBR val selection = fromTemporaryBasals(temporaryBasals, start, end) // TODO do not upload running TBR
if (selection.isNotEmpty()) if (selection.isNotEmpty())
rxBus.send(EventTidepoolStatus("${selection.size} TBRs selected for upload")) rxBus.send(EventTidepoolStatus("${selection.size} TBRs selected for upload"))
return selection return selection
} }
fun newInstanceOrNull(ps: ProfileSwitch): ProfileElement? = try { private fun newInstanceOrNull(ps: ProfileSwitch): ProfileElement? = try {
ProfileElement(ps, activePlugin.activePump.serialNumber()) ProfileElement(ps, activePlugin.activePump.serialNumber())
} catch (e: Throwable) { } catch (e: Throwable) {
null null

View file

@ -1,36 +1,36 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose import com.google.gson.annotations.Expose
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
import java.util.* import java.util.*
class BloodGlucoseElement(careportalEvent: CareportalEvent) class BloodGlucoseElement(therapyEvent: TherapyEvent)
: BaseElement(careportalEvent.date, UUID.nameUUIDFromBytes(("AAPS-bg" + careportalEvent.date).toByteArray()).toString()) { : BaseElement(therapyEvent.timestamp, UUID.nameUUIDFromBytes(("AAPS-bg" + therapyEvent.timestamp).toByteArray()).toString()) {
@Expose @Expose
var subType: String = "manual" var subType: String = "manual"
@Expose @Expose
var units: String = "mg/dL" var units: String = "mg/dL"
@Expose @Expose
var value: Int = 0 var value: Int = 0
init { init {
type = "cbg" type = "cbg"
subType = "manual" // TODO subType = "manual" // TODO
val json = if (careportalEvent.json != null) JSONObject(careportalEvent.json) else JSONObject() value = if (therapyEvent.glucose != null && therapyEvent.units != null)
value = Profile.toMgdl(JsonHelper.safeGetDouble(json, "glucose"), JsonHelper.safeGetString(json, "units", Constants.MGDL)).toInt() Profile.toMgdl(therapyEvent.glucose!!, therapyEvent.units).toInt()
else 0
} }
companion object { companion object {
fun fromCareportalEvents(careportalList: List<CareportalEvent>): List<BloodGlucoseElement> { fun fromCareportalEvents(careportalList: List<TherapyEvent>): List<BloodGlucoseElement> {
val results = LinkedList<BloodGlucoseElement>() val results = LinkedList<BloodGlucoseElement>()
for (bt in careportalList) { for (bt in careportalList) {
if (bt.eventType == CareportalEvent.MBG || bt.eventType == CareportalEvent.BGCHECK) { if (bt.type == TherapyEvent.Type.NS_MBG || bt.type == TherapyEvent.Type.FINGER_STICK_BG_VALUE) {
val bge = BloodGlucoseElement(bt) val bge = BloodGlucoseElement(bt)
if (bge.value > 0) if (bge.value > 0)
results.add(BloodGlucoseElement(bt)) results.add(BloodGlucoseElement(bt))

View file

@ -16,10 +16,10 @@ import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.interfaces.end import info.nightscout.androidaps.database.interfaces.end
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TDD import info.nightscout.androidaps.db.TDD
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.*
@ -545,7 +545,7 @@ class ActionStringHandler @Inject constructor(
private fun doECarbs(carbs: Int, time: Long, duration: Int) { private fun doECarbs(carbs: Int, time: Long, duration: Int) {
if (carbs > 0) { if (carbs > 0) {
if (duration == 0) { if (duration == 0) {
carbsGenerator.createCarb(carbs, time, CareportalEvent.CARBCORRECTION, "watch") carbsGenerator.createCarb(carbs, time, TherapyEvent.Type.CARBS_CORRECTION.text, "watch")
} else { } else {
carbsGenerator.generateCarbs(carbs, time, duration, "watch eCarbs") carbsGenerator.generateCarbs(carbs, time, duration, "watch eCarbs")
} }

View file

@ -4,7 +4,8 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface
@ -17,6 +18,7 @@ import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.percentile import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.percentile
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.extensions.isEvent5minBack
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONException import org.json.JSONException
@ -34,7 +36,8 @@ open class SensitivityAAPSPlugin @Inject constructor(
sp: SP?, sp: SP?,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val databaseHelper: DatabaseHelperInterface private val databaseHelper: DatabaseHelperInterface,
private val repository: AppRepository
) : AbstractSensitivityPlugin(PluginDescription() ) : AbstractSensitivityPlugin(PluginDescription()
.mainType(PluginType.SENSITIVITY) .mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon) .pluginIcon(R.drawable.ic_generic_icon)
@ -67,7 +70,7 @@ open class SensitivityAAPSPlugin @Inject constructor(
aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + plugin.lastDataTime()) aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + plugin.lastDataTime())
return AutosensResult() return AutosensResult()
} }
val siteChanges = databaseHelper.getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true) val siteChanges = repository.getTherapyEventDataFromTime(fromTime, TherapyEvent.Type.CANNULA_CHANGE, true).blockingGet()
val profileSwitches = databaseHelper.getProfileSwitchEventsFromTime(fromTime, true) val profileSwitches = databaseHelper.getProfileSwitchEventsFromTime(fromTime, true)
val deviationsArray: MutableList<Double> = ArrayList() val deviationsArray: MutableList<Double> = ArrayList()
var pastSensitivity = "" var pastSensitivity = ""
@ -84,7 +87,7 @@ open class SensitivityAAPSPlugin @Inject constructor(
} }
// reset deviations after site change // reset deviations after site change
if (CareportalEvent(injector).isEvent5minBack(siteChanges, autosensData.time)) { if (isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear() deviationsArray.clear()
pastSensitivity += "(SITECHANGE)" pastSensitivity += "(SITECHANGE)"
} }

View file

@ -4,7 +4,8 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface
@ -18,6 +19,7 @@ import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.percentile import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.percentile
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.extensions.isEvent5minBack
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONException import org.json.JSONException
@ -35,7 +37,8 @@ open class SensitivityOref1Plugin @Inject constructor(
sp: SP?, sp: SP?,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val databaseHelper: DatabaseHelperInterface private val databaseHelper: DatabaseHelperInterface,
private val repository: AppRepository
) : AbstractSensitivityPlugin(PluginDescription() ) : AbstractSensitivityPlugin(PluginDescription()
.mainType(PluginType.SENSITIVITY) .mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon) .pluginIcon(R.drawable.ic_generic_icon)
@ -68,7 +71,7 @@ open class SensitivityOref1Plugin @Inject constructor(
aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + plugin.lastDataTime()) aapsLogger.debug(LTag.AUTOSENS, "No autosens data available. toTime: " + dateUtil.dateAndTimeString(toTime) + " lastDataTime: " + plugin.lastDataTime())
return AutosensResult() return AutosensResult()
} }
val siteChanges = databaseHelper.getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true) val siteChanges = repository.getTherapyEventDataFromTime(fromTime, TherapyEvent.Type.CANNULA_CHANGE, true).blockingGet()
val profileSwitches = databaseHelper.getProfileSwitchEventsFromTime(fromTime, true) val profileSwitches = databaseHelper.getProfileSwitchEventsFromTime(fromTime, true)
//[0] = 8 hour //[0] = 8 hour
@ -100,7 +103,7 @@ open class SensitivityOref1Plugin @Inject constructor(
var pastSensitivity = pastSensitivityArray[hourSegment] var pastSensitivity = pastSensitivityArray[hourSegment]
// reset deviations after site change // reset deviations after site change
if (CareportalEvent(injector).isEvent5minBack(siteChanges, autosensData.time)) { if (isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear() deviationsArray.clear()
pastSensitivity += "(SITECHANGE)" pastSensitivity += "(SITECHANGE)"
} }

View file

@ -5,7 +5,8 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface
@ -17,6 +18,7 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.extensions.isEvent5minBack
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONException import org.json.JSONException
@ -33,7 +35,8 @@ open class SensitivityWeightedAveragePlugin @Inject constructor(
sp: SP, sp: SP,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val databaseHelper: DatabaseHelperInterface private val databaseHelper: DatabaseHelperInterface,
private val repository: AppRepository
) : AbstractSensitivityPlugin(PluginDescription() ) : AbstractSensitivityPlugin(PluginDescription()
.mainType(PluginType.SENSITIVITY) .mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon) .pluginIcon(R.drawable.ic_generic_icon)
@ -66,7 +69,7 @@ open class SensitivityWeightedAveragePlugin @Inject constructor(
aapsLogger.debug(LTag.AUTOSENS, "No profile available") aapsLogger.debug(LTag.AUTOSENS, "No profile available")
return AutosensResult() return AutosensResult()
} }
val siteChanges = databaseHelper.getCareportalEventsFromTime(fromTime, CareportalEvent.SITECHANGE, true) val siteChanges = repository.getTherapyEventDataFromTime(fromTime, TherapyEvent.Type.CANNULA_CHANGE, true).blockingGet()
val profileSwitches = databaseHelper.getProfileSwitchEventsFromTime(fromTime, true) val profileSwitches = databaseHelper.getProfileSwitchEventsFromTime(fromTime, true)
var pastSensitivity = "" var pastSensitivity = ""
var index = 0 var index = 0
@ -87,7 +90,7 @@ open class SensitivityWeightedAveragePlugin @Inject constructor(
} }
// reset deviations after site change // reset deviations after site change
if (CareportalEvent(injector).isEvent5minBack(siteChanges, autosensData.time)) { if (isEvent5minBack(siteChanges, autosensData.time)) {
data.clear() data.clear()
pastSensitivity += "(SITECHANGE)" pastSensitivity += "(SITECHANGE)"
} }

View file

@ -8,10 +8,10 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
@ -26,8 +26,6 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign import io.reactivex.rxkotlin.plusAssign
import org.json.JSONException
import org.json.JSONObject
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -36,8 +34,7 @@ import javax.inject.Singleton
class EversensePlugin @Inject constructor( class EversensePlugin @Inject constructor(
injector: HasAndroidInjector, injector: HasAndroidInjector,
resourceHelper: ResourceHelper, resourceHelper: ResourceHelper,
aapsLogger: AAPSLogger, aapsLogger: AAPSLogger
private val databaseHelper: DatabaseHelperInterface
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.BGSOURCE) .mainType(PluginType.BGSOURCE)
.fragmentClass(BGSourceFragment::class.java.name) .fragmentClass(BGSourceFragment::class.java.name)
@ -139,20 +136,18 @@ class EversensePlugin @Inject constructor(
aapsLogger.debug(LTag.BGSOURCE, "calibrationTimestamps" + Arrays.toString(calibrationTimestamps)) aapsLogger.debug(LTag.BGSOURCE, "calibrationTimestamps" + Arrays.toString(calibrationTimestamps))
aapsLogger.debug(LTag.BGSOURCE, "calibrationRecordNumbers" + Arrays.toString(calibrationRecordNumbers)) aapsLogger.debug(LTag.BGSOURCE, "calibrationRecordNumbers" + Arrays.toString(calibrationRecordNumbers))
for (i in calibrationGlucoseLevels.indices) { for (i in calibrationGlucoseLevels.indices) {
try { eversensePlugin.disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction(
if (eversensePlugin.databaseHelper.getCareportalEventFromTimestamp(calibrationTimestamps[i]) == null) { timestamp = calibrationTimestamps[i],
val data = JSONObject() type = TherapyEvent.Type.FINGER_STICK_BG_VALUE,
data.put("enteredBy", "AndroidAPS-Eversense") glucose = calibrationGlucoseLevels[i].toDouble(),
data.put("created_at", DateUtil.toISOString(calibrationTimestamps[i])) glucoseType = TherapyEvent.MeterType.FINGER,
data.put("eventType", CareportalEvent.BGCHECK) units = Constants.MGDL,
data.put("glucoseType", "Finger") enteredBy = "AndroidAPS-Eversense"
data.put("glucose", calibrationGlucoseLevels[i]) )).subscribe({ result ->
data.put("units", Constants.MGDL) result.inserted.forEach { nsUpload.uploadEvent(it) }
nsUpload.uploadCareportalEntryToNS(data, calibrationTimestamps[i]) }, {
} aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it)
} catch (e: JSONException) { })
aapsLogger.error("Unhandled exception", e)
}
} }
} }
} }

View file

@ -4,7 +4,7 @@ import android.content.Context
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
@ -14,6 +14,7 @@ import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.roundToInt
@Singleton @Singleton
class CarbsGenerator @Inject constructor( class CarbsGenerator @Inject constructor(
@ -28,9 +29,9 @@ class CarbsGenerator @Inject constructor(
val ticks = duration * 4 //duration guaranteed to be integer greater zero val ticks = duration * 4 //duration guaranteed to be integer greater zero
for (i in 0 until ticks) { for (i in 0 until ticks) {
val carbTime = startTime + i * 15 * 60 * 1000 val carbTime = startTime + i * 15 * 60 * 1000
val smallCarbAmount = Math.round(1.0 * remainingCarbs / (ticks - i)).toInt() //on last iteration (ticks-i) is 1 -> smallCarbAmount == remainingCarbs val smallCarbAmount = (1.0 * remainingCarbs / (ticks - i)).roundToInt() //on last iteration (ticks-i) is 1 -> smallCarbAmount == remainingCarbs
remainingCarbs -= smallCarbAmount.toLong() remainingCarbs -= smallCarbAmount.toLong()
if (smallCarbAmount > 0) createCarb(smallCarbAmount, carbTime, CareportalEvent.MEALBOLUS, notes) if (smallCarbAmount > 0) createCarb(smallCarbAmount, carbTime, TherapyEvent.Type.MEAL_BOLUS.text, notes)
} }
} }

View file

@ -9,32 +9,42 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.transactions.InvalidateAAPSStartedTherapyEventTransaction
import info.nightscout.androidaps.database.transactions.InvalidateTherapyEventTransaction
import info.nightscout.androidaps.databinding.TreatmentsCareportalFragmentBinding import info.nightscout.androidaps.databinding.TreatmentsCareportalFragmentBinding
import info.nightscout.androidaps.databinding.TreatmentsCareportalItemBinding import info.nightscout.androidaps.databinding.TreatmentsCareportalItemBinding
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.events.EventTherapyEventChange
import info.nightscout.androidaps.events.EventCareportalEventChange import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.CareportalEventsViewHolder import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.TherapyEventsViewHolder
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.Translator import info.nightscout.androidaps.utils.Translator
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.Completable
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import io.reactivex.rxkotlin.subscribeBy
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
class TreatmentsCareportalFragment : DaggerFragment() { class TreatmentsCareportalFragment : DaggerFragment() {
private val disposable = CompositeDisposable() @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@ -45,9 +55,13 @@ class TreatmentsCareportalFragment : DaggerFragment() {
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var buildHelper: BuildHelper @Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var repository: AppRepository
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
private val disposable = CompositeDisposable()
private val millsToThePast = T.days(30).msecs()
private var _binding: TreatmentsCareportalFragmentBinding? = null private var _binding: TreatmentsCareportalFragmentBinding? = null
// This property is only valid between onCreateView and // This property is only valid between onCreateView and
@ -61,12 +75,17 @@ class TreatmentsCareportalFragment : DaggerFragment() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.recyclerview.setHasFixedSize(true) binding.recyclerview.setHasFixedSize(true)
binding.recyclerview.layoutManager = LinearLayoutManager(view.context) binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
binding.recyclerview.adapter = RecyclerViewAdapter(databaseHelper.getCareportalEvents(false))
binding.refreshFromNightscout.setOnClickListener { binding.refreshFromNightscout.setOnClickListener {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal), resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal), resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", Runnable {
uel.log("CAREPORTAL NS REFRESH") uel.log("CAREPORTAL NS REFRESH")
databaseHelper.resetCareportalEvents() disposable += Completable.fromAction { repository.deleteAllTherapyEventsEntries() }
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.main)
.subscribeBy(
onError = { aapsLogger.error("Error removing entries", it) },
onComplete = { rxBus.send(EventTherapyEventChange()) }
)
rxBus.send(EventNSClientRestart()) rxBus.send(EventNSClientRestart())
}) })
} }
@ -75,34 +94,58 @@ class TreatmentsCareportalFragment : DaggerFragment() {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal), resourceHelper.gs(R.string.careportal_removestartedevents), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal), resourceHelper.gs(R.string.careportal_removestartedevents), Runnable {
uel.log("REMOVED RESTART EVENTS") uel.log("REMOVED RESTART EVENTS")
val events = databaseHelper.getCareportalEvents(false) // val events = databaseHelper.getCareportalEvents(false)
for (i in events.indices) { repository.runTransactionForResult(InvalidateAAPSStartedTherapyEventTransaction())
val careportalEvent = events[i] .subscribe({ result ->
if (careportalEvent.json.contains(resourceHelper.gs(R.string.androidaps_start))) { result.invalidated.forEach { event ->
if (NSUpload.isIdValid(careportalEvent._id)) if (NSUpload.isIdValid(event.interfaceIDs.nightscoutId))
nsUpload.removeCareportalEntryFromNS(careportalEvent._id) nsUpload.removeCareportalEntryFromNS(event.interfaceIDs.nightscoutId)
else else
uploadQueue.removeID("dbAdd", careportalEvent._id) uploadQueue.removeID("dbAdd", event.timestamp.toString())
databaseHelper.delete(careportalEvent) }
} }, {
} aapsLogger.error(LTag.BGSOURCE, "Error while invalidating therapy event", it)
})
}, null) }, null)
} }
} }
val nsUploadOnly = sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode() val nsUploadOnly = sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode()
if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.GONE if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.GONE
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
rxBus.send(EventTreatmentUpdateGui())
}
}
fun swapAdapter() {
val now = System.currentTimeMillis()
if (binding.showInvalidated.isChecked)
repository
.getTherapyEventDataIncludingInvalidFromTime(now - millsToThePast, false)
.observeOn(aapsSchedulers.main)
.subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) }
else
repository
.getTherapyEventDataFromTime(now - millsToThePast, false)
.observeOn(aapsSchedulers.main)
.subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) }
} }
@Synchronized @Synchronized
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
swapAdapter()
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventCareportalEventChange::class.java) .toObservable(EventTherapyEventChange::class.java)
.observeOn(aapsSchedulers.main) .observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException) .debounce(1L, TimeUnit.SECONDS)
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
) )
updateGui() disposable += rxBus
.toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above
.observeOn(aapsSchedulers.io)
.debounce(1L, TimeUnit.SECONDS)
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
} }
@Synchronized @Synchronized
@ -114,53 +157,53 @@ class TreatmentsCareportalFragment : DaggerFragment() {
@Synchronized @Synchronized
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
binding.recyclerview.adapter = null // avoid leaks
_binding = null _binding = null
} }
private fun updateGui() { inner class RecyclerViewAdapter internal constructor(private var list: List<TherapyEvent>) : RecyclerView.Adapter<TherapyEventsViewHolder>() {
if (_binding == null) return
binding.recyclerview.swapAdapter(RecyclerViewAdapter(databaseHelper.getCareportalEvents(false)), false)
}
inner class RecyclerViewAdapter internal constructor(private var careportalEventList: List<CareportalEvent>) : RecyclerView.Adapter<CareportalEventsViewHolder>() { override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): TherapyEventsViewHolder {
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): CareportalEventsViewHolder {
val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.treatments_careportal_item, viewGroup, false) val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.treatments_careportal_item, viewGroup, false)
return CareportalEventsViewHolder(v) return TherapyEventsViewHolder(v)
} }
override fun onBindViewHolder(holder: CareportalEventsViewHolder, position: Int) { override fun onBindViewHolder(holder: TherapyEventsViewHolder, position: Int) {
val careportalEvent = careportalEventList[position] val therapyEvent = list[position]
holder.binding.ns.visibility = if (NSUpload.isIdValid(careportalEvent._id)) View.VISIBLE else View.GONE holder.binding.ns.visibility = (therapyEvent.interfaceIDs.nightscoutId != null).toVisibility()
holder.binding.date.text = dateUtil.dateAndTimeString(careportalEvent.date) holder.binding.invalid.visibility = therapyEvent.isValid.not().toVisibility()
holder.binding.duration.text = if (careportalEvent.durationInMsec() == 0L) "" else DateUtil.niceTimeScalar(careportalEvent.durationInMsec(), resourceHelper) holder.binding.date.text = dateUtil.dateAndTimeString(therapyEvent.timestamp)
holder.binding.note.text = careportalEvent.notes holder.binding.duration.text = if (therapyEvent.duration == 0L) "" else DateUtil.niceTimeScalar(therapyEvent.duration, resourceHelper)
holder.binding.type.text = translator.translate(careportalEvent.eventType) holder.binding.note.text = therapyEvent.note
holder.binding.remove.tag = careportalEvent holder.binding.type.text = translator.translate(therapyEvent.type.text)
holder.binding.remove.tag = therapyEvent
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
return careportalEventList.size return list.size
} }
inner class CareportalEventsViewHolder(view: View) : RecyclerView.ViewHolder(view) { inner class TherapyEventsViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val binding = TreatmentsCareportalItemBinding.bind(view) val binding = TreatmentsCareportalItemBinding.bind(view)
init { init {
binding.remove.setOnClickListener { v: View -> binding.remove.setOnClickListener { v: View ->
val careportalEvent = v.tag as CareportalEvent val therapyEvent = v.tag as TherapyEvent
activity?.let { activity -> activity?.let { activity ->
val text = resourceHelper.gs(R.string.eventtype) + ": " + translator.translate(careportalEvent.eventType) + "\n" + val text = resourceHelper.gs(R.string.eventtype) + ": " + translator.translate(therapyEvent.type.text) + "\n" +
resourceHelper.gs(R.string.notes_label) + ": " + careportalEvent.notes + "\n" + resourceHelper.gs(R.string.notes_label) + ": " + (therapyEvent.note ?: "") + "\n" +
resourceHelper.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(careportalEvent.date) resourceHelper.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(therapyEvent.timestamp)
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable {
uel.log("REMOVED CAREP", text) uel.log("REMOVED CAREPORTAL", text)
if (NSUpload.isIdValid(careportalEvent._id)) disposable += repository.runTransactionForResult(InvalidateTherapyEventTransaction(therapyEvent.id))
nsUpload.removeCareportalEntryFromNS(careportalEvent._id) .subscribe({
else val id = therapyEvent.interfaceIDs.nightscoutId
uploadQueue.removeID("dbAdd", careportalEvent._id) if (NSUpload.isIdValid(id)) nsUpload.removeCareportalEntryFromNS(id)
databaseHelper.delete(careportalEvent) else uploadQueue.removeID("dbAdd", therapyEvent.timestamp.toString())
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while invalidating therapy event", it)
})
}, null) }, null)
} }
} }

View file

@ -11,7 +11,7 @@ import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.events.EventRefreshOverview import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.*
@ -336,7 +336,7 @@ class BolusWizard @Inject constructor(
val confirmMessage = confirmMessageAfterConstraints(advisor = true) val confirmMessage = confirmMessageAfterConstraints(advisor = true)
OKDialog.showConfirmation(ctx, resourceHelper.gs(R.string.boluswizard), confirmMessage, { OKDialog.showConfirmation(ctx, resourceHelper.gs(R.string.boluswizard), confirmMessage, {
DetailedBolusInfo().apply { DetailedBolusInfo().apply {
eventType = CareportalEvent.CORRECTIONBOLUS eventType = TherapyEvent.Type.CORRECTION_BOLUS.text
insulin = insulinAfterConstraints insulin = insulinAfterConstraints
carbs = 0.0 carbs = 0.0
context = ctx context = ctx
@ -400,7 +400,7 @@ class BolusWizard @Inject constructor(
} }
} }
DetailedBolusInfo().apply { DetailedBolusInfo().apply {
eventType = CareportalEvent.BOLUSWIZARD eventType = TherapyEvent.Type.BOLUS_WIZARD.text
insulin = insulinAfterConstraints insulin = insulinAfterConstraints
carbs = this@BolusWizard.carbs.toDouble() carbs = this@BolusWizard.carbs.toDouble()
context = ctx context = ctx

View file

@ -1,4 +1,5 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -14,7 +15,7 @@
android:id="@+id/refresh_from_nightscout" android:id="@+id/refresh_from_nightscout"
style="?android:attr/buttonStyle" style="?android:attr/buttonStyle"
android:layout_width="0px" android:layout_width="0px"
android:layout_height="fill_parent" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:layout_weight="1" android:layout_weight="1"
android:drawableStart="@drawable/ic_refresh" android:drawableStart="@drawable/ic_refresh"
@ -24,12 +25,28 @@
android:id="@+id/remove_androidaps_started_events" android:id="@+id/remove_androidaps_started_events"
style="?android:attr/buttonStyle" style="?android:attr/buttonStyle"
android:layout_width="0px" android:layout_width="0px"
android:layout_height="fill_parent" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:layout_weight="1" android:layout_weight="1"
android:drawableStart="@drawable/ic_remove" android:drawableStart="@drawable/ic_remove"
android:text="@string/careportal_removestartedevents" /> android:text="@string/careportal_removestartedevents" />
<CheckBox
android:id="@+id/show_invalidated"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:checked="false"
android:paddingEnd="5dp"
tools:ignore="RtlSymmetry" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/show_calculation"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout> </LinearLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView

View file

@ -38,14 +38,6 @@
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
tools:ignore="HardcodedText,RtlSymmetry" /> tools:ignore="HardcodedText,RtlSymmetry" />
<TextView
android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingEnd="10dp"
tools:ignore="RtlSymmetry" />
<TextView <TextView
android:id="@+id/type" android:id="@+id/type"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -72,6 +64,15 @@
android:textColor="@color/colorSetTempButton" android:textColor="@color/colorSetTempButton"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
<TextView
android:id="@+id/invalid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:text="@string/invalid"
android:textColor="@android:color/holo_red_light" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
@ -79,16 +80,24 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="horizontal"> android:orientation="horizontal">
<TextView
android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingStart="10dp"
android:paddingEnd="10dp"
tools:ignore="RtlSymmetry" />
<TextView <TextView
android:id="@+id/note" android:id="@+id/note"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_weight="1" android:layout_weight="1"
android:paddingStart="10dp"
android:paddingEnd="10dp" android:paddingEnd="10dp"
android:text="Activity" android:text="Activity"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText,RtlSymmetry" />
<TextView <TextView
android:id="@+id/remove" android:id="@+id/remove"
@ -104,10 +113,10 @@
<View <View
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="2dip" android:layout_height="2dip"
android:layout_marginBottom="5dp"
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginBottom="5dp"
android:background="@color/list_delimiter" /> android:background="@color/list_delimiter" />
</LinearLayout> </LinearLayout>

View file

@ -42,8 +42,6 @@ import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.anyString
import org.powermock.core.classloader.annotations.PrepareForTest import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner import org.powermock.modules.junit4.PowerMockRunner
import java.util.* import java.util.*
@ -144,7 +142,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
comboPlugin = ComboPlugin(injector, aapsLogger, rxBus, resourceHelper, profileFunction, treatmentsInterface, sp, commandQueue, context, databaseHelper) comboPlugin = ComboPlugin(injector, aapsLogger, rxBus, resourceHelper, profileFunction, treatmentsInterface, sp, commandQueue, context, databaseHelper)
danaRPlugin = DanaRPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, activePlugin, sp, commandQueue, danaPump, dateUtil, fabricPrivacy) danaRPlugin = DanaRPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, activePlugin, sp, commandQueue, danaPump, dateUtil, fabricPrivacy)
danaRSPlugin = DanaRSPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, activePluginProvider, sp, commandQueue, danaPump, detailedBolusInfoStorage, fabricPrivacy, dateUtil) danaRSPlugin = DanaRSPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, activePluginProvider, sp, commandQueue, danaPump, detailedBolusInfoStorage, fabricPrivacy, dateUtil)
insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsInterface, sp, commandQueue, profileFunction, nsUpload, context, uploadQueue, Config(), dateUtil, databaseHelper) insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsInterface, sp, commandQueue, profileFunction, nsUpload, context, uploadQueue, Config(), dateUtil, databaseHelper, repository)
openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsInterface, iobCobCalculatorPlugin, hardLimits, profiler, sp, dateUtil, repository) openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsInterface, iobCobCalculatorPlugin, hardLimits, profiler, sp, dateUtil, repository)
openAPSAMAPlugin = OpenAPSAMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsInterface, iobCobCalculatorPlugin, hardLimits, profiler, fabricPrivacy, dateUtil, repository) openAPSAMAPlugin = OpenAPSAMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsInterface, iobCobCalculatorPlugin, hardLimits, profiler, fabricPrivacy, dateUtil, repository)
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, BuildHelper(Config(), loggerUtils), treatmentsInterface, Config()) safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, BuildHelper(Config(), loggerUtils), treatmentsInterface, Config())
@ -184,7 +182,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
Assert.assertEquals(false, c.value()) Assert.assertEquals(false, c.value())
`when`(sp.getString(R.string.key_aps_mode, "open")).thenReturn("open") `when`(sp.getString(R.string.key_aps_mode, "open")).thenReturn("open")
c = constraintChecker.isClosedLoopAllowed() c = constraintChecker.isClosedLoopAllowed()
Assert.assertTrue(c.reasonList[0].toString().contains("Closed loop mode disabled in preferences")) // Safety & Objectives Assert.assertTrue(c.reasonList[0].contains("Closed loop mode disabled in preferences")) // Safety & Objectives
// Assert.assertEquals(3, c.reasonList.size) // 2x Safety & Objectives // Assert.assertEquals(3, c.reasonList.size) // 2x Safety & Objectives
Assert.assertEquals(false, c.value()) Assert.assertEquals(false, c.value())
} }

View file

@ -7,7 +7,12 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.TestBase
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.PumpDescription
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
@ -15,6 +20,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorP
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -30,7 +36,7 @@ import org.powermock.modules.junit4.PowerMockRunner
@RunWith(PowerMockRunner::class) @RunWith(PowerMockRunner::class)
@PrepareForTest( @PrepareForTest(
ConstraintChecker::class, VirtualPumpPlugin::class, FabricPrivacy::class, ReceiverStatusStore::class, ConstraintChecker::class, VirtualPumpPlugin::class, FabricPrivacy::class, ReceiverStatusStore::class,
IobCobCalculatorPlugin::class) IobCobCalculatorPlugin::class, AppRepository::class)
class LoopPluginTest : TestBase() { class LoopPluginTest : TestBase() {
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
@ -48,14 +54,15 @@ class LoopPluginTest : TestBase() {
@Mock lateinit var receiverStatusStore: ReceiverStatusStore @Mock lateinit var receiverStatusStore: ReceiverStatusStore
@Mock lateinit var nsUpload: NSUpload @Mock lateinit var nsUpload: NSUpload
@Mock lateinit var notificationManager: NotificationManager @Mock lateinit var notificationManager: NotificationManager
@Mock lateinit var databaseHelper: DatabaseHelperInterface @Mock lateinit var repository: AppRepository
@Mock lateinit var dateUtil: DateUtil
private lateinit var loopPlugin: LoopPlugin private lateinit var loopPlugin: LoopPlugin
val injector = HasAndroidInjector { AndroidInjector { } } val injector = HasAndroidInjector { AndroidInjector { } }
@Before fun prepareMock() { @Before fun prepareMock() {
loopPlugin = LoopPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, Config(), constraintChecker, resourceHelper, profileFunction, context, commandQueue, activePlugin, treatmentsPlugin, virtualPumpPlugin, iobCobCalculatorPlugin, receiverStatusStore, fabricPrivacy, nsUpload, databaseHelper) loopPlugin = LoopPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, Config(), constraintChecker, resourceHelper, profileFunction, context, commandQueue, activePlugin, treatmentsPlugin, virtualPumpPlugin, iobCobCalculatorPlugin, receiverStatusStore, fabricPrivacy, nsUpload, dateUtil, repository)
`when`(activePlugin.activePump).thenReturn(virtualPumpPlugin) `when`(activePlugin.activePump).thenReturn(virtualPumpPlugin)
`when`(context.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(notificationManager) `when`(context.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(notificationManager)
} }

View file

@ -17,4 +17,5 @@ android {
dependencies { dependencies {
implementation project(':core') implementation project(':core')
implementation project(':database')
} }

View file

@ -6,6 +6,7 @@ import android.os.SystemClock;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.joda.time.DateTime;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.ArrayList; import java.util.ArrayList;
@ -24,7 +25,7 @@ import info.nightscout.androidaps.combo.R;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.database.entities.TherapyEvent;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TDD; import info.nightscout.androidaps.db.TDD;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
@ -996,8 +997,8 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
double pumpBasalRate = state.tbrActive double pumpBasalRate = state.tbrActive
? Math.round(state.basalRate * 100 / state.tbrPercent * 100) / 100d ? Math.round(state.basalRate * 100 / state.tbrPercent * 100) / 100d
: state.basalRate; : state.basalRate;
int pumpHour = new Date(state.pumpTime).getHours(); int pumpHour = new DateTime(state.pumpTime).getHourOfDay();
int phoneHour = new Date().getHours(); int phoneHour = DateTime.now().getHourOfDay();
if (pumpHour != phoneHour) { if (pumpHour != phoneHour) {
// only check if clocks are close // only check if clocks are close
return; return;
@ -1157,7 +1158,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
dbi.pumpId = dbi.date; dbi.pumpId = dbi.date;
dbi.source = Source.PUMP; dbi.source = Source.PUMP;
dbi.insulin = pumpBolus.amount; dbi.insulin = pumpBolus.amount;
dbi.eventType = CareportalEvent.CORRECTIONBOLUS; dbi.eventType = TherapyEvent.Type.CORRECTION_BOLUS.getText();
if (treatmentsPlugin.addToHistoryTreatment(dbi, true)) { if (treatmentsPlugin.addToHistoryTreatment(dbi, true)) {
updated = true; updated = true;
} }

View file

@ -5,25 +5,32 @@ import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.data.GlucoseValueDataPoint import info.nightscout.androidaps.data.GlucoseValueDataPoint
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.db.* import info.nightscout.androidaps.data.TherapyEventDataPoint
import info.nightscout.androidaps.db.ExtendedBolus
import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.db.TemporaryBasal
import info.nightscout.androidaps.db.Treatment
import info.nightscout.androidaps.interfaces.ProfileStore import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.plugins.aps.loop.APSResult import info.nightscout.androidaps.plugins.aps.loop.APSResult
import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
@Module @Module
@Suppress("unused") @Suppress("unused")
abstract class CoreDataClassesModule { abstract class CoreDataClassesModule {
@ContributesAndroidInjector abstract fun nsMbgInjector(): NSMbg
@ContributesAndroidInjector abstract fun pumpEnactResultInjector(): PumpEnactResult @ContributesAndroidInjector abstract fun pumpEnactResultInjector(): PumpEnactResult
@ContributesAndroidInjector abstract fun apsResultInjector(): APSResult @ContributesAndroidInjector abstract fun apsResultInjector(): APSResult
@ContributesAndroidInjector abstract fun autosensDataInjector(): AutosensData @ContributesAndroidInjector abstract fun autosensDataInjector(): AutosensData
@ContributesAndroidInjector abstract fun profileInjector(): Profile @ContributesAndroidInjector abstract fun profileInjector(): Profile
@ContributesAndroidInjector abstract fun profileStoreInjector(): ProfileStore @ContributesAndroidInjector abstract fun profileStoreInjector(): ProfileStore
@ContributesAndroidInjector abstract fun glucoseValueDataPointInjector(): GlucoseValueDataPoint
@ContributesAndroidInjector abstract fun treatmentInjector(): Treatment @ContributesAndroidInjector abstract fun treatmentInjector(): Treatment
@ContributesAndroidInjector abstract fun profileSwitchInjector(): ProfileSwitch @ContributesAndroidInjector abstract fun profileSwitchInjector(): ProfileSwitch
@ContributesAndroidInjector abstract fun temporaryBasalInjector(): TemporaryBasal @ContributesAndroidInjector abstract fun temporaryBasalInjector(): TemporaryBasal
@ContributesAndroidInjector abstract fun careportalEventInjector(): CareportalEvent
@ContributesAndroidInjector abstract fun extendedBolusInjector(): ExtendedBolus @ContributesAndroidInjector abstract fun extendedBolusInjector(): ExtendedBolus
@ContributesAndroidInjector abstract fun glucoseValueDataPointInjector(): GlucoseValueDataPoint
@ContributesAndroidInjector abstract fun therapyEventDataPointInjector(): TherapyEventDataPoint
} }

View file

@ -6,7 +6,7 @@ import org.json.JSONObject;
import java.util.Date; import java.util.Date;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.database.entities.TherapyEvent;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
/** /**
@ -16,7 +16,7 @@ import info.nightscout.androidaps.db.Source;
public class DetailedBolusInfo { public class DetailedBolusInfo {
public long date = System.currentTimeMillis(); public long date = System.currentTimeMillis();
public long lastKnownBolusTime; public long lastKnownBolusTime;
public String eventType = CareportalEvent.MEALBOLUS; public String eventType = TherapyEvent.Type.MEAL_BOLUS.getText();
public double insulin = 0; public double insulin = 0;
public double carbs = 0; public double carbs = 0;
public int source = Source.NONE; public int source = Source.NONE;

View file

@ -0,0 +1,104 @@
package info.nightscout.androidaps.data
import android.graphics.Color
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.interfaces.Interval
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.Translator
import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
class TherapyEventDataPoint @Inject constructor(
val injector: HasAndroidInjector,
val data: TherapyEvent
) : DataPointWithLabelInterface, Interval {
@Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var translator: Translator
private var yValue = 0.0
init {
injector.androidInjector().inject(this)
}
override fun getX(): Double {
return data.timestamp.toDouble()
}
override fun getY(): Double {
val units = profileFunction.getUnits()
if (data.type == TherapyEvent.Type.NS_MBG) return Profile.fromMgdlToUnits(data.glucose!!, units)
if (data.glucose != null && data.glucose != 0.0) {
var mmol = 0.0
var mgdl = 0.0
if (units == Constants.MGDL) {
mgdl = data.glucose!!
mmol = data.glucose!! * Constants.MGDL_TO_MMOLL
}
if (units == Constants.MMOL) {
mmol = data.glucose!!
mgdl = data.glucose!! * Constants.MMOLL_TO_MGDL
}
return Profile.toUnits(mgdl, mmol, units)
}
return yValue
}
override fun setY(y: Double) {
yValue = y
}
override fun getLabel(): String? =
if (data.note != null) data.note
else translator.translate(data.type.text)
override fun getDuration(): Long = end() - start()
override fun getShape(): PointsWithLabelGraphSeries.Shape =
when {
data.type == TherapyEvent.Type.NS_MBG -> PointsWithLabelGraphSeries.Shape.MBG
data.type == TherapyEvent.Type.FINGER_STICK_BG_VALUE -> PointsWithLabelGraphSeries.Shape.BGCHECK
data.type == TherapyEvent.Type.ANNOUNCEMENT -> PointsWithLabelGraphSeries.Shape.ANNOUNCEMENT
data.type == TherapyEvent.Type.APS_OFFLINE -> PointsWithLabelGraphSeries.Shape.OPENAPSOFFLINE
data.type == TherapyEvent.Type.EXERCISE -> PointsWithLabelGraphSeries.Shape.EXERCISE
duration > 0 -> PointsWithLabelGraphSeries.Shape.GENERALWITHDURATION
else -> PointsWithLabelGraphSeries.Shape.GENERAL
}
override fun getSize(): Float = if (resourceHelper.gb(R.bool.isTablet)) 12.0f else 10.0f
override fun getColor(): Int =
when (data.type) {
TherapyEvent.Type.ANNOUNCEMENT -> resourceHelper.gc(R.color.notificationAnnouncement)
TherapyEvent.Type.NS_MBG -> Color.RED
TherapyEvent.Type.FINGER_STICK_BG_VALUE -> Color.RED
TherapyEvent.Type.EXERCISE -> Color.BLUE
TherapyEvent.Type.APS_OFFLINE -> Color.GRAY and -0x7f000001
else -> Color.GRAY
}
// Interval interface
private var cutEnd: Long? = null
override fun durationInMsec(): Long = data.duration
override fun start(): Long = data.timestamp
override fun originalEnd(): Long = data.timestamp + durationInMsec()
override fun end(): Long = cutEnd ?: originalEnd()
override fun cutEndTo(end: Long) {
cutEnd = end
}
override fun match(time: Long): Boolean = start() <= time && end() >= time
override fun before(time: Long): Boolean = end() < time
override fun after(time: Long): Boolean = start() > time
override val isInProgress: Boolean get() = match(System.currentTimeMillis())
override val isEndingEvent: Boolean get() = durationInMsec() == 0L
override val isValid: Boolean get() = data.type == TherapyEvent.Type.APS_OFFLINE
}

View file

@ -1,354 +0,0 @@
package info.nightscout.androidaps.db;
import android.graphics.Color;
import androidx.annotation.NonNull;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.core.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface;
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.T;
import info.nightscout.androidaps.utils.Translator;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
@DatabaseTable(tableName = "CareportalEvents")
public class CareportalEvent implements DataPointWithLabelInterface, Interval {
@Inject ProfileFunction profileFunction;
@Inject ResourceHelper resourceHelper;
@Inject AAPSLogger aapsLogger;
@Inject Translator translator;
@Inject DateUtil dateUtil;
@DatabaseField(id = true)
public long date;
@DatabaseField
public boolean isValid = true;
@DatabaseField
public int source = Source.NONE;
@DatabaseField
public String _id;
@DatabaseField
public String eventType;
@DatabaseField
public String json;
public static final String CARBCORRECTION = "Carb Correction";
public static final String BOLUSWIZARD = "Bolus Wizard";
public static final String CORRECTIONBOLUS = "Correction Bolus";
public static final String MEALBOLUS = "Meal Bolus";
public static final String COMBOBOLUS = "Combo Bolus";
public static final String TEMPBASAL = "Temp Basal";
public static final String TEMPORARYTARGET = "Temporary Target";
public static final String PROFILESWITCH = "Profile Switch";
public static final String SITECHANGE = "Site Change";
public static final String INSULINCHANGE = "Insulin Change";
public static final String SENSORCHANGE = "Sensor Change";
public static final String PUMPBATTERYCHANGE = "Pump Battery Change";
public static final String BGCHECK = "BG Check";
public static final String ANNOUNCEMENT = "Announcement";
public static final String NOTE = "Note";
public static final String QUESTION = "Question";
public static final String EXERCISE = "Exercise";
public static final String OPENAPSOFFLINE = "OpenAPS Offline";
public static final String NONE = "<none>";
public static final String MBG = "Mbg"; // comming from entries
// found in CareDialog.kt file
public static final String FINGER = "Finger";
public static final String SENSOR = "Sensor";
public static final String MANUAL = "Manual";
// found in Translator.kt
public static final String SNACKBOLUS = "Snack Bolus";
public static final String SENSORSTART = "Sensor Start";
public static final String TEMPBASALSTART = "Temp Basal Start";
public static final String TEMPBASALEND = "Temp Basal End";
public static final String TEMPBASALCANCEL = "Temporary Target Cancel";
@Deprecated
public CareportalEvent() {
StaticInjector.Companion.getInstance().androidInjector().inject(this);
}
public CareportalEvent(HasAndroidInjector injector) {
injector.androidInjector().inject(this);
}
public CareportalEvent(NSMbg mbg) {
this();
date = mbg.date;
eventType = MBG;
json = mbg.json;
}
public long getMillisecondsFromStart() {
return System.currentTimeMillis() - date;
}
private double getHoursFromStart() {
return (System.currentTimeMillis() - date) / (60 * 60 * 1000.0);
}
public String age(boolean useShortText, ResourceHelper resourceHelper) {
Map<TimeUnit, Long> diff = DateUtil.computeDiff(date, System.currentTimeMillis());
String days = " " + resourceHelper.gs(R.string.days) + " ";
String hours = " " + resourceHelper.gs(R.string.hours) + " ";
if (useShortText) {
days = resourceHelper.gs(R.string.shortday);
hours = resourceHelper.gs(R.string.shorthour);
}
return diff.get(TimeUnit.DAYS) + days + diff.get(TimeUnit.HOURS) + hours;
}
public boolean isOlderThan(double hours) {
return getHoursFromStart() > hours;
}
@Override @NonNull
public String toString() {
return "CareportalEvent{" +
"date= " + date +
", date= " + dateUtil.dateAndTimeString(date) +
", isValid= " + isValid +
", _id= " + _id +
", eventType= " + eventType +
", json= " + json +
"}";
}
public boolean isEvent5minBack(List<CareportalEvent> list, long time) {
for (int i = 0; i < list.size(); i++) {
CareportalEvent event = list.get(i);
if (event.date <= time && event.date > (time - T.mins(5).msecs())) {
aapsLogger.debug(LTag.DATABASE, "Found event for time: " + dateUtil.dateAndTimeString(time) + " " + event.toString());
return true;
}
}
return false;
}
// -------- DataPointWithLabelInterface -------
@Override
public double getX() {
return date;
}
private double yValue = 0;
@Override
public double getY() {
String units = profileFunction.getUnits();
if (eventType.equals(MBG)) {
double mbg = 0d;
try {
JSONObject object = new JSONObject(json);
mbg = object.getDouble("mgdl");
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
return Profile.fromMgdlToUnits(mbg, units);
}
double glucose = 0d;
try {
JSONObject object = new JSONObject(json);
if (object.has("glucose")) {
glucose = object.getDouble("glucose");
units = object.getString("units");
}
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
if (glucose != 0d) {
double mmol = 0d;
double mgdl = 0;
if (units.equals(Constants.MGDL)) {
mgdl = glucose;
mmol = glucose * Constants.MGDL_TO_MMOLL;
}
if (units.equals(Constants.MMOL)) {
mmol = glucose;
mgdl = glucose * Constants.MMOLL_TO_MGDL;
}
return Profile.toUnits(mgdl, mmol, units);
}
return yValue;
}
@Override
public void setY(double y) {
yValue = y;
}
@Override
public String getLabel() {
try {
JSONObject object = new JSONObject(json);
if (object.has("notes"))
return StringUtils.abbreviate(object.getString("notes"), 40);
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
return translator.translate(eventType);
}
public String getNotes() {
try {
JSONObject object = new JSONObject(json);
if (object.has("notes"))
return object.getString("notes");
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
return "";
}
@Override
public long getDuration() {
return end() - start();
}
@Override
public PointsWithLabelGraphSeries.Shape getShape() {
switch (eventType) {
case CareportalEvent.MBG:
return PointsWithLabelGraphSeries.Shape.MBG;
case CareportalEvent.BGCHECK:
return PointsWithLabelGraphSeries.Shape.BGCHECK;
case CareportalEvent.ANNOUNCEMENT:
return PointsWithLabelGraphSeries.Shape.ANNOUNCEMENT;
case CareportalEvent.OPENAPSOFFLINE:
return PointsWithLabelGraphSeries.Shape.OPENAPSOFFLINE;
case CareportalEvent.EXERCISE:
return PointsWithLabelGraphSeries.Shape.EXERCISE;
}
if (getDuration() > 0)
return PointsWithLabelGraphSeries.Shape.GENERALWITHDURATION;
return PointsWithLabelGraphSeries.Shape.GENERAL;
}
@Override
public float getSize() {
boolean isTablet = resourceHelper.gb(R.bool.isTablet);
return isTablet ? 12 : 10;
}
@Override
public int getColor() {
if (eventType.equals(ANNOUNCEMENT))
return resourceHelper.gc(R.color.notificationAnnouncement);
if (eventType.equals(MBG))
return Color.RED;
if (eventType.equals(BGCHECK))
return Color.RED;
if (eventType.equals(EXERCISE))
return Color.BLUE;
if (eventType.equals(OPENAPSOFFLINE))
return Color.GRAY & 0x80FFFFFF;
return Color.GRAY;
}
// Interval interface
private Long cuttedEnd = null;
@Override
public long durationInMsec() {
try {
JSONObject object = new JSONObject(json);
if (object.has("duration"))
return object.getInt("duration") * 60 * 1000L;
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
return 0;
}
@Override
public long start() {
return date;
}
@Override
public long originalEnd() {
return date + durationInMsec();
}
@Override
public long end() {
if (cuttedEnd != null)
return cuttedEnd;
return originalEnd();
}
@Override
public void cutEndTo(long end) {
cuttedEnd = end;
}
@Override
public boolean match(long time) {
if (start() <= time && end() >= time)
return true;
return false;
}
public boolean before(long time) {
if (end() < time)
return true;
return false;
}
public boolean after(long time) {
if (start() > time)
return true;
return false;
}
@Override
public boolean isInProgress() {
return match(System.currentTimeMillis());
}
@Override
public boolean isEndingEvent() {
return durationInMsec() == 0;
}
@Override
public boolean isValid() {
return eventType.equals(OPENAPSOFFLINE);
}
}

View file

@ -9,7 +9,6 @@ interface DatabaseHelperInterface {
fun resetDatabases() fun resetDatabases()
fun createOrUpdate(careportalEvent: CareportalEvent)
fun createOrUpdate(extendedBolus: ExtendedBolus): Boolean fun createOrUpdate(extendedBolus: ExtendedBolus): Boolean
fun createOrUpdate(profileSwitch: ProfileSwitch) fun createOrUpdate(profileSwitch: ProfileSwitch)
fun createOrUpdate(record: DanaRHistoryRecord) fun createOrUpdate(record: DanaRHistoryRecord)
@ -26,7 +25,6 @@ interface DatabaseHelperInterface {
fun deleteDbRequest(id: String): Int fun deleteDbRequest(id: String): Int
fun delete(tempBasal: TemporaryBasal) fun delete(tempBasal: TemporaryBasal)
fun delete(extendedBolus: ExtendedBolus) fun delete(extendedBolus: ExtendedBolus)
fun delete(careportalEvent: CareportalEvent)
fun delete(profileSwitch: ProfileSwitch) fun delete(profileSwitch: ProfileSwitch)
fun deleteDbRequestbyMongoId(action: String, _id: String) fun deleteDbRequestbyMongoId(action: String, _id: String)
fun getDbRequestIterator(): CloseableIterator<DbRequest> fun getDbRequestIterator(): CloseableIterator<DbRequest>
@ -36,12 +34,6 @@ interface DatabaseHelperInterface {
fun findTempBasalByPumpId(id: Long): TemporaryBasal fun findTempBasalByPumpId(id: Long): TemporaryBasal
fun getTemporaryBasalsDataFromTime(mills: Long, ascending: Boolean): List<TemporaryBasal> fun getTemporaryBasalsDataFromTime(mills: Long, ascending: Boolean): List<TemporaryBasal>
fun getExtendedBolusDataFromTime(mills: Long, ascending: Boolean): List<ExtendedBolus> fun getExtendedBolusDataFromTime(mills: Long, ascending: Boolean): List<ExtendedBolus>
fun getCareportalEventFromTimestamp(timestamp: Long): CareportalEvent?
fun getLastCareportalEvent(event: String): CareportalEvent?
fun getCareportalEventsFromTime(mills: Long, ascending: Boolean): List<CareportalEvent>
fun getCareportalEventsFromTime(mills: Long, type: String, ascending: Boolean): List<CareportalEvent>
fun getCareportalEvents(start: Long, end: Long, ascending: Boolean): List<CareportalEvent>
fun getCareportalEvents(ascending: Boolean): List<CareportalEvent>
fun getProfileSwitchEventsFromTime(from: Long, to: Long, ascending: Boolean): List<ProfileSwitch> fun getProfileSwitchEventsFromTime(from: Long, to: Long, ascending: Boolean): List<ProfileSwitch>
fun getProfileSwitchEventsFromTime(mills: Long, ascending: Boolean): List<ProfileSwitch> fun getProfileSwitchEventsFromTime(mills: Long, ascending: Boolean): List<ProfileSwitch>
fun getAllOmnipodHistoryRecordsFromTimestamp(timestamp: Long, ascending: Boolean): List<OmnipodHistoryRecord> fun getAllOmnipodHistoryRecordsFromTimestamp(timestamp: Long, ascending: Boolean): List<OmnipodHistoryRecord>
@ -49,23 +41,19 @@ interface DatabaseHelperInterface {
fun getTDDsForLastXDays(days: Int): List<TDD> fun getTDDsForLastXDays(days: Int): List<TDD>
fun getProfileSwitchData(from: Long, ascending: Boolean): List<ProfileSwitch> fun getProfileSwitchData(from: Long, ascending: Boolean): List<ProfileSwitch>
fun getExtendedBolusByPumpId(pumpId: Long): ExtendedBolus? fun getExtendedBolusByPumpId(pumpId: Long): ExtendedBolus?
fun getAllCareportalEvents(): List<CareportalEvent>
fun getAllExtendedBoluses(): List<ExtendedBolus> fun getAllExtendedBoluses(): List<ExtendedBolus>
fun getAllProfileSwitches(): List<ProfileSwitch> fun getAllProfileSwitches(): List<ProfileSwitch>
fun getAllTDDs(): List<TDD> fun getAllTDDs(): List<TDD>
fun getAllTemporaryBasals(): List<TemporaryBasal> fun getAllTemporaryBasals(): List<TemporaryBasal>
fun getAllOHQueueItems(maxEntries: Long): List<OHQueueItem> fun getAllOHQueueItems(maxEntries: Long): List<OHQueueItem>
fun resetCareportalEvents()
fun resetProfileSwitch() fun resetProfileSwitch()
// old DB model // old DB model
fun deleteTempBasalById(_id: String) fun deleteTempBasalById(_id: String)
fun deleteExtendedBolusById(_id: String) fun deleteExtendedBolusById(_id: String)
fun deleteCareportalEventById(_id: String)
fun deleteProfileSwitchById(_id: String) fun deleteProfileSwitchById(_id: String)
fun createTempBasalFromJsonIfNotExists(json: JSONObject) fun createTempBasalFromJsonIfNotExists(json: JSONObject)
fun createExtendedBolusFromJsonIfNotExists(json: JSONObject) fun createExtendedBolusFromJsonIfNotExists(json: JSONObject)
fun createCareportalEventFromJsonIfNotExists(json: JSONObject)
fun createProfileSwitchFromJsonIfNotExists(activePluginProvider: ActivePluginProvider, nsUpload: NSUpload, trJson: JSONObject) fun createProfileSwitchFromJsonIfNotExists(activePluginProvider: ActivePluginProvider, nsUpload: NSUpload, trJson: JSONObject)
fun getInsightBolusID(pumpSerial: String, bolusID: Int, timestamp: Long): InsightBolusID? fun getInsightBolusID(pumpSerial: String, bolusID: Int, timestamp: Long): InsightBolusID?

View file

@ -20,13 +20,11 @@ import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.database.entities.GlucoseValue; import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.database.entities.TemporaryTarget; import info.nightscout.androidaps.database.entities.TemporaryTarget;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.database.entities.TherapyEvent;
import info.nightscout.androidaps.db.DbRequest; import info.nightscout.androidaps.db.DbRequest;
import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch; import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface; import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface;
import info.nightscout.androidaps.interfaces.LoopInterface; import info.nightscout.androidaps.interfaces.LoopInterface;
import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.interfaces.ProfileFunction;
@ -51,12 +49,10 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP;
@Singleton @Singleton
public class NSUpload { public class NSUpload {
private final HasAndroidInjector injector;
private final AAPSLogger aapsLogger; private final AAPSLogger aapsLogger;
private final ResourceHelper resourceHelper; private final ResourceHelper resourceHelper;
private final SP sp; private final SP sp;
private final UploadQueueInterface uploadQueue; private final UploadQueueInterface uploadQueue;
private final DatabaseHelperInterface databaseHelper;
private final RunningConfiguration runningConfiguration; private final RunningConfiguration runningConfiguration;
private final ProfileFunction profileFunction; private final ProfileFunction profileFunction;
@ -64,29 +60,25 @@ public class NSUpload {
@Inject @Inject
public NSUpload( public NSUpload(
HasAndroidInjector injector,
AAPSLogger aapsLogger, AAPSLogger aapsLogger,
ResourceHelper resourceHelper, ResourceHelper resourceHelper,
SP sp, SP sp,
UploadQueueInterface uploadQueue, UploadQueueInterface uploadQueue,
RunningConfiguration runningConfiguration, RunningConfiguration runningConfiguration,
DatabaseHelperInterface databaseHelper,
ProfileFunction profileFunction ProfileFunction profileFunction
) { ) {
this.injector = injector;
this.aapsLogger = aapsLogger; this.aapsLogger = aapsLogger;
this.resourceHelper = resourceHelper; this.resourceHelper = resourceHelper;
this.sp = sp; this.sp = sp;
this.uploadQueue = uploadQueue; this.uploadQueue = uploadQueue;
this.runningConfiguration = runningConfiguration; this.runningConfiguration = runningConfiguration;
this.databaseHelper = databaseHelper;
this.profileFunction = profileFunction; this.profileFunction = profileFunction;
} }
public void uploadTempBasalStartAbsolute(TemporaryBasal temporaryBasal, Double originalExtendedAmount) { public void uploadTempBasalStartAbsolute(TemporaryBasal temporaryBasal, Double originalExtendedAmount) {
try { try {
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPBASAL); data.put("eventType", TherapyEvent.Type.TEMPORARY_BASAL.getText());
data.put("duration", temporaryBasal.durationInMinutes); data.put("duration", temporaryBasal.durationInMinutes);
data.put("absolute", temporaryBasal.absoluteRate); data.put("absolute", temporaryBasal.absoluteRate);
data.put("rate", temporaryBasal.absoluteRate); data.put("rate", temporaryBasal.absoluteRate);
@ -118,7 +110,7 @@ public class NSUpload {
} }
} else { } else {
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPBASAL); data.put("eventType", TherapyEvent.Type.TEMPORARY_BASAL.getText());
data.put("duration", temporaryBasal.durationInMinutes); data.put("duration", temporaryBasal.durationInMinutes);
data.put("percent", temporaryBasal.percentRate - 100); data.put("percent", temporaryBasal.percentRate - 100);
if (profile != null) if (profile != null)
@ -137,7 +129,7 @@ public class NSUpload {
public void uploadTempBasalEnd(long time, boolean isFakedTempBasal, long pumpId) { public void uploadTempBasalEnd(long time, boolean isFakedTempBasal, long pumpId) {
try { try {
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPBASAL); data.put("eventType", TherapyEvent.Type.TEMPORARY_BASAL.getText());
data.put("created_at", DateUtil.toISOString(time)); data.put("created_at", DateUtil.toISOString(time));
data.put("enteredBy", "openaps://" + "AndroidAPS"); data.put("enteredBy", "openaps://" + "AndroidAPS");
if (isFakedTempBasal) if (isFakedTempBasal)
@ -153,7 +145,7 @@ public class NSUpload {
public void uploadExtendedBolus(ExtendedBolus extendedBolus) { public void uploadExtendedBolus(ExtendedBolus extendedBolus) {
try { try {
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.COMBOBOLUS); data.put("eventType", TherapyEvent.Type.COMBO_BOLUS.getText());
data.put("duration", extendedBolus.durationInMinutes); data.put("duration", extendedBolus.durationInMinutes);
data.put("splitNow", 0); data.put("splitNow", 0);
data.put("splitExt", 100); data.put("splitExt", 100);
@ -172,7 +164,7 @@ public class NSUpload {
public void uploadExtendedBolusEnd(long time, long pumpId) { public void uploadExtendedBolusEnd(long time, long pumpId) {
try { try {
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.COMBOBOLUS); data.put("eventType", TherapyEvent.Type.COMBO_BOLUS.getText());
data.put("duration", 0); data.put("duration", 0);
data.put("splitNow", 0); data.put("splitNow", 0);
data.put("splitExt", 100); data.put("splitExt", 100);
@ -293,7 +285,7 @@ public class NSUpload {
public void uploadTempTarget(TemporaryTarget tempTarget) { public void uploadTempTarget(TemporaryTarget tempTarget) {
try { try {
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPORARYTARGET); data.put("eventType", TherapyEvent.Type.TEMPORARY_TARGET.getText());
data.put("duration", T.msecs(tempTarget.getDuration()).mins()); data.put("duration", T.msecs(tempTarget.getDuration()).mins());
data.put(ISVALID, tempTarget.isValid()); data.put(ISVALID, tempTarget.isValid());
if (tempTarget.getLowTarget() > 0) { if (tempTarget.getLowTarget() > 0) {
@ -313,7 +305,7 @@ public class NSUpload {
public void updateTempTarget(TemporaryTarget tempTarget) { public void updateTempTarget(TemporaryTarget tempTarget) {
try { try {
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPORARYTARGET); data.put("eventType", TherapyEvent.Type.TEMPORARY_TARGET.getText());
data.put("duration", T.msecs(tempTarget.getDuration()).mins()); data.put("duration", T.msecs(tempTarget.getDuration()).mins());
data.put(ISVALID, tempTarget.isValid()); data.put(ISVALID, tempTarget.isValid());
if (tempTarget.getLowTarget() > 0) { if (tempTarget.getLowTarget() > 0) {
@ -343,7 +335,7 @@ public class NSUpload {
private static JSONObject getJson(ProfileSwitch profileSwitch) throws JSONException { private static JSONObject getJson(ProfileSwitch profileSwitch) throws JSONException {
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.PROFILESWITCH); data.put("eventType", TherapyEvent.Type.PROFILE_SWITCH.getText());
data.put("duration", profileSwitch.durationInMinutes); data.put("duration", profileSwitch.durationInMinutes);
data.put("profile", profileSwitch.getCustomizedName()); data.put("profile", profileSwitch.getCustomizedName());
data.put("profileJson", profileSwitch.profileJson); data.put("profileJson", profileSwitch.profileJson);
@ -382,21 +374,11 @@ public class NSUpload {
} }
// TODO replace with seting isValid = false
public void removeCareportalEntryFromNS(String _id) { public void removeCareportalEntryFromNS(String _id) {
uploadQueue.add(new DbRequest("dbRemove", "treatments", _id, System.currentTimeMillis())); uploadQueue.add(new DbRequest("dbRemove", "treatments", _id, System.currentTimeMillis()));
} }
public void uploadOpenAPSOffline(CareportalEvent event) {
try {
JSONObject data = new JSONObject(event.json);
data.put("created_at", DateUtil.toISOString(event.date));
data.put("enteredBy", "openaps://" + "AndroidAPS");
uploadQueue.add(new DbRequest("dbAdd", "treatments", data, event.date));
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
}
public void uploadError(String error) { public void uploadError(String error) {
uploadError(error, new Date()); uploadError(error, new Date());
} }
@ -473,6 +455,7 @@ public class NSUpload {
data.put("eventType", careportalEvent); data.put("eventType", careportalEvent);
data.put("created_at", DateUtil.toISOString(time)); data.put("created_at", DateUtil.toISOString(time));
data.put("enteredBy", sp.getString("careportal_enteredby", "AndroidAPS")); data.put("enteredBy", sp.getString("careportal_enteredby", "AndroidAPS"));
data.put("units", profileFunction.getUnits());
if (notes != null) { if (notes != null) {
data.put("notes", notes); data.put("notes", notes);
} }
@ -482,6 +465,23 @@ public class NSUpload {
uploadQueue.add(new DbRequest("dbAdd", "treatments", data, time)); uploadQueue.add(new DbRequest("dbAdd", "treatments", data, time));
} }
public void uploadEvent(TherapyEvent event) {
JSONObject data = new JSONObject();
try {
data.put("eventType", event.getType().getText());
data.put("created_at", event.getTimestamp());
data.put("enteredBy", event.getEnteredBy());
if (event.getUnits() != null) data.put("units", event.getUnits());
if (event.getDuration() != 0) data.put("duration", T.msecs(event.getDuration()).mins());
if (event.getNote() != null) data.put("notes", event.getNote());
if (event.getGlucose() != null) data.put("glucose", event.getGlucose());
if (event.getGlucoseType() != null) data.put("glucoseType", event.getGlucoseType().getText());
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
uploadQueue.add(new DbRequest("dbAdd", "treatments", data, event.getTimestamp()));
}
public void removeFoodFromNS(String _id) { public void removeFoodFromNS(String _id) {
try { try {
uploadQueue.add(new DbRequest("dbRemove", "food", _id, System.currentTimeMillis())); uploadQueue.add(new DbRequest("dbRemove", "food", _id, System.currentTimeMillis()));
@ -492,7 +492,7 @@ public class NSUpload {
} }
public void createNSTreatment(JSONObject data, ProfileStore profileStore, ProfileFunction profileFunction, long eventTime) { public void createNSTreatment(JSONObject data, ProfileStore profileStore, ProfileFunction profileFunction, long eventTime) {
if (JsonHelper.safeGetString(data, "eventType", "").equals(CareportalEvent.PROFILESWITCH)) { if (JsonHelper.safeGetString(data, "eventType", "").equals(TherapyEvent.Type.PROFILE_SWITCH.getText())) {
ProfileSwitch profileSwitch = profileFunction.prepareProfileSwitch( ProfileSwitch profileSwitch = profileFunction.prepareProfileSwitch(
profileStore, profileStore,
JsonHelper.safeGetString(data, "profile"), JsonHelper.safeGetString(data, "profile"),
@ -513,27 +513,4 @@ public class NSUpload {
return _id.length() == 24; return _id.length() == 24;
} }
public void generateCareportalEvent(String eventType, long time, String notes) {
CareportalEvent careportalEvent = new CareportalEvent(injector);
careportalEvent.source = Source.USER;
careportalEvent.date = time;
careportalEvent.json = generateJson(eventType, time, notes).toString();
careportalEvent.eventType = eventType;
databaseHelper.createOrUpdate(careportalEvent);
uploadEvent(eventType, time, notes);
}
private JSONObject generateJson(String careportalEvent, long time, String notes) {
JSONObject data = new JSONObject();
try {
data.put("eventType", careportalEvent);
data.put("created_at", DateUtil.toISOString(time));
data.put("mills", time);
data.put("enteredBy", sp.getString("careportal_enteredby", "AndroidAPS"));
if (!notes.isEmpty()) data.put("notes", notes);
} catch (JSONException ignored) {
}
return data;
}
} }

View file

@ -2,25 +2,40 @@ package info.nightscout.androidaps.plugins.general.nsclient.data;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger;
import info.nightscout.androidaps.logging.LTag; import javax.inject.Inject;
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.logging.AAPSLogger;
public class NSMbg { public class NSMbg {
private static final Logger log = StacktraceLoggerWrapper.getLogger(LTag.NSCLIENT); @Inject public AAPSLogger aapsLogger;
public long date; public long date;
public double mbg; public double mbg;
public String json; public String json;
public NSMbg(JSONObject json) { public NSMbg(HasAndroidInjector injector) {
injector.androidInjector().inject(this);
}
public NSMbg(HasAndroidInjector injector, JSONObject json) {
this(injector);
try { try {
date = json.getLong("mills"); date = json.getLong("mills");
mbg = json.getDouble("mgdl"); mbg = json.getDouble("mgdl");
this.json = json.toString(); this.json = json.toString();
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); aapsLogger.error("Unhandled exception", e);
log.error("Data: " + json.toString()); aapsLogger.error("Data: " + json.toString());
}
}
public String id() {
try {
return new JSONObject(json).getString("_id");
} catch (JSONException e) {
return null;
} }
} }
} }

View file

@ -1,14 +1,11 @@
package info.nightscout.androidaps.utils package info.nightscout.androidaps.utils
import info.nightscout.androidaps.core.R import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
/**
* Created by mike on 15.07.2016.
*/
@Singleton @Singleton
class Translator @Inject internal constructor( class Translator @Inject internal constructor(
private val resourceHelper: ResourceHelper private val resourceHelper: ResourceHelper
@ -16,31 +13,33 @@ class Translator @Inject internal constructor(
fun translate(text: String): String = fun translate(text: String): String =
when (text) { when (text) {
CareportalEvent.BGCHECK -> resourceHelper.gs(R.string.careportal_bgcheck) TherapyEvent.Type.FINGER_STICK_BG_VALUE.text -> resourceHelper.gs(R.string.careportal_bgcheck)
CareportalEvent.SNACKBOLUS -> resourceHelper.gs(R.string.careportal_snackbolus) TherapyEvent.Type.SNACK_BOLUS.text -> resourceHelper.gs(R.string.careportal_snackbolus)
CareportalEvent.MEALBOLUS -> resourceHelper.gs(R.string.careportal_mealbolus) TherapyEvent.Type.MEAL_BOLUS.text -> resourceHelper.gs(R.string.careportal_mealbolus)
CareportalEvent.CORRECTIONBOLUS -> resourceHelper.gs(R.string.careportal_correctionbolus) TherapyEvent.Type.CORRECTION_BOLUS.text -> resourceHelper.gs(R.string.careportal_correctionbolus)
CareportalEvent.CARBCORRECTION -> resourceHelper.gs(R.string.careportal_carbscorrection) TherapyEvent.Type.CARBS_CORRECTION.text -> resourceHelper.gs(R.string.careportal_carbscorrection)
CareportalEvent.COMBOBOLUS -> resourceHelper.gs(R.string.careportal_combobolus) TherapyEvent.Type.COMBO_BOLUS.text -> resourceHelper.gs(R.string.careportal_combobolus)
CareportalEvent.ANNOUNCEMENT -> resourceHelper.gs(R.string.careportal_announcement) TherapyEvent.Type.ANNOUNCEMENT.text -> resourceHelper.gs(R.string.careportal_announcement)
CareportalEvent.NOTE -> resourceHelper.gs(R.string.careportal_note) TherapyEvent.Type.NOTE.text -> resourceHelper.gs(R.string.careportal_note)
CareportalEvent.QUESTION -> resourceHelper.gs(R.string.careportal_question) TherapyEvent.Type.QUESTION.text -> resourceHelper.gs(R.string.careportal_question)
CareportalEvent.EXERCISE -> resourceHelper.gs(R.string.careportal_exercise) TherapyEvent.Type.EXERCISE.text -> resourceHelper.gs(R.string.careportal_exercise)
CareportalEvent.SITECHANGE -> resourceHelper.gs(R.string.careportal_pumpsitechange) TherapyEvent.Type.CANNULA_CHANGE.text -> resourceHelper.gs(R.string.careportal_pumpsitechange)
CareportalEvent.PUMPBATTERYCHANGE -> resourceHelper.gs(R.string.careportal_pumpbatterychange) TherapyEvent.Type.PUMP_BATTERY_CHANGE.text -> resourceHelper.gs(R.string.careportal_pumpbatterychange)
CareportalEvent.SENSORSTART -> resourceHelper.gs(R.string.careportal_cgmsensorstart) TherapyEvent.Type.SENSOR_STARTED.text -> resourceHelper.gs(R.string.careportal_cgmsensorstart)
CareportalEvent.SENSORCHANGE -> resourceHelper.gs(R.string.careportal_cgmsensorinsert) TherapyEvent.Type.SENSOR_STOPPED.text -> resourceHelper.gs(R.string.careportal_cgm_sensor_stop)
CareportalEvent.INSULINCHANGE -> resourceHelper.gs(R.string.careportal_insulincartridgechange) TherapyEvent.Type.SENSOR_CHANGE.text -> resourceHelper.gs(R.string.careportal_cgmsensorinsert)
CareportalEvent.TEMPBASALSTART -> resourceHelper.gs(R.string.careportal_tempbasalstart) TherapyEvent.Type.INSULIN_CHANGE.text -> resourceHelper.gs(R.string.careportal_insulincartridgechange)
CareportalEvent.TEMPBASALEND -> resourceHelper.gs(R.string.careportal_tempbasalend) TherapyEvent.Type.DAD_ALERT.text -> resourceHelper.gs(R.string.careportal_dad_alert)
CareportalEvent.PROFILESWITCH -> resourceHelper.gs(R.string.careportal_profileswitch) TherapyEvent.Type.TEMPORARY_BASAL_START.text -> resourceHelper.gs(R.string.careportal_tempbasalstart)
CareportalEvent.TEMPORARYTARGET -> resourceHelper.gs(R.string.careportal_temporarytarget) TherapyEvent.Type.TEMPORARY_BASAL_END.text -> resourceHelper.gs(R.string.careportal_tempbasalend)
CareportalEvent.TEMPBASALCANCEL -> resourceHelper.gs(R.string.careportal_temporarytargetcancel) TherapyEvent.Type.PROFILE_SWITCH.text -> resourceHelper.gs(R.string.careportal_profileswitch)
CareportalEvent.OPENAPSOFFLINE -> resourceHelper.gs(R.string.careportal_openapsoffline) TherapyEvent.Type.TEMPORARY_TARGET.text -> resourceHelper.gs(R.string.careportal_temporarytarget)
CareportalEvent.MBG -> resourceHelper.gs(R.string.careportal_mbg) TherapyEvent.Type.TEMPORARY_TARGET_CANCEL.text -> resourceHelper.gs(R.string.careportal_temporarytargetcancel)
CareportalEvent.FINGER -> resourceHelper.gs(R.string.glucosetype_finger) TherapyEvent.Type.APS_OFFLINE.text -> resourceHelper.gs(R.string.careportal_openapsoffline)
CareportalEvent.SENSOR -> resourceHelper.gs(R.string.glucosetype_sensor) TherapyEvent.Type.NS_MBG.text -> resourceHelper.gs(R.string.careportal_mbg)
CareportalEvent.MANUAL -> resourceHelper.gs(R.string.manual) TherapyEvent.MeterType.FINGER.text -> resourceHelper.gs(R.string.glucosetype_finger)
else -> resourceHelper.gs(R.string.unknown) TherapyEvent.MeterType.SENSOR.text -> resourceHelper.gs(R.string.glucosetype_sensor)
TherapyEvent.MeterType.MANUAL.text -> resourceHelper.gs(R.string.manual)
else -> resourceHelper.gs(R.string.unknown)
} }
} }

View file

@ -3,7 +3,8 @@ package info.nightscout.androidaps.utils
import android.graphics.Color import android.graphics.Color
import android.widget.TextView import android.widget.TextView
import info.nightscout.androidaps.core.R import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.utils.extensions.isOlderThan
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -29,10 +30,10 @@ class WarnColors @Inject constructor(val resourceHelper: ResourceHelper) {
else -> normalColor else -> normalColor
}) })
fun setColorByAge(view: TextView?, careportalEvent: CareportalEvent, warnThreshold: Double, urgentThreshold: Double) = fun setColorByAge(view: TextView?, therapyEvent: TherapyEvent, warnThreshold: Double, urgentThreshold: Double) =
view?.setTextColor(when { view?.setTextColor(when {
careportalEvent.isOlderThan(urgentThreshold) -> resourceHelper.gc(R.color.low) therapyEvent.isOlderThan(urgentThreshold) -> resourceHelper.gc(R.color.low)
careportalEvent.isOlderThan(warnThreshold) -> resourceHelper.gc(R.color.high) therapyEvent.isOlderThan(warnThreshold) -> resourceHelper.gc(R.color.high)
else -> Color.WHITE else -> Color.WHITE
}) })
} }

View file

@ -0,0 +1,91 @@
package info.nightscout.androidaps.utils.extensions
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.json.JSONObject
import java.util.concurrent.TimeUnit
fun TherapyEvent.age(useShortText: Boolean, resourceHelper: ResourceHelper): String {
val diff = DateUtil.computeDiff(timestamp, System.currentTimeMillis())
var days = " " + resourceHelper.gs(R.string.days) + " "
var hours = " " + resourceHelper.gs(R.string.hours) + " "
if (useShortText) {
days = resourceHelper.gs(R.string.shortday)
hours = resourceHelper.gs(R.string.shorthour)
}
return diff[TimeUnit.DAYS].toString() + days + diff[TimeUnit.HOURS] + hours
}
fun TherapyEvent.isOlderThan(hours: Double): Boolean {
return getHoursFromStart() > hours
}
fun TherapyEvent.getHoursFromStart(): Double {
return (System.currentTimeMillis() - timestamp) / (60 * 60 * 1000.0)
}
fun therapyEventFromNsMbg(mbg: NSMbg) =
TherapyEvent(
type = TherapyEvent.Type.NS_MBG,
timestamp = mbg.date,
glucose = mbg.mbg
).also {
it.interfaceIDs.nightscoutId = mbg.id()
}
/*
create fake object with nsID and isValid == false
*/
fun therapyEventFromNsIdForInvalidating(nsId: String): TherapyEvent =
therapyEventFromJson(
JSONObject()
.put("mills", 1)
.put("_id", nsId)
.put(NSUpload.ISVALID, false)
)!!
fun therapyEventFromJson(jsonObject: JSONObject): TherapyEvent? {
val units = JsonHelper.safeGetString(jsonObject, "units", Constants.MGDL)
val timestamp = JsonHelper.safeGetLongAllowNull(jsonObject, "mills", null) ?: return null
val type = TherapyEvent.Type.fromString(JsonHelper.safeGetString(jsonObject, "eventType", TherapyEvent.Type.NONE.text))
val duration = JsonHelper.safeGetLong(jsonObject, "duration")
val glucose = JsonHelper.safeGetDoubleAllowNull(jsonObject, "glucose")
val glucoseType = TherapyEvent.MeterType.fromString(JsonHelper.safeGetString(jsonObject, "glucoseType"))
val enteredBy = JsonHelper.safeGetStringAllowNull(jsonObject, "enteredBy", null)
val note = JsonHelper.safeGetStringAllowNull(jsonObject, "notes", null)
val id = JsonHelper.safeGetStringAllowNull(jsonObject, "_id", null) ?: return null
val isValid = JsonHelper.safeGetBoolean(jsonObject, NSUpload.ISVALID, true)
val te = TherapyEvent(
timestamp = timestamp,
duration = TimeUnit.MINUTES.toMillis(duration),
units = units,
type = type,
glucose = glucose,
glucoseType = glucoseType,
enteredBy = enteredBy,
note = note,
isValid = isValid
)
te.interfaceIDs.nightscoutId = id
return te
}
fun isEvent5minBack(list: List<TherapyEvent>, time: Long): Boolean {
for (i in list.indices) {
val event = list[i]
if (event.timestamp <= time && event.timestamp > time - T.mins(5).msecs()) {
return true
}
}
return false
}

View file

@ -247,6 +247,8 @@
<string name="careportal_pumpsitechange">Pump Site Change</string> <string name="careportal_pumpsitechange">Pump Site Change</string>
<string name="careportal_cgmsensorinsert">CGM Sensor Insert</string> <string name="careportal_cgmsensorinsert">CGM Sensor Insert</string>
<string name="careportal_cgmsensorstart">CGM Sensor Start</string> <string name="careportal_cgmsensorstart">CGM Sensor Start</string>
<string name="careportal_cgm_sensor_stop">CGM Sensor Stop</string>
<string name="careportal_dad_alert">D.A.D. Alert</string>
<string name="careportal_insulincartridgechange">Insulin Cartridge Change</string> <string name="careportal_insulincartridgechange">Insulin Cartridge Change</string>
<string name="careportal_profileswitch">Profile switch</string> <string name="careportal_profileswitch">Profile switch</string>
<string name="careportal_snackbolus">Snack Bolus</string> <string name="careportal_snackbolus">Snack Bolus</string>

View file

@ -23,4 +23,5 @@ android {
dependencies { dependencies {
implementation project(':core') implementation project(':core')
implementation project(':dana') implementation project(':dana')
implementation project(':database')
} }

View file

@ -1,9 +1,13 @@
package info.nightscout.androidaps.danars.comm package info.nightscout.androidaps.danars.comm
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.dana.DanaPump
import info.nightscout.androidaps.danars.R import info.nightscout.androidaps.danars.R
import info.nightscout.androidaps.danars.encryption.BleEncryption
import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction
import info.nightscout.androidaps.db.ExtendedBolus import info.nightscout.androidaps.db.ExtendedBolus
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TemporaryBasal import info.nightscout.androidaps.db.TemporaryBasal
@ -13,14 +17,13 @@ import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage import info.nightscout.androidaps.plugins.pump.common.bolusInfo.DetailedBolusInfoStorage
import info.nightscout.androidaps.dana.DanaPump
import info.nightscout.androidaps.danars.encryption.BleEncryption
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import org.joda.time.DateTime import org.joda.time.DateTime
import org.joda.time.DateTimeZone import org.joda.time.DateTimeZone
import java.util.*
import javax.inject.Inject import javax.inject.Inject
open class DanaRS_Packet_APS_History_Events( open class DanaRS_Packet_APS_History_Events(
@ -35,6 +38,9 @@ open class DanaRS_Packet_APS_History_Events(
@Inject lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage @Inject lateinit var detailedBolusInfoStorage: DetailedBolusInfoStorage
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var nsUpload: NSUpload @Inject lateinit var nsUpload: NSUpload
@Inject lateinit var repository: AppRepository
private val disposable = CompositeDisposable()
init { init {
opCode = BleEncryption.DANAR_PACKET__OPCODE__APS_HISTORY_EVENTS opCode = BleEncryption.DANAR_PACKET__OPCODE__APS_HISTORY_EVENTS
@ -174,7 +180,15 @@ open class DanaRS_Packet_APS_History_Events(
DanaPump.REFILL -> { DanaPump.REFILL -> {
aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT REFILL (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U") aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT REFILL (" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U")
if (sp.getBoolean(R.string.key_rs_loginsulinchange, true)) if (sp.getBoolean(R.string.key_rs_loginsulinchange, true))
nsUpload.generateCareportalEvent(CareportalEvent.INSULINCHANGE, datetime, resourceHelper.gs(R.string.danarspump)) disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction(
timestamp = datetime,
type = TherapyEvent.Type.INSULIN_CHANGE,
note = resourceHelper.gs(R.string.danarspump)
)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadEvent(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it)
})
status = "REFILL " + dateUtil.timeString(datetime) status = "REFILL " + dateUtil.timeString(datetime)
} }
@ -202,11 +216,19 @@ open class DanaRS_Packet_APS_History_Events(
DanaPump.PRIMECANNULA -> { DanaPump.PRIMECANNULA -> {
aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT PRIMECANNULA(" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U") aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT PRIMECANNULA(" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Amount: " + param1 / 100.0 + "U")
if (sp.getBoolean(R.string.key_rs_logcanulachange, true)) if (sp.getBoolean(R.string.key_rs_logcanulachange, true))
nsUpload.generateCareportalEvent(CareportalEvent.SITECHANGE, datetime, resourceHelper.gs(R.string.danarspump)) disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction(
timestamp = datetime,
type = TherapyEvent.Type.CANNULA_CHANGE,
note = resourceHelper.gs(R.string.danarspump)
)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadEvent(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it)
})
status = "PRIMECANNULA " + dateUtil.timeString(datetime) status = "PRIMECANNULA " + dateUtil.timeString(datetime)
} }
DanaPump.TIMECHANGE -> { DanaPump.TIMECHANGE -> {
val oldDateTime = intFromBuffMsbLsb(data, 7, 4) * 1000L val oldDateTime = intFromBuffMsbLsb(data, 7, 4) * 1000L
aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT TIMECHANGE(" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Previous: " + dateUtil.dateAndTimeString(oldDateTime)) aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT TIMECHANGE(" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Previous: " + dateUtil.dateAndTimeString(oldDateTime))
status = "TIMECHANGE " + dateUtil.timeString(datetime) status = "TIMECHANGE " + dateUtil.timeString(datetime)

View file

@ -1,8 +1,8 @@
{ {
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 3, "version": 4,
"identityHash": "a1db89121451334b6eb389e8c702dd2c", "identityHash": "e8b8785efbd1699431eef90a5b441ed3",
"entities": [ "entities": [
{ {
"tableName": "apsResults", "tableName": "apsResults",
@ -1714,7 +1714,7 @@
}, },
{ {
"tableName": "therapyEvents", "tableName": "therapyEvents",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `type` TEXT NOT NULL, `note` TEXT, `amount` REAL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `therapyEvents`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `type` TEXT NOT NULL, `note` TEXT, `enteredBy` TEXT, `glucose` REAL, `glucoseType` TEXT, `units` TEXT, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `therapyEvents`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -1777,11 +1777,29 @@
"notNull": false "notNull": false
}, },
{ {
"fieldPath": "amount", "fieldPath": "enteredBy",
"columnName": "amount", "columnName": "enteredBy",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "glucose",
"columnName": "glucose",
"affinity": "REAL", "affinity": "REAL",
"notNull": false "notNull": false
}, },
{
"fieldPath": "glucoseType",
"columnName": "glucoseType",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "units",
"columnName": "units",
"affinity": "TEXT",
"notNull": false
},
{ {
"fieldPath": "interfaceIDs_backing.nightscoutSystemId", "fieldPath": "interfaceIDs_backing.nightscoutSystemId",
"columnName": "nightscoutSystemId", "columnName": "nightscoutSystemId",
@ -2751,7 +2769,7 @@
"views": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a1db89121451334b6eb389e8c702dd2c')" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e8b8785efbd1699431eef90a5b441ed3')"
] ]
} }
} }

View file

@ -6,7 +6,7 @@ import androidx.room.TypeConverters
import info.nightscout.androidaps.database.daos.* import info.nightscout.androidaps.database.daos.*
import info.nightscout.androidaps.database.entities.* import info.nightscout.androidaps.database.entities.*
const val DATABASE_VERSION = 3 const val DATABASE_VERSION = 4
@Database(version = DATABASE_VERSION, @Database(version = DATABASE_VERSION,
entities = [APSResult::class, Bolus::class, BolusCalculatorResult::class, Carbs::class, entities = [APSResult::class, Bolus::class, BolusCalculatorResult::class, Carbs::class,

View file

@ -2,6 +2,7 @@ package info.nightscout.androidaps.database
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.entities.UserEntry import info.nightscout.androidaps.database.entities.UserEntry
import info.nightscout.androidaps.database.interfaces.DBEntry import info.nightscout.androidaps.database.interfaces.DBEntry
import info.nightscout.androidaps.database.transactions.Transaction import info.nightscout.androidaps.database.transactions.Transaction
@ -130,6 +131,45 @@ class AppRepository @Inject internal constructor(
database.userEntryDao.insert(word) database.userEntryDao.insert(word)
} }
// THERAPY EVENT
fun getTherapyEventDataFromTime(timestamp: Long, ascending: Boolean): Single<List<TherapyEvent>> =
database.therapyEventDao.getTherapyEventDataFromTime(timestamp)
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())
fun getTherapyEventDataFromTime(timestamp: Long, type: TherapyEvent.Type, ascending: Boolean): Single<List<TherapyEvent>> =
database.therapyEventDao.getTherapyEventDataFromTime(timestamp, type)
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())
fun getTherapyEventDataIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single<List<TherapyEvent>> =
database.therapyEventDao.getTherapyEventDataIncludingInvalidFromTime(timestamp)
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())
@Suppress("unused")
fun getValidTherapyEventsByType(type: TherapyEvent.Type): List<TherapyEvent> =
database.therapyEventDao.getValidByType(type)
fun deleteAllTherapyEventsEntries() =
database.therapyEventDao.deleteAllEntries()
fun getLastTherapyRecord(type: TherapyEvent.Type): Single<ValueWrapper<TherapyEvent>> =
database.therapyEventDao.getLastTherapyRecord(type).toWrappedSingle()
.subscribeOn(Schedulers.io())
fun getTherapyEventByTimestamp(type: TherapyEvent.Type, timestamp: Long): TherapyEvent? =
database.therapyEventDao.findByTimestamp(type, timestamp)
fun compatGetTherapyEventDataFromTime(timestamp: Long, ascending: Boolean): Single<List<TherapyEvent>> =
database.therapyEventDao.compatGetTherapyEventDataFromTime(timestamp)
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())
fun compatGetTherapyEventDataFromToTime(from: Long, to: Long): Single<List<TherapyEvent>> =
database.therapyEventDao.compatGetTherapyEventDataFromToTime(from, to)
.subscribeOn(Schedulers.io())
} }
@Suppress("USELESS_CAST") @Suppress("USELESS_CAST")

View file

@ -46,6 +46,12 @@ class Converters {
@TypeConverter @TypeConverter
fun toTherapyEventType(therapyEventType: String?) = therapyEventType?.let { TherapyEvent.Type.valueOf(it) } fun toTherapyEventType(therapyEventType: String?) = therapyEventType?.let { TherapyEvent.Type.valueOf(it) }
@TypeConverter
fun fromGlucoseType(meterType: TherapyEvent.MeterType?) = meterType?.name
@TypeConverter
fun toGlucoseType(meterType: String?) = meterType?.let { TherapyEvent.MeterType.valueOf(it) }
@TypeConverter @TypeConverter
fun fromGlucoseUnit(glucoseUnit: ProfileSwitch.GlucoseUnit?) = glucoseUnit?.name fun fromGlucoseUnit(glucoseUnit: ProfileSwitch.GlucoseUnit?) = glucoseUnit?.name
@ -91,24 +97,24 @@ class Converters {
@TypeConverter @TypeConverter
fun anyToString(value: Any?) = when (value) { fun anyToString(value: Any?) = when (value) {
null -> null null -> null
is String -> "S$value" is String -> "S$value"
is Int -> "I$value" is Int -> "I$value"
is Long -> "L$value" is Long -> "L$value"
is Boolean -> "B$value" is Boolean -> "B$value"
is Float -> "F$value" is Float -> "F$value"
else -> throw IllegalArgumentException("Type not supported") else -> throw IllegalArgumentException("Type not supported")
} }
@TypeConverter @TypeConverter
fun stringToAny(value: String?): Any? = when { fun stringToAny(value: String?): Any? = when {
value == null -> null value == null -> null
value.startsWith("S") -> value.substring(1) value.startsWith("S") -> value.substring(1)
value.startsWith("I") -> value.substring(1).toInt() value.startsWith("I") -> value.substring(1).toInt()
value.startsWith("L") -> value.substring(1).toLong() value.startsWith("L") -> value.substring(1).toLong()
value.startsWith("B") -> value.substring(1).toBoolean() value.startsWith("B") -> value.substring(1).toBoolean()
value.startsWith("F") -> value.substring(1).toFloat() value.startsWith("F") -> value.substring(1).toFloat()
else -> throw IllegalArgumentException("Type not supported") else -> throw IllegalArgumentException("Type not supported")
} }
@TypeConverter @TypeConverter

View file

@ -3,9 +3,7 @@ package info.nightscout.androidaps.database.daos
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import info.nightscout.androidaps.database.TABLE_THERAPY_EVENTS import info.nightscout.androidaps.database.TABLE_THERAPY_EVENTS
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.TherapyEvent import info.nightscout.androidaps.database.entities.TherapyEvent
import io.reactivex.Flowable
import io.reactivex.Maybe import io.reactivex.Maybe
import io.reactivex.Single import io.reactivex.Single
@ -21,4 +19,27 @@ internal interface TherapyEventDao : TraceableDao<TherapyEvent> {
@Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE type = :type AND timestamp = :timestamp AND referenceId IS NULL") @Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE type = :type AND timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(type: TherapyEvent.Type, timestamp: Long): TherapyEvent? fun findByTimestamp(type: TherapyEvent.Type, timestamp: Long): TherapyEvent?
@Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE type = :type AND referenceId IS NULL")
fun getValidByType(type: TherapyEvent.Type): List<TherapyEvent>
@Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE nightscoutId = :nsId AND referenceId IS NULL")
fun findByNSId(nsId: String): TherapyEvent?
@Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE timestamp >= :timestamp AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC")
fun getTherapyEventDataFromTime(timestamp: Long): Single<List<TherapyEvent>>
@Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE type = :type AND timestamp >= :timestamp AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC")
fun getTherapyEventDataFromTime(timestamp: Long, type: TherapyEvent.Type): Single<List<TherapyEvent>>
@Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE timestamp >= :timestamp AND referenceId IS NULL ORDER BY timestamp ASC")
fun getTherapyEventDataIncludingInvalidFromTime(timestamp: Long): Single<List<TherapyEvent>>
@Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE type = :type AND isValid = 1 ORDER BY id DESC LIMIT 1")
fun getLastTherapyRecord(type: TherapyEvent.Type): Maybe<TherapyEvent>
@Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE timestamp >= :timestamp AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC")
fun compatGetTherapyEventDataFromTime(timestamp: Long): Single<List<TherapyEvent>>
@Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE timestamp >= :from AND timestamp <= :to AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC")
fun compatGetTherapyEventDataFromToTime(from: Long, to: Long): Single<List<TherapyEvent>>
} }

View file

@ -1,63 +1,160 @@
package info.nightscout.androidaps.database.entities package info.nightscout.androidaps.database.entities
import androidx.room.* import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
import com.google.gson.annotations.SerializedName
import info.nightscout.androidaps.database.TABLE_THERAPY_EVENTS import info.nightscout.androidaps.database.TABLE_THERAPY_EVENTS
import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration
import info.nightscout.androidaps.database.interfaces.TraceableDBEntry import info.nightscout.androidaps.database.interfaces.TraceableDBEntry
import java.util.TimeZone import java.util.*
@Entity(tableName = TABLE_THERAPY_EVENTS, @Entity(tableName = TABLE_THERAPY_EVENTS,
foreignKeys = [ForeignKey( foreignKeys = [ForeignKey(
entity = TherapyEvent::class, entity = TherapyEvent::class,
parentColumns = ["id"], parentColumns = ["id"],
childColumns = ["referenceId"])], childColumns = ["referenceId"])],
indices = [Index("referenceId"), Index("timestamp")]) indices = [Index("referenceId"), Index("timestamp")])
data class TherapyEvent( data class TherapyEvent(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
override var id: Long = 0, override var id: Long = 0,
override var version: Int = 0, override var version: Int = 0,
override var dateCreated: Long = -1, override var dateCreated: Long = -1,
override var isValid: Boolean = true, override var isValid: Boolean = true,
override var referenceId: Long? = null, override var referenceId: Long? = null,
@Embedded @Embedded
override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(),
override var timestamp: Long, override var timestamp: Long,
override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(),
override var duration: Long = 0, override var duration: Long = 0,
var type: Type, var type: Type,
var note: String? = null, var note: String? = null,
var amount: Double? = null var enteredBy: String? = null,
var glucose: Double? = null,
var glucoseType: MeterType? = null,
var units: String? = null
) : TraceableDBEntry, DBEntryWithTimeAndDuration { ) : TraceableDBEntry, DBEntryWithTimeAndDuration {
enum class Type {
CANNULA_CHANGED, enum class MeterType(val text: String) {
TUBE_CHANGED, @SerializedName("Finger")
RESERVOIR_CHANGED, FINGER("Finger"),
BATTERY_CHANGED, @SerializedName("Sensor")
LEAKING_INFUSION_SET, SENSOR("Sensor"),
SENSOR_INSERTED, @SerializedName("Manual")
SENSOR_STARTED, MANUAL("Manual")
SENSOR_STOPPED, ;
FINGER_STICK_BG_VALUE,
ACTIVITY, companion object {
FALLING_ASLEEP,
WAKING_UP, fun fromString(text: String?) = values().firstOrNull { it.text == text } ?: MANUAL
SICKNESS, }
STRESS, }
PRE_PERIOD,
ALCOHOL, @Suppress("unused")
CORTISON, enum class Type(val text: String, val nsNative: Boolean = false) {
FEELING_LOW,
FEELING_HIGH, @SerializedName("Site Change")
ANNOUNCEMENT, CANNULA_CHANGE("Site Change", nsNative = true),
QUESTION, @SerializedName("Insulin Change")
NOTE, INSULIN_CHANGE("Insulin Change", nsNative = true),
APS_OFFLINE, @SerializedName("Pump Battery Change")
BATTERY_EMPTY, PUMP_BATTERY_CHANGE("Pump Battery Change", nsNative = true),
RESERVOIR_EMPTY, @SerializedName("Sensor Change")
OCCLUSION, SENSOR_CHANGE("Sensor Change", nsNative = true),
PUMP_STOPPED, @SerializedName("Sensor Start")
PUMP_STARTED, SENSOR_STARTED("Sensor Start", nsNative = true),
PUMP_PAUSED @SerializedName("Sensor Stop")
SENSOR_STOPPED("Sensor Stop", nsNative = true),
@SerializedName("BG Check")
FINGER_STICK_BG_VALUE("BG Check", nsNative = true),
@SerializedName("Exercise")
EXERCISE("Exercise", nsNative = true),
@SerializedName("Announcement")
ANNOUNCEMENT("Announcement", nsNative = true),
@SerializedName("Question")
QUESTION("Question", nsNative = true),
@SerializedName("Note")
NOTE("Note", nsNative = true),
@SerializedName("OpenAPS Offline")
APS_OFFLINE("OpenAPS Offline", nsNative = true),
@SerializedName("D.A.D. Alert")
DAD_ALERT("D.A.D. Alert", nsNative = true),
@SerializedName("Mbg")
NS_MBG("Mbg", nsNative = true),
// Used but not as a Therapy Event (use constants only)
@SerializedName("Carb Correction")
CARBS_CORRECTION("Carb Correction", nsNative = true),
@SerializedName("Bolus Wizard")
BOLUS_WIZARD("Bolus Wizard", nsNative = true),
@SerializedName("Correction Bolus")
CORRECTION_BOLUS("Correction Bolus", nsNative = true),
@SerializedName("Meal Bolus")
MEAL_BOLUS("Meal Bolus", nsNative = true),
@SerializedName("Combo Bolus")
COMBO_BOLUS("Combo Bolus", nsNative = true),
@SerializedName("Temporary Target")
TEMPORARY_TARGET("Temporary Target", nsNative = true),
@SerializedName("Temporary Target Cancel")
TEMPORARY_TARGET_CANCEL("Temporary Target Cancel", nsNative = true),
@SerializedName("Profile Switch")
PROFILE_SWITCH("Profile Switch", nsNative = true),
@SerializedName("Snack Bolus")
SNACK_BOLUS("Snack Bolus", nsNative = true),
@SerializedName("Temp Basal")
TEMPORARY_BASAL("Temp Basal", nsNative = true),
@SerializedName("Temp Basal Start")
TEMPORARY_BASAL_START("Temp Basal Start", nsNative = true),
@SerializedName("Temp Basal End")
TEMPORARY_BASAL_END("Temp Basal End", nsNative = true),
// Not supported by NS
@SerializedName("Tube Change")
TUBE_CHANGE("Tube Change"),
@SerializedName("Falling Asleep")
FALLING_ASLEEP("Falling Asleep"),
@SerializedName("Battery Empty")
BATTERY_EMPTY("Battery Empty"),
@SerializedName("Reservoir Empty")
RESERVOIR_EMPTY("Reservoir Empty"),
@SerializedName("Occlusion")
OCCLUSION("Occlusion"),
@SerializedName("Pump Stopped")
PUMP_STOPPED("Pump Stopped"),
@SerializedName("Pump Started")
PUMP_STARTED("Pump Started"),
@SerializedName("Pump Paused")
PUMP_PAUSED("Pump Paused"),
@SerializedName("Waking Up")
WAKING_UP("Waking Up"),
@SerializedName("Sickness")
SICKNESS("Sickness"),
@SerializedName("Stress")
STRESS("Stress"),
@SerializedName("Pre Period")
PRE_PERIOD("Pre Period"),
@SerializedName("Alcohol")
ALCOHOL("Alcohol"),
@SerializedName("Cortisone")
CORTISONE("Cortisone"),
@SerializedName("Feeling Low")
FEELING_LOW("Feeling Low"),
@SerializedName("Feeling High")
FEELING_HIGH("Feeling High"),
@SerializedName("Leaking Infusion Set")
LEAKING_INFUSION_SET("Leaking Infusion Set"),
// Default
@SerializedName("<none>")
NONE("<none>")
;
companion object {
fun fromString(text: String?) = values().firstOrNull { it.text == text } ?: NONE
}
} }
} }

View file

@ -56,15 +56,15 @@ class CgmSourceTransaction(
database.therapyEventDao.insertNewEntry(TherapyEvent( database.therapyEventDao.insertNewEntry(TherapyEvent(
timestamp = it.timestamp, timestamp = it.timestamp,
type = TherapyEvent.Type.FINGER_STICK_BG_VALUE, type = TherapyEvent.Type.FINGER_STICK_BG_VALUE,
amount = it.value glucose = it.value
)) ))
} }
} }
sensorInsertionTime?.let { sensorInsertionTime?.let {
if (database.therapyEventDao.findByTimestamp(TherapyEvent.Type.SENSOR_INSERTED, it) == null) { if (database.therapyEventDao.findByTimestamp(TherapyEvent.Type.SENSOR_CHANGE, it) == null) {
database.therapyEventDao.insertNewEntry(TherapyEvent( database.therapyEventDao.insertNewEntry(TherapyEvent(
timestamp = it, timestamp = it,
type = TherapyEvent.Type.SENSOR_INSERTED type = TherapyEvent.Type.SENSOR_CHANGE
)) ))
} }
} }

View file

@ -0,0 +1,27 @@
package info.nightscout.androidaps.database.transactions
import info.nightscout.androidaps.database.entities.TherapyEvent
class InsertTherapyEventIfNewTransaction(
val therapyEvent: TherapyEvent
) : Transaction<InsertTherapyEventIfNewTransaction.TransactionResult>() {
constructor(timestamp: Long, type: TherapyEvent.Type, duration: Long = 0, note: String? = null, enteredBy: String? = null, glucose: Double? = null, glucoseType: TherapyEvent.MeterType? = null, units: String? = null) :
this(TherapyEvent(timestamp = timestamp, type = type, duration = duration, note = note, enteredBy = enteredBy, glucose = glucose, glucoseType = glucoseType, units = units))
override fun run(): TransactionResult {
val result = TransactionResult()
val current = database.therapyEventDao.findByTimestamp(therapyEvent.type, therapyEvent.timestamp)
if (current == null) {
database.therapyEventDao.insertNewEntry(therapyEvent)
result.inserted.add(therapyEvent)
} else result.existing.add(therapyEvent)
return result
}
class TransactionResult {
val inserted = mutableListOf<TherapyEvent>()
val existing = mutableListOf<TherapyEvent>()
}
}

View file

@ -0,0 +1,22 @@
package info.nightscout.androidaps.database.transactions
import info.nightscout.androidaps.database.entities.TherapyEvent
class InvalidateAAPSStartedTherapyEventTransaction : Transaction<InvalidateAAPSStartedTherapyEventTransaction.TransactionResult>() {
override fun run(): TransactionResult {
val result = TransactionResult()
val therapyEvents = database.therapyEventDao.getValidByType(TherapyEvent.Type.NOTE)
for (event in therapyEvents) {
event.isValid = false
database.therapyEventDao.updateExistingEntry(event)
result.invalidated.add(event)
}
return result
}
class TransactionResult {
val invalidated = mutableListOf<TherapyEvent>()
}
}

View file

@ -0,0 +1,10 @@
package info.nightscout.androidaps.database.transactions
class InvalidateTherapyEventTransaction(val id: Long) : Transaction<Unit>() {
override fun run() {
val therapyEvent = database.therapyEventDao.findById(id)
?: throw IllegalArgumentException("There is no such TherapyEvent with the specified ID.")
therapyEvent.isValid = false
database.therapyEventDao.updateExistingEntry(therapyEvent)
}
}

View file

@ -0,0 +1,50 @@
package info.nightscout.androidaps.database.transactions
import info.nightscout.androidaps.database.entities.TherapyEvent
/**
* Sync the TherapyEvents from NS
*/
class SyncTherapyEventTransaction(private val therapyEvent: TherapyEvent) : Transaction<SyncTherapyEventTransaction.TransactionResult>() {
override fun run(): TransactionResult {
val result = TransactionResult()
val current: TherapyEvent? =
therapyEvent.interfaceIDs.nightscoutId?.let {
database.therapyEventDao.findByNSId(it)
}
if (current != null) {
// nsId exists, allow only invalidation
if (current.isValid && !therapyEvent.isValid) {
current.isValid = false
database.therapyEventDao.updateExistingEntry(current)
result.invalidated.add(current)
}
return result
}
// not known nsId
val existing = database.therapyEventDao.findByTimestamp(therapyEvent.type, therapyEvent.timestamp)
if (existing != null && existing.interfaceIDs.nightscoutId == null) {
// the same record, update nsId only
existing.interfaceIDs.nightscoutId = therapyEvent.interfaceIDs.nightscoutId
existing.isValid = therapyEvent.isValid
database.therapyEventDao.updateExistingEntry(existing)
result.updatedNsId.add(existing)
} else {
database.therapyEventDao.insertNewEntry(therapyEvent)
result.inserted.add(therapyEvent)
}
return result
}
class TransactionResult {
val updatedNsId = mutableListOf<TherapyEvent>()
val inserted = mutableListOf<TherapyEvent>()
val invalidated = mutableListOf<TherapyEvent>()
}
}

View file

@ -17,4 +17,5 @@ android {
dependencies { dependencies {
implementation project(':core') implementation project(':core')
implementation project(':database')
} }

View file

@ -30,7 +30,9 @@ import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.TherapyEvent;
import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction;
import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.InsightBolusID; import info.nightscout.androidaps.db.InsightBolusID;
import info.nightscout.androidaps.db.InsightHistoryOffset; import info.nightscout.androidaps.db.InsightHistoryOffset;
@ -134,6 +136,7 @@ import info.nightscout.androidaps.plugins.pump.insight.utils.ParameterBlockUtil;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
@Singleton @Singleton
public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, ConstraintsInterface, InsightConnectionService.StateCallback { public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, ConstraintsInterface, InsightConnectionService.StateCallback {
@ -150,6 +153,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
private final UploadQueueInterface uploadQueue; private final UploadQueueInterface uploadQueue;
private final DateUtil dateUtil; private final DateUtil dateUtil;
private final DatabaseHelperInterface databaseHelper; private final DatabaseHelperInterface databaseHelper;
private final AppRepository repository;
public static final String ALERT_CHANNEL_ID = "AndroidAPS-InsightAlert"; public static final String ALERT_CHANNEL_ID = "AndroidAPS-InsightAlert";
@ -184,10 +188,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
private List<BasalProfileBlock> profileBlocks; private List<BasalProfileBlock> profileBlocks;
private boolean limitsFetched; private boolean limitsFetched;
private double maximumBolusAmount; private double maximumBolusAmount;
private double maximumBasalAmount;
private double minimumBolusAmount; private double minimumBolusAmount;
private double minimumBasalAmount;
private long lastUpdated = -1;
private OperatingMode operatingMode; private OperatingMode operatingMode;
private BatteryStatus batteryStatus; private BatteryStatus batteryStatus;
private CartridgeStatus cartridgeStatus; private CartridgeStatus cartridgeStatus;
@ -198,6 +199,8 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
private boolean statusLoaded; private boolean statusLoaded;
private TBROverNotificationBlock tbrOverNotificationBlock; private TBROverNotificationBlock tbrOverNotificationBlock;
private final CompositeDisposable disposable = new CompositeDisposable();
@Inject @Inject
public LocalInsightPlugin( public LocalInsightPlugin(
HasAndroidInjector injector, HasAndroidInjector injector,
@ -213,7 +216,8 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
UploadQueueInterface uploadQueue, UploadQueueInterface uploadQueue,
ConfigInterface config, ConfigInterface config,
DateUtil dateUtil, DateUtil dateUtil,
DatabaseHelperInterface databaseHelper DatabaseHelperInterface databaseHelper,
AppRepository repository
) { ) {
super(new PluginDescription() super(new PluginDescription()
.pluginIcon(R.drawable.ic_insight_128) .pluginIcon(R.drawable.ic_insight_128)
@ -238,6 +242,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
this.uploadQueue = uploadQueue; this.uploadQueue = uploadQueue;
this.dateUtil = dateUtil; this.dateUtil = dateUtil;
this.databaseHelper = databaseHelper; this.databaseHelper = databaseHelper;
this.repository = repository;
pumpDescription = new PumpDescription(); pumpDescription = new PumpDescription();
pumpDescription.setPumpDescription(PumpType.AccuChekInsightBluetooth); pumpDescription.setPumpDescription(PumpType.AccuChekInsightBluetooth);
@ -247,10 +252,6 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
return tbrOverNotificationBlock; return tbrOverNotificationBlock;
} }
public long getLastUpdated() {
return lastUpdated;
}
public InsightConnectionService getConnectionService() { public InsightConnectionService getConnectionService() {
return connectionService; return connectionService;
} }
@ -465,7 +466,6 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
} }
statusLoaded = true; statusLoaded = true;
} }
lastUpdated = System.currentTimeMillis();
new Handler(Looper.getMainLooper()).post(() -> { new Handler(Looper.getMainLooper()).post(() -> {
rxBus.send(new EventLocalInsightUpdateGUI()); rxBus.send(new EventLocalInsightUpdateGUI());
rxBus.send(new EventRefreshOverview("LocalInsightPlugin::fetchStatus", false)); rxBus.send(new EventRefreshOverview("LocalInsightPlugin::fetchStatus", false));
@ -474,9 +474,9 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
private void fetchLimitations() throws Exception { private void fetchLimitations() throws Exception {
maximumBolusAmount = ParameterBlockUtil.readParameterBlock(connectionService, Service.CONFIGURATION, MaxBolusAmountBlock.class).getAmountLimitation(); maximumBolusAmount = ParameterBlockUtil.readParameterBlock(connectionService, Service.CONFIGURATION, MaxBolusAmountBlock.class).getAmountLimitation();
maximumBasalAmount = ParameterBlockUtil.readParameterBlock(connectionService, Service.CONFIGURATION, MaxBasalAmountBlock.class).getAmountLimitation(); double maximumBasalAmount = ParameterBlockUtil.readParameterBlock(connectionService, Service.CONFIGURATION, MaxBasalAmountBlock.class).getAmountLimitation();
minimumBolusAmount = ParameterBlockUtil.readParameterBlock(connectionService, Service.CONFIGURATION, FactoryMinBolusAmountBlock.class).getAmountLimitation(); minimumBolusAmount = ParameterBlockUtil.readParameterBlock(connectionService, Service.CONFIGURATION, FactoryMinBolusAmountBlock.class).getAmountLimitation();
minimumBasalAmount = ParameterBlockUtil.readParameterBlock(connectionService, Service.CONFIGURATION, FactoryMinBasalAmountBlock.class).getAmountLimitation(); double minimumBasalAmount = ParameterBlockUtil.readParameterBlock(connectionService, Service.CONFIGURATION, FactoryMinBasalAmountBlock.class).getAmountLimitation();
this.pumpDescription.setBasalMaximumRate(maximumBasalAmount); this.pumpDescription.setBasalMaximumRate(maximumBasalAmount);
this.pumpDescription.setBasalMinimumRate(minimumBasalAmount); this.pumpDescription.setBasalMinimumRate(minimumBasalAmount);
limitsFetched = true; limitsFetched = true;
@ -1269,7 +1269,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
if (!sp.getBoolean("insight_log_site_changes", false)) return; if (!sp.getBoolean("insight_log_site_changes", false)) return;
long timestamp = parseDate(event.getEventYear(), event.getEventMonth(), event.getEventDay(), long timestamp = parseDate(event.getEventYear(), event.getEventMonth(), event.getEventDay(),
event.getEventHour(), event.getEventMinute(), event.getEventSecond()) + timeOffset; event.getEventHour(), event.getEventMinute(), event.getEventSecond()) + timeOffset;
uploadCareportalEvent(timestamp, CareportalEvent.SITECHANGE); uploadCareportalEvent(timestamp, TherapyEvent.Type.CANNULA_CHANGE);
} }
private void processTotalDailyDoseEvent(TotalDailyDoseEvent event) { private void processTotalDailyDoseEvent(TotalDailyDoseEvent event) {
@ -1297,14 +1297,14 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
if (!sp.getBoolean("insight_log_reservoir_changes", false)) return; if (!sp.getBoolean("insight_log_reservoir_changes", false)) return;
long timestamp = parseDate(event.getEventYear(), event.getEventMonth(), event.getEventDay(), long timestamp = parseDate(event.getEventYear(), event.getEventMonth(), event.getEventDay(),
event.getEventHour(), event.getEventMinute(), event.getEventSecond()) + timeOffset; event.getEventHour(), event.getEventMinute(), event.getEventSecond()) + timeOffset;
uploadCareportalEvent(timestamp, CareportalEvent.INSULINCHANGE); uploadCareportalEvent(timestamp, TherapyEvent.Type.INSULIN_CHANGE);
} }
private void processPowerUpEvent(PowerUpEvent event) { private void processPowerUpEvent(PowerUpEvent event) {
if (!sp.getBoolean("insight_log_battery_changes", false)) return; if (!sp.getBoolean("insight_log_battery_changes", false)) return;
long timestamp = parseDate(event.getEventYear(), event.getEventMonth(), event.getEventDay(), long timestamp = parseDate(event.getEventYear(), event.getEventMonth(), event.getEventDay(),
event.getEventHour(), event.getEventMinute(), event.getEventSecond()) + timeOffset; event.getEventHour(), event.getEventMinute(), event.getEventSecond()) + timeOffset;
uploadCareportalEvent(timestamp, CareportalEvent.PUMPBATTERYCHANGE); uploadCareportalEvent(timestamp, TherapyEvent.Type.PUMP_BATTERY_CHANGE);
} }
private void processOperatingModeChangedEvent(String serial, List<InsightPumpID> pumpStartedEvents, OperatingModeChangedEvent event) { private void processOperatingModeChangedEvent(String serial, List<InsightPumpID> pumpStartedEvents, OperatingModeChangedEvent event) {
@ -1552,25 +1552,12 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
} }
private void logNote(long date, String note) { private void logNote(long date, String note) {
try { if (repository.getTherapyEventByTimestamp(TherapyEvent.Type.NOTE, date) != null) return;
if (databaseHelper.getCareportalEventFromTimestamp(date) != null) disposable.add(repository.runTransactionForResult(new InsertTherapyEventIfNewTransaction(date, TherapyEvent.Type.NOTE, 0, note, sp.getString("careportal_enteredby", "AndroidAPS"), null, null, null))
return; .subscribe(
JSONObject data = new JSONObject(); result -> result.getInserted().forEach(nsUpload::uploadEvent),
String enteredBy = sp.getString("careportal_enteredby", ""); error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error)
if (!enteredBy.equals("")) data.put("enteredBy", enteredBy); ));
data.put("created_at", DateUtil.toISOString(date));
data.put("eventType", CareportalEvent.NOTE);
data.put("notes", note);
CareportalEvent careportalEvent = new CareportalEvent(getInjector());
careportalEvent.date = date;
careportalEvent.source = Source.USER;
careportalEvent.eventType = CareportalEvent.NOTE;
careportalEvent.json = data.toString();
databaseHelper.createOrUpdate(careportalEvent);
nsUpload.uploadCareportalEntryToNS(data, date);
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
} }
private long parseRelativeDate(int year, int month, int day, int hour, int minute, int second, int relativeHour, int relativeMinute, int relativeSecond) { private long parseRelativeDate(int year, int month, int day, int hour, int minute, int second, int relativeHour, int relativeMinute, int relativeSecond) {
@ -1586,25 +1573,13 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
return calendar.getTimeInMillis(); return calendar.getTimeInMillis();
} }
private void uploadCareportalEvent(long date, String event) { private void uploadCareportalEvent(long date, TherapyEvent.Type event) {
if (databaseHelper.getCareportalEventFromTimestamp(date) != null) if (repository.getTherapyEventByTimestamp(event, date) != null) return;
return; disposable.add(repository.runTransactionForResult(new InsertTherapyEventIfNewTransaction(date, event, 0, null, sp.getString("careportal_enteredby", "AndroidAPS"), null, null, null))
try { .subscribe(
JSONObject data = new JSONObject(); result -> result.getInserted().forEach(nsUpload::uploadEvent),
String enteredBy = sp.getString("careportal_enteredby", ""); error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error)
if (!enteredBy.equals("")) data.put("enteredBy", enteredBy); ));
data.put("created_at", DateUtil.toISOString(date));
data.put("eventType", event);
CareportalEvent careportalEvent = new CareportalEvent(getInjector());
careportalEvent.date = date;
careportalEvent.source = Source.USER;
careportalEvent.eventType = event;
careportalEvent.json = data.toString();
databaseHelper.createOrUpdate(careportalEvent);
nsUpload.uploadCareportalEntryToNS(data, date);
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
} }
@NonNull @Override @NonNull @Override

View file

@ -17,4 +17,5 @@ android {
dependencies { dependencies {
implementation project(':core') implementation project(':core')
implementation project(':rileylink') implementation project(':rileylink')
implementation project(':database')
} }

View file

@ -6,8 +6,6 @@ import com.google.gson.GsonBuilder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.joda.time.LocalDateTime; import org.joda.time.LocalDateTime;
import org.joda.time.Minutes; import org.joda.time.Minutes;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
@ -23,12 +21,15 @@ import javax.inject.Singleton;
import dagger.android.HasAndroidInjector; import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.TherapyEvent;
import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction;
import info.nightscout.androidaps.db.DbObjectBase; import info.nightscout.androidaps.db.DbObjectBase;
import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TDD; import info.nightscout.androidaps.db.TDD;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
@ -51,11 +52,10 @@ import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalProce
import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus; import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus;
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst; import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicConst;
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentUpdateReturn; import info.nightscout.androidaps.plugins.treatments.TreatmentUpdateReturn;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.Round; import info.nightscout.androidaps.utils.Round;
import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
/** /**
@ -81,6 +81,7 @@ public class MedtronicHistoryData {
private final MedtronicUtil medtronicUtil; private final MedtronicUtil medtronicUtil;
private final MedtronicPumpHistoryDecoder medtronicPumpHistoryDecoder; private final MedtronicPumpHistoryDecoder medtronicPumpHistoryDecoder;
private final DatabaseHelperInterface databaseHelper; private final DatabaseHelperInterface databaseHelper;
private final AppRepository repository;
private final List<PumpHistoryEntry> allHistory; private final List<PumpHistoryEntry> allHistory;
private List<PumpHistoryEntry> newHistory = null; private List<PumpHistoryEntry> newHistory = null;
@ -94,6 +95,7 @@ public class MedtronicHistoryData {
private long lastIdUsed = 0; private long lastIdUsed = 0;
private final CompositeDisposable disposable = new CompositeDisposable();
/** /**
* Double bolus debug. We seem to have small problem with double Boluses (or sometimes also missing boluses * Double bolus debug. We seem to have small problem with double Boluses (or sometimes also missing boluses
* from history. This flag turns on debugging for that (default is off=false)... Debuging is pretty detailed, * from history. This flag turns on debugging for that (default is off=false)... Debuging is pretty detailed,
@ -112,7 +114,8 @@ public class MedtronicHistoryData {
NSUpload nsUpload, NSUpload nsUpload,
MedtronicUtil medtronicUtil, MedtronicUtil medtronicUtil,
MedtronicPumpHistoryDecoder medtronicPumpHistoryDecoder, MedtronicPumpHistoryDecoder medtronicPumpHistoryDecoder,
DatabaseHelperInterface databaseHelperInterface DatabaseHelperInterface databaseHelperInterface,
AppRepository repository
) { ) {
this.allHistory = new ArrayList<>(); this.allHistory = new ArrayList<>();
@ -124,6 +127,7 @@ public class MedtronicHistoryData {
this.medtronicUtil = medtronicUtil; this.medtronicUtil = medtronicUtil;
this.medtronicPumpHistoryDecoder = medtronicPumpHistoryDecoder; this.medtronicPumpHistoryDecoder = medtronicPumpHistoryDecoder;
this.databaseHelper = databaseHelperInterface; this.databaseHelper = databaseHelperInterface;
this.repository = repository;
} }
private Gson gson() { private Gson gson() {
@ -549,7 +553,7 @@ public class MedtronicHistoryData {
long lastPrimeFromAAPS = sp.getLong(MedtronicConst.Statistics.LastPrime, 0L); long lastPrimeFromAAPS = sp.getLong(MedtronicConst.Statistics.LastPrime, 0L);
if (lastPrimeRecord != lastPrimeFromAAPS) { if (lastPrimeRecord != lastPrimeFromAAPS) {
uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastPrimeRecord), CareportalEvent.SITECHANGE); uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastPrimeRecord), TherapyEvent.Type.CANNULA_CHANGE);
sp.putLong(MedtronicConst.Statistics.LastPrime, lastPrimeRecord); sp.putLong(MedtronicConst.Statistics.LastPrime, lastPrimeRecord);
} }
@ -572,7 +576,7 @@ public class MedtronicHistoryData {
long lastRewindFromAAPS = sp.getLong(MedtronicConst.Statistics.LastRewind, 0L); long lastRewindFromAAPS = sp.getLong(MedtronicConst.Statistics.LastRewind, 0L);
if (lastRewindRecord != lastRewindFromAAPS) { if (lastRewindRecord != lastRewindFromAAPS) {
uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastRewindRecord), CareportalEvent.INSULINCHANGE); uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastRewindRecord), TherapyEvent.Type.INSULIN_CHANGE);
sp.putLong(MedtronicConst.Statistics.LastRewind, lastRewindRecord); sp.putLong(MedtronicConst.Statistics.LastRewind, lastRewindRecord);
} }
@ -580,28 +584,15 @@ public class MedtronicHistoryData {
} }
private void uploadCareportalEvent(long date, String event) { private void uploadCareportalEvent(long date, TherapyEvent.Type event) {
if (databaseHelper.getCareportalEventFromTimestamp(date) != null) if (repository.getTherapyEventByTimestamp(event, date) != null) return;
return; disposable.add(repository.runTransactionForResult(new InsertTherapyEventIfNewTransaction(date, event, 0, null, sp.getString("careportal_enteredby", "AndroidAPS"), null, null, null))
try { .subscribe(
JSONObject data = new JSONObject(); result -> result.getInserted().forEach(nsUpload::uploadEvent),
String enteredBy = sp.getString("careportal_enteredby", ""); error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error)
if (!enteredBy.equals("")) data.put("enteredBy", enteredBy); ));
data.put("created_at", DateUtil.toISOString(date));
data.put("eventType", event);
CareportalEvent careportalEvent = new CareportalEvent(injector);
careportalEvent.date = date;
careportalEvent.source = Source.USER;
careportalEvent.eventType = event;
careportalEvent.json = data.toString();
databaseHelper.createOrUpdate(careportalEvent);
nsUpload.uploadCareportalEntryToNS(data, date);
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
} }
private void processTDDs(List<PumpHistoryEntry> tddsIn) { private void processTDDs(List<PumpHistoryEntry> tddsIn) {
List<PumpHistoryEntry> tdds = filterTDDs(tddsIn); List<PumpHistoryEntry> tdds = filterTDDs(tddsIn);
@ -1523,7 +1514,7 @@ public class MedtronicHistoryData {
// HELPER METHODS // HELPER METHODS
private void sort(List<PumpHistoryEntry> list) { private void sort(List<PumpHistoryEntry> list) {
if (list!=null && !list.isEmpty()) { if (list != null && !list.isEmpty()) {
Collections.sort(list, new PumpHistoryEntry.Comparator()); Collections.sort(list, new PumpHistoryEntry.Comparator());
} }
} }

View file

@ -18,4 +18,5 @@ dependencies {
implementation project(':core') implementation project(':core')
implementation project(':omnipod-common') implementation project(':omnipod-common')
implementation project(':rileylink') implementation project(':rileylink')
implementation project(':database')
} }

View file

@ -4,8 +4,6 @@ import android.content.Context;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.Duration; import org.joda.time.Duration;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@ -20,7 +18,9 @@ import info.nightscout.androidaps.activities.ErrorHelperActivity;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.TherapyEvent;
import info.nightscout.androidaps.database.transactions.InsertTherapyEventIfNewTransaction;
import info.nightscout.androidaps.db.OmnipodHistoryRecord; import info.nightscout.androidaps.db.OmnipodHistoryRecord;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
@ -28,7 +28,6 @@ import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.events.EventRefreshOverview;
import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
@ -85,10 +84,10 @@ import info.nightscout.androidaps.plugins.pump.omnipod.eros.event.EventOmnipodEr
import info.nightscout.androidaps.plugins.pump.omnipod.eros.rileylink.manager.OmnipodRileyLinkCommunicationManager; import info.nightscout.androidaps.plugins.pump.omnipod.eros.rileylink.manager.OmnipodRileyLinkCommunicationManager;
import info.nightscout.androidaps.plugins.pump.omnipod.eros.util.AapsOmnipodUtil; import info.nightscout.androidaps.plugins.pump.omnipod.eros.util.AapsOmnipodUtil;
import info.nightscout.androidaps.plugins.pump.omnipod.eros.util.OmnipodAlertUtil; import info.nightscout.androidaps.plugins.pump.omnipod.eros.util.OmnipodAlertUtil;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.rx.AapsSchedulers; import info.nightscout.androidaps.utils.rx.AapsSchedulers;
import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.subjects.SingleSubject; import io.reactivex.subjects.SingleSubject;
@Singleton @Singleton
@ -97,7 +96,6 @@ public class AapsOmnipodErosManager {
private final PodStateManager podStateManager; private final PodStateManager podStateManager;
private final AapsOmnipodUtil aapsOmnipodUtil; private final AapsOmnipodUtil aapsOmnipodUtil;
private final AAPSLogger aapsLogger; private final AAPSLogger aapsLogger;
private final AapsSchedulers aapsSchedulers;
private final RxBusWrapper rxBus; private final RxBusWrapper rxBus;
private final ResourceHelper resourceHelper; private final ResourceHelper resourceHelper;
private final HasAndroidInjector injector; private final HasAndroidInjector injector;
@ -107,8 +105,8 @@ public class AapsOmnipodErosManager {
private final DatabaseHelperInterface databaseHelper; private final DatabaseHelperInterface databaseHelper;
private final OmnipodAlertUtil omnipodAlertUtil; private final OmnipodAlertUtil omnipodAlertUtil;
private final NSUpload nsUpload; private final NSUpload nsUpload;
private final ProfileFunction profileFunction;
private final Context context; private final Context context;
private final AppRepository repository;
private boolean basalBeepsEnabled; private boolean basalBeepsEnabled;
private boolean bolusBeepsEnabled; private boolean bolusBeepsEnabled;
@ -125,6 +123,8 @@ public class AapsOmnipodErosManager {
private boolean showRileyLinkBatteryLevel; private boolean showRileyLinkBatteryLevel;
private boolean batteryChangeLoggingEnabled; private boolean batteryChangeLoggingEnabled;
private final CompositeDisposable disposable = new CompositeDisposable();
@Inject @Inject
public AapsOmnipodErosManager(OmnipodRileyLinkCommunicationManager communicationService, public AapsOmnipodErosManager(OmnipodRileyLinkCommunicationManager communicationService,
PodStateManager podStateManager, PodStateManager podStateManager,
@ -139,13 +139,12 @@ public class AapsOmnipodErosManager {
DatabaseHelperInterface databaseHelper, DatabaseHelperInterface databaseHelper,
OmnipodAlertUtil omnipodAlertUtil, OmnipodAlertUtil omnipodAlertUtil,
NSUpload nsUpload, NSUpload nsUpload,
ProfileFunction profileFunction, Context context,
Context context) { AppRepository repository) {
this.podStateManager = podStateManager; this.podStateManager = podStateManager;
this.aapsOmnipodUtil = aapsOmnipodUtil; this.aapsOmnipodUtil = aapsOmnipodUtil;
this.aapsLogger = aapsLogger; this.aapsLogger = aapsLogger;
this.aapsSchedulers = aapsSchedulers;
this.rxBus = rxBus; this.rxBus = rxBus;
this.sp = sp; this.sp = sp;
this.resourceHelper = resourceHelper; this.resourceHelper = resourceHelper;
@ -154,8 +153,8 @@ public class AapsOmnipodErosManager {
this.databaseHelper = databaseHelper; this.databaseHelper = databaseHelper;
this.omnipodAlertUtil = omnipodAlertUtil; this.omnipodAlertUtil = omnipodAlertUtil;
this.nsUpload = nsUpload; this.nsUpload = nsUpload;
this.profileFunction = profileFunction;
this.context = context; this.context = context;
this.repository = repository;
delegate = new OmnipodManager(aapsLogger, aapsSchedulers, communicationService, podStateManager); delegate = new OmnipodManager(aapsLogger, aapsSchedulers, communicationService, podStateManager);
@ -224,8 +223,8 @@ public class AapsOmnipodErosManager {
addToHistory(System.currentTimeMillis(), PodHistoryEntryType.INSERT_CANNULA, result.getComment(), result.getSuccess()); addToHistory(System.currentTimeMillis(), PodHistoryEntryType.INSERT_CANNULA, result.getComment(), result.getSuccess());
if (result.getSuccess()) { if (result.getSuccess()) {
uploadCareportalEvent(System.currentTimeMillis() - 1000, CareportalEvent.INSULINCHANGE); uploadCareportalEvent(System.currentTimeMillis() - 1000, TherapyEvent.Type.INSULIN_CHANGE);
uploadCareportalEvent(System.currentTimeMillis(), CareportalEvent.SITECHANGE); uploadCareportalEvent(System.currentTimeMillis(), TherapyEvent.Type.CANNULA_CHANGE);
dismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED); dismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED);
@ -1003,28 +1002,12 @@ public class AapsOmnipodErosManager {
return new BasalSchedule(entries); return new BasalSchedule(entries);
} }
private void uploadCareportalEvent(long date, String event) { private void uploadCareportalEvent(long date, TherapyEvent.Type event) {
if (databaseHelper.getCareportalEventFromTimestamp(date) != null) if (repository.getTherapyEventByTimestamp(event, date) != null) return;
return; disposable.add(repository.runTransactionForResult(new InsertTherapyEventIfNewTransaction(date, event, 0, null, sp.getString("careportal_enteredby", "AndroidAPS"), null, null, null))
try { .subscribe(
JSONObject data = new JSONObject(); result -> result.getInserted().forEach(nsUpload::uploadEvent),
String enteredBy = sp.getString("careportal_enteredby", ""); error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error)
if (enteredBy.isEmpty()) { ));
data.put("enteredBy", enteredBy);
}
data.put("created_at", DateUtil.toISOString(date));
data.put("mills", date);
data.put("eventType", event);
data.put("units", profileFunction.getUnits());
CareportalEvent careportalEvent = new CareportalEvent(injector);
careportalEvent.date = date;
careportalEvent.source = Source.USER;
careportalEvent.eventType = event;
careportalEvent.json = data.toString();
databaseHelper.createOrUpdate(careportalEvent);
nsUpload.uploadCareportalEntryToNS(data, date);
} catch (JSONException e) {
aapsLogger.error(LTag.PUMPCOMM, "Unhandled exception when uploading SiteChange event.", e);
}
} }
} }