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">
<option name="AUTODETECT_INDENTS" value="false" />
<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="NAME_COUNT_TO_USE_STAR_IMPORT" value="6" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="6" />

View file

@ -111,7 +111,7 @@ android {
defaultConfig {
multiDexEnabled true
versionCode 1500
version "2.8.2.1-dev-c"
version "2.8.2.1-dev-d"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
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.entities.GlucoseValue
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.EventTempTargetChange
import info.nightscout.androidaps.events.EventTherapyEventChange
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
@ -39,5 +40,9 @@ class CompatDBHelper @Inject constructor(
aapsLogger.debug(LTag.DATABASE, "Firing 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 info.nightscout.androidaps.dana.comm.RecordTypes;
import info.nightscout.androidaps.data.NonOverlappingIntervals;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventCareportalEventChange;
import info.nightscout.androidaps.events.EventExtendedBolusChange;
import info.nightscout.androidaps.events.EventProfileNeedsUpdate;
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_DANARHISTORY = "DanaRHistory";
public static final String DATABASE_DBREQUESTS = "DBRequests";
public static final String DATABASE_CAREPORTALEVENTS = "CareportalEvents";
public static final String DATABASE_TDDS = "TDDs";
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 ScheduledFuture<?> scheduledExtendedBolusPost = null;
private static final ScheduledExecutorService careportalEventWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledCareportalEventPost = null;
private static final ScheduledExecutorService profileSwitchEventWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledProfileSwitchEventPost = null;
@ -111,7 +105,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class);
TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class);
TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class);
TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class);
TableUtils.createTableIfNotExists(connectionSource, TDD.class);
TableUtils.createTableIfNotExists(connectionSource, InsightHistoryOffset.class);
@ -141,7 +134,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.dropTable(connectionSource, DbRequest.class, true);
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
TableUtils.dropTable(connectionSource, ExtendedBolus.class, true);
TableUtils.dropTable(connectionSource, CareportalEvent.class, true);
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
onCreate(database, connectionSource);
} else if (oldVersion < 10) {
@ -189,7 +181,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.dropTable(connectionSource, DbRequest.class, true);
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
TableUtils.dropTable(connectionSource, ExtendedBolus.class, true);
TableUtils.dropTable(connectionSource, CareportalEvent.class, true);
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
TableUtils.dropTable(connectionSource, TDD.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, TemporaryBasal.class);
TableUtils.createTableIfNotExists(connectionSource, ExtendedBolus.class);
TableUtils.createTableIfNotExists(connectionSource, CareportalEvent.class);
TableUtils.createTableIfNotExists(connectionSource, ProfileSwitch.class);
TableUtils.createTableIfNotExists(connectionSource, TDD.class);
TableUtils.createTableIfNotExists(connectionSource, OmnipodHistoryRecord.class);
@ -208,7 +198,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
virtualPumpPlugin.setFakingStatus(true);
scheduleTemporaryBasalChange();
scheduleExtendedBolusChange();
scheduleCareportalEventChange();
scheduleProfileSwitchChange();
new java.util.Timer().schedule(
new java.util.TimerTask() {
@ -244,16 +233,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
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() {
try {
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
@ -295,10 +274,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return getDao(ExtendedBolus.class);
}
private Dao<CareportalEvent, Long> getDaoCareportalEvents() throws SQLException {
return getDao(CareportalEvent.class);
}
private Dao<ProfileSwitch, Long> getDaoProfileSwitch() throws SQLException {
return getDao(ProfileSwitch.class);
}
@ -411,14 +386,20 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void deleteDbRequestbyMongoId(String action, String id) {
try {
QueryBuilder<DbRequest, String> queryBuilder = getDaoDbRequest().queryBuilder();
// By nsID
Where where = queryBuilder.where();
where.eq("_id", id).and().eq("action", action);
queryBuilder.limit(10L);
PreparedQuery<DbRequest> preparedQuery = queryBuilder.prepare();
List<DbRequest> dbList = getDaoDbRequest().query(preparedQuery);
for (DbRequest r : dbList) {
delete(r);
}
for (DbRequest r : dbList) 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) {
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 ---------------
public List<ProfileSwitch> getProfileSwitchData(long from, boolean ascending) {
@ -1726,9 +1494,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public long getCountOfAllRows() {
try {
return getDaoCareportalEvents().countOf()
+ getDaoExtendedBolus().countOf()
+ getDaoCareportalEvents().countOf()
return getDaoExtendedBolus().countOf()
+ getDaoProfileSwitch().countOf()
+ getDaoTDD().countOf()
+ getDaoTemporaryBasal().countOf();

View file

@ -24,10 +24,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
@Inject DatabaseHelperProvider() {
}
@Override public void createOrUpdate(@NonNull CareportalEvent careportalEvent) {
MainApp.Companion.getDbHelper().createOrUpdate(careportalEvent);
}
@Override public void createOrUpdate(@NonNull DanaRHistoryRecord record) {
MainApp.Companion.getDbHelper().createOrUpdate(record);
}
@ -92,10 +88,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
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) {
return MainApp.Companion.getDbHelper().getAllOmnipodHistoryRecordsFromTimeStamp(timestamp, ascending);
}
@ -168,10 +160,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
MainApp.Companion.getDbHelper().deleteExtendedBolusById(_id);
}
@Override public void deleteCareportalEventById(@NonNull String _id) {
MainApp.Companion.getDbHelper().deleteCareportalEventById(_id);
}
@Override public void deleteProfileSwitchById(@NonNull String _id) {
MainApp.Companion.getDbHelper().deleteProfileSwitchById(_id);
}
@ -184,10 +172,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
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) {
MainApp.Companion.getDbHelper().createProfileSwitchFromJsonIfNotExists(activePluginProvider, nsUpload, trJson);
}
@ -200,34 +184,10 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
MainApp.Companion.getDbHelper().createOrUpdate(record);
}
@Override public void delete(@NonNull CareportalEvent careportalEvent) {
MainApp.Companion.getDbHelper().delete(careportalEvent);
}
@Override public void delete(@NonNull ProfileSwitch 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) {
return MainApp.Companion.getDbHelper().getProfileSwitchEventsFromTime(from, to, ascending);
}
@ -236,10 +196,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
return MainApp.Companion.getDbHelper().getProfileSwitchEventsFromTime(mills, ascending);
}
@NonNull @Override public List<CareportalEvent> getAllCareportalEvents() {
return MainApp.Companion.getDbHelper().getAllCareportalEvents();
}
@NonNull @Override public List<ExtendedBolus> getAllExtendedBoluses() {
return MainApp.Companion.getDbHelper().getAllExtendedBoluses();
}
@ -260,10 +216,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
return MainApp.Companion.getDbHelper().getAllOHQueueItems(maxEntries);
}
@Override public void resetCareportalEvents() {
MainApp.Companion.getDbHelper().resetCareportalEvents();
}
@Override public void 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.database.AppRepository
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.databinding.DialogCarbsBinding
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.LTag
@ -271,11 +271,11 @@ class CarbsDialog : DialogFragmentWithDate() {
if (carbsAfterConstraints > 0) {
if (duration == 0) {
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 {
uel.log("CARBS", d1 = carbsAfterConstraints.toDouble(), i1 = timeOffset, i2 = duration)
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) {

View file

@ -13,20 +13,22 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.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.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
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.T
import info.nightscout.androidaps.utils.Translator
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
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.util.*
import javax.inject.Inject
@ -40,7 +42,9 @@ class CareDialog : DialogFragmentWithDate() {
@Inject lateinit var nsUpload: NSUpload
@Inject lateinit var translator: Translator
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var databaseHelper: DatabaseHelperInterface
@Inject lateinit var repository: AppRepository
private val disposable = CompositeDisposable()
enum class EventType {
BGCHECK,
@ -114,7 +118,7 @@ class CareDialog : DialogFragmentWithDate() {
when (options) {
EventType.QUESTION,
EventType.ANNOUNCEMENT,
EventType.BGCHECK -> {
EventType.BGCHECK -> {
binding.durationLayout.visibility = View.GONE
}
@ -126,7 +130,7 @@ class CareDialog : DialogFragmentWithDate() {
}
EventType.NOTE,
EventType.EXERCISE -> {
EventType.EXERCISE -> {
binding.bgLayout.visibility = View.GONE
binding.bgsource.visibility = View.GONE
}
@ -163,70 +167,62 @@ class CareDialog : DialogFragmentWithDate() {
}
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 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()
if (options == EventType.BGCHECK || options == EventType.QUESTION || options == EventType.ANNOUNCEMENT) {
val type =
val meterType =
when {
binding.meter.isChecked -> CareportalEvent.FINGER
binding.sensor.isChecked -> CareportalEvent.SENSOR
else -> CareportalEvent.MANUAL
binding.meter.isChecked -> TherapyEvent.MeterType.FINGER
binding.sensor.isChecked -> TherapyEvent.MeterType.SENSOR
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))
json.put("glucose", binding.bg.value)
json.put("glucoseType", type)
therapyEvent.glucoseType = meterType
therapyEvent.glucose = binding.bg.value
}
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()))
json.put("duration", binding.duration.value.toInt())
therapyEvent.duration = T.mins(binding.duration.value.toLong()).msecs()
}
val notes = binding.notesLayout.notes.text.toString()
if (notes.isNotEmpty()) {
actions.add(resourceHelper.gs(R.string.notes_label) + ": " + notes)
json.put("notes", notes)
therapyEvent.note = notes
}
eventTime -= eventTime % 1000
if (eventTimeChanged)
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime))
json.put("created_at", DateUtil.toISOString(eventTime))
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)
therapyEvent.enteredBy = enteredBy
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(event), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
val careportalEvent = CareportalEvent(injector)
careportalEvent.date = eventTime
careportalEvent.source = Source.USER
careportalEvent.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
}
careportalEvent.json = json.toString()
uel.log("CAREPORTAL", careportalEvent.eventType)
databaseHelper.createOrUpdate(careportalEvent)
nsUpload.uploadCareportalEntryToNS(json, eventTime)
disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction(therapyEvent)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadEvent(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it)
})
uel.log("CAREPORTAL", therapyEvent.type.text)
}, null)
}
return true

View file

@ -9,12 +9,15 @@ import com.google.common.base.Joiner
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
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.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
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.extensions.formatColor
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import java.util.*
import javax.inject.Inject
import kotlin.math.abs
@ -38,6 +43,9 @@ class FillDialog : DialogFragmentWithDate() {
@Inject lateinit var commandQueue: CommandQueueProvider
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var repository: AppRepository
private val disposable = CompositeDisposable()
private var _binding: DialogFillBinding? = null
@ -132,12 +140,28 @@ class FillDialog : DialogFragmentWithDate() {
}
if (siteChange) {
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) {
// add a second for case of both checked
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)
}

View file

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

View file

@ -12,8 +12,8 @@ import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.databinding.DialogTreatmentBinding
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.ActivePluginProvider
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)), {
uel.log("TREATMENT", d1 = insulin, i1 = carbs)
val detailedBolusInfo = DetailedBolusInfo()
if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = CareportalEvent.CARBCORRECTION
if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS
if (insulinAfterConstraints == 0.0) detailedBolusInfo.eventType = TherapyEvent.Type.CARBS_CORRECTION.text
if (carbsAfterConstraints == 0) detailedBolusInfo.eventType = TherapyEvent.Type.CORRECTION_BOLUS.text
detailedBolusInfo.insulin = insulinAfterConstraints
detailedBolusInfo.carbs = carbsAfterConstraints.toDouble()
detailedBolusInfo.context = context

View file

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

View file

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

View file

@ -30,8 +30,9 @@ import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.database.AppRepository;
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.db.CareportalEvent;
import info.nightscout.androidaps.database.transactions.SyncTherapyEventTransaction;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventChargingState;
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.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
public class NSClientPlugin extends PluginBase {
@ -424,14 +428,18 @@ public class NSClientPlugin extends PluginBase {
TemporaryTarget temporaryTarget = temporaryTargetFromNsIdForInvalidating(_id);
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)),
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
EventNsTreatment evtTreatment = new EventNsTreatment(EventNsTreatment.Companion.getREMOVE(), json);
rxBus.send(evtTreatment);
// old DB model
databaseHelper.deleteTempBasalById(_id);
databaseHelper.deleteExtendedBolusById(_id);
databaseHelper.deleteCareportalEventById(_id);
databaseHelper.deleteProfileSwitchById(_id);
}
@ -448,40 +456,52 @@ public class NSClientPlugin extends PluginBase {
if (insulin > 0 || carbs > 0) {
EventNsTreatment evtTreatment = new EventNsTreatment(mode, json);
rxBus.send(evtTreatment);
} else if (eventType.equals(CareportalEvent.TEMPORARYTARGET)) {
} else if (eventType.equals(TherapyEvent.Type.TEMPORARY_TARGET.getText())) {
TemporaryTarget temporaryTarget = temporaryTargetFromJson(json);
if (temporaryTarget != null) {
disposable.add(repository.runTransactionForResult(new SyncTemporaryTargetTransaction(temporaryTarget)).subscribe(
result -> {
result.getInserted().forEach(record -> uel.log("TT 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)));
disposable.add(repository.runTransactionForResult(new SyncTemporaryTargetTransaction(temporaryTarget))
.subscribe(
result -> {
result.getInserted().forEach(record -> uel.log("TT 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.DATABASE, "Error while saving temporary target", error)));
} else {
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);
} else if (eventType.equals(CareportalEvent.COMBOBOLUS)) {
} else if (eventType.equals(TherapyEvent.Type.COMBO_BOLUS.getText())) {
databaseHelper.createExtendedBolusFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.PROFILESWITCH)) {
} else if (eventType.equals(TherapyEvent.Type.PROFILE_SWITCH.getText())) {
databaseHelper.createProfileSwitchFromJsonIfNotExists(activePlugin, nsUpload, json);
} else if (eventType.equals(CareportalEvent.SITECHANGE) ||
eventType.equals(CareportalEvent.INSULINCHANGE) ||
eventType.equals(CareportalEvent.SENSORCHANGE) ||
eventType.equals(CareportalEvent.BGCHECK) ||
eventType.equals(CareportalEvent.NOTE) ||
eventType.equals(CareportalEvent.NONE) ||
eventType.equals(CareportalEvent.ANNOUNCEMENT) ||
eventType.equals(CareportalEvent.QUESTION) ||
eventType.equals(CareportalEvent.EXERCISE) ||
eventType.equals(CareportalEvent.OPENAPSOFFLINE) ||
eventType.equals(CareportalEvent.PUMPBATTERYCHANGE)) {
databaseHelper.createCareportalEventFromJsonIfNotExists(json);
} else if (eventType.equals(TherapyEvent.Type.CANNULA_CHANGE.getText()) ||
eventType.equals(TherapyEvent.Type.INSULIN_CHANGE.getText()) ||
eventType.equals(TherapyEvent.Type.SENSOR_CHANGE.getText()) ||
eventType.equals(TherapyEvent.Type.FINGER_STICK_BG_VALUE.getText()) ||
eventType.equals(TherapyEvent.Type.NOTE.getText()) ||
eventType.equals(TherapyEvent.Type.NONE.getText()) ||
eventType.equals(TherapyEvent.Type.ANNOUNCEMENT.getText()) ||
eventType.equals(TherapyEvent.Type.QUESTION.getText()) ||
eventType.equals(TherapyEvent.Type.EXERCISE.getText()) ||
eventType.equals(TherapyEvent.Type.APS_OFFLINE.getText()) ||
eventType.equals(TherapyEvent.Type.PUMP_BATTERY_CHANGE.getText())) {
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 now = System.currentTimeMillis();
String enteredBy = JsonHelper.safeGetString(json, "enteredBy", "");
@ -498,9 +518,12 @@ public class NSClientPlugin extends PluginBase {
}
private void storeMbg(JSONObject mbgJson) {
NSMbg nsMbg = new NSMbg(mbgJson);
CareportalEvent careportalEvent = new CareportalEvent(nsMbg);
databaseHelper.createOrUpdate(careportalEvent);
aapsLogger.debug(LTag.DATASERVICE, "Adding/Updating new MBG: " + careportalEvent.toString());
NSMbg nsMbg = new NSMbg(getInjector(), mbgJson);
if (nsMbg.mbg != 0.0 && nsMbg.date != 0)
disposable.add(repository.runTransactionForResult(new SyncTherapyEventTransaction(therapyEventFromNsMbg(nsMbg)))
.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.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.db.*
import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
@ -198,23 +199,16 @@ class OpenHumansUploader @Inject constructor(
}
@JvmOverloads
fun enqueueCareportalEvent(careportalEvent: CareportalEvent, deleted: Boolean = false) = insertQueueItem("CareportalEvents") {
put("date", careportalEvent.date)
put("isValid", careportalEvent.isValid)
put("source", careportalEvent.source)
put("nsId", careportalEvent._id)
put("eventType", careportalEvent.eventType)
val data = JSONObject(careportalEvent.json)
val reducedData = JSONObject()
if (data.has("mgdl")) reducedData.put("mgdl", data.getDouble("mgdl"))
if (data.has("glucose")) reducedData.put("glucose", data.getDouble("glucose"))
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)
fun enqueueTherapyEvent(therapyEvent: TherapyEvent, deleted: Boolean = false) = insertQueueItem("TherapyEvents") {
put("date", therapyEvent.timestamp)
put("isValid", therapyEvent.isValid)
put("nsId", therapyEvent.interfaceIDs.nightscoutId)
put("eventType", therapyEvent.type.text)
put("glucose", therapyEvent.glucose)
put("units", therapyEvent.units)
put("glucoseType", therapyEvent.glucoseType?.text)
put("units", therapyEvent.units)
put("duration", therapyEvent.duration)
put("isDeletion", deleted)
}
@ -370,8 +364,8 @@ class OpenHumansUploader @Inject constructor(
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetBgReadingsDataFromTime(0, true).blockingGet()) })
.map { enqueueBGReading(it); increaseCounter() }
.ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllCareportalEvents()) })
.map { enqueueCareportalEvent(it); increaseCounter() }
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetTherapyEventDataFromTime(0, true).blockingGet()) })
.map { enqueueTherapyEvent(it); increaseCounter() }
.ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllExtendedBoluses()) })
.map { enqueueExtendedBolus(it); increaseCounter() }

View file

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

View file

@ -5,14 +5,16 @@ import android.widget.TextView
import androidx.annotation.StringRes
import info.nightscout.androidaps.Config
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.DatabaseHelperInterface
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.driver.definition.OmnipodConstants
import info.nightscout.androidaps.utils.DecimalFormatter
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.sharedPreferences.SP
import javax.inject.Inject
@ -25,7 +27,7 @@ class StatusLightHandler @Inject constructor(
private val activePlugin: ActivePluginProvider,
private val warnColors: WarnColors,
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?) {
val pump = activePlugin.activePump
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_insulin_age, CareportalEvent.INSULINCHANGE, 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_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, TherapyEvent.Type.INSULIN_CHANGE, R.string.key_statuslights_iage_warning, 72.0, R.string.key_statuslights_iage_critical, 144.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)) {
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 (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 urgent = sp.getDouble(urgentSettings, defaultUrgentThreshold)
val careportalEvent = databaseHelper.getLastCareportalEvent(eventName)
if (careportalEvent != null) {
warnColors.setColorByAge(view, careportalEvent, warn, urgent)
view?.text = careportalEvent.age(resourceHelper.shortTextMode(), resourceHelper)
val therapyEvent = repository.getLastTherapyRecord(type).blockingGet()
if (therapyEvent is ValueWrapper.Existing) {
warnColors.setColorByAge(view, therapyEvent.value, warn, urgent)
view?.text = therapyEvent.value.age(resourceHelper.shortTextMode(), resourceHelper)
} else {
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.IobTotal
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.TherapyEventDataPoint
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.GlucoseValue
@ -268,10 +269,12 @@ class GraphData(
}
// 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)
.forEach {
it.y = getNearestBg(it.x.toLong())
if (it.y == 0.0) it.y = getNearestBg(it.x.toLong())
filteredTreatments.add(it)
}

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.general.tidepool.comm
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Intervals
import info.nightscout.androidaps.database.AppRepository
@ -23,10 +22,10 @@ import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.max
import kotlin.math.min
@Singleton
class UploadChunk @Inject constructor(
private val injector: HasAndroidInjector,
private val sp: SP,
private val rxBus: RxBusWrapper,
private val aapsLogger: AAPSLogger,
@ -38,19 +37,19 @@ class UploadChunk @Inject constructor(
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? {
if (session == null)
return null
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)
if (result.length < 3) {
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
}
@ -62,7 +61,7 @@ class UploadChunk @Inject constructor(
aapsLogger.debug(LTag.TIDEPOOL, "End is <= start: " + dateUtil.dateAndTimeString(start) + " " + dateUtil.dateAndTimeString(end))
return ""
}
if (end - start > MAX_UPLOAD_SIZE) {
if (end - start > maxUploadSize) {
aapsLogger.debug(LTag.TIDEPOOL, "More than max range - rejecting")
return ""
}
@ -128,7 +127,7 @@ class UploadChunk @Inject constructor(
}
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)
if (selection.isNotEmpty())
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> {
val results = LinkedList<BasalElement>()
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))
}
return results
}
private fun getBasals(start: Long, end: Long): List<BasalElement> {
val tbrs = treatmentsPlugin.temporaryBasalsFromHistory
tbrs.merge()
val selection = fromTemporaryBasals(tbrs, start, end) // TODO do not upload running TBR
val temporaryBasals = treatmentsPlugin.temporaryBasalsFromHistory
temporaryBasals.merge()
val selection = fromTemporaryBasals(temporaryBasals, start, end) // TODO do not upload running TBR
if (selection.isNotEmpty())
rxBus.send(EventTidepoolStatus("${selection.size} TBRs selected for upload"))
return selection
}
fun newInstanceOrNull(ps: ProfileSwitch): ProfileElement? = try {
private fun newInstanceOrNull(ps: ProfileSwitch): ProfileElement? = try {
ProfileElement(ps, activePlugin.activePump.serialNumber())
} catch (e: Throwable) {
null

View file

@ -1,36 +1,36 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
import info.nightscout.androidaps.database.entities.TherapyEvent
import java.util.*
class BloodGlucoseElement(careportalEvent: CareportalEvent)
: BaseElement(careportalEvent.date, UUID.nameUUIDFromBytes(("AAPS-bg" + careportalEvent.date).toByteArray()).toString()) {
class BloodGlucoseElement(therapyEvent: TherapyEvent)
: BaseElement(therapyEvent.timestamp, UUID.nameUUIDFromBytes(("AAPS-bg" + therapyEvent.timestamp).toByteArray()).toString()) {
@Expose
var subType: String = "manual"
@Expose
var units: String = "mg/dL"
@Expose
var value: Int = 0
init {
type = "cbg"
subType = "manual" // TODO
val json = if (careportalEvent.json != null) JSONObject(careportalEvent.json) else JSONObject()
value = Profile.toMgdl(JsonHelper.safeGetDouble(json, "glucose"), JsonHelper.safeGetString(json, "units", Constants.MGDL)).toInt()
value = if (therapyEvent.glucose != null && therapyEvent.units != null)
Profile.toMgdl(therapyEvent.glucose!!, therapyEvent.units).toInt()
else 0
}
companion object {
fun fromCareportalEvents(careportalList: List<CareportalEvent>): List<BloodGlucoseElement> {
fun fromCareportalEvents(careportalList: List<TherapyEvent>): List<BloodGlucoseElement> {
val results = LinkedList<BloodGlucoseElement>()
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)
if (bge.value > 0)
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.ValueWrapper
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.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TDD
import info.nightscout.androidaps.interfaces.*
@ -545,7 +545,7 @@ class ActionStringHandler @Inject constructor(
private fun doECarbs(carbs: Int, time: Long, duration: Int) {
if (carbs > 0) {
if (duration == 0) {
carbsGenerator.createCarb(carbs, time, CareportalEvent.CARBCORRECTION, "watch")
carbsGenerator.createCarb(carbs, time, TherapyEvent.Type.CARBS_CORRECTION.text, "watch")
} else {
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.R
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.interfaces.DatabaseHelperInterface
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.IobCobCalculatorPlugin.Companion.percentile
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.sharedPreferences.SP
import org.json.JSONException
@ -34,7 +36,8 @@ open class SensitivityAAPSPlugin @Inject constructor(
sp: SP?,
private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil,
private val databaseHelper: DatabaseHelperInterface
private val databaseHelper: DatabaseHelperInterface,
private val repository: AppRepository
) : AbstractSensitivityPlugin(PluginDescription()
.mainType(PluginType.SENSITIVITY)
.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())
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 deviationsArray: MutableList<Double> = ArrayList()
var pastSensitivity = ""
@ -84,7 +87,7 @@ open class SensitivityAAPSPlugin @Inject constructor(
}
// reset deviations after site change
if (CareportalEvent(injector).isEvent5minBack(siteChanges, autosensData.time)) {
if (isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear()
pastSensitivity += "(SITECHANGE)"
}

View file

@ -4,7 +4,8 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
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.interfaces.DatabaseHelperInterface
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.IobCobCalculatorPlugin.Companion.percentile
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.sharedPreferences.SP
import org.json.JSONException
@ -35,7 +37,8 @@ open class SensitivityOref1Plugin @Inject constructor(
sp: SP?,
private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil,
private val databaseHelper: DatabaseHelperInterface
private val databaseHelper: DatabaseHelperInterface,
private val repository: AppRepository
) : AbstractSensitivityPlugin(PluginDescription()
.mainType(PluginType.SENSITIVITY)
.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())
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)
//[0] = 8 hour
@ -100,7 +103,7 @@ open class SensitivityOref1Plugin @Inject constructor(
var pastSensitivity = pastSensitivityArray[hourSegment]
// reset deviations after site change
if (CareportalEvent(injector).isEvent5minBack(siteChanges, autosensData.time)) {
if (isEvent5minBack(siteChanges, autosensData.time)) {
deviationsArray.clear()
pastSensitivity += "(SITECHANGE)"
}

View file

@ -5,7 +5,8 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
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.interfaces.DatabaseHelperInterface
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.plugins.iob.iobCobCalculator.AutosensResult
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.sharedPreferences.SP
import org.json.JSONException
@ -33,7 +35,8 @@ open class SensitivityWeightedAveragePlugin @Inject constructor(
sp: SP,
private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil,
private val databaseHelper: DatabaseHelperInterface
private val databaseHelper: DatabaseHelperInterface,
private val repository: AppRepository
) : AbstractSensitivityPlugin(PluginDescription()
.mainType(PluginType.SENSITIVITY)
.pluginIcon(R.drawable.ic_generic_icon)
@ -66,7 +69,7 @@ open class SensitivityWeightedAveragePlugin @Inject constructor(
aapsLogger.debug(LTag.AUTOSENS, "No profile available")
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)
var pastSensitivity = ""
var index = 0
@ -87,7 +90,7 @@ open class SensitivityWeightedAveragePlugin @Inject constructor(
}
// reset deviations after site change
if (CareportalEvent(injector).isEvent5minBack(siteChanges, autosensData.time)) {
if (isEvent5minBack(siteChanges, autosensData.time)) {
data.clear()
pastSensitivity += "(SITECHANGE)"
}

View file

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

View file

@ -4,7 +4,7 @@ import android.content.Context
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
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.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider
@ -14,6 +14,7 @@ import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.roundToInt
@Singleton
class CarbsGenerator @Inject constructor(
@ -28,9 +29,9 @@ class CarbsGenerator @Inject constructor(
val ticks = duration * 4 //duration guaranteed to be integer greater zero
for (i in 0 until ticks) {
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()
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 dagger.android.support.DaggerFragment
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.TreatmentsCareportalItemBinding
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.events.EventCareportalEventChange
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.events.EventTherapyEventChange
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
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.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.Translator
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
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.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.Completable
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import io.reactivex.rxkotlin.subscribeBy
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class TreatmentsCareportalFragment : DaggerFragment() {
private val disposable = CompositeDisposable()
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var sp: SP
@Inject lateinit var resourceHelper: ResourceHelper
@ -45,9 +55,13 @@ class TreatmentsCareportalFragment : DaggerFragment() {
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var databaseHelper: DatabaseHelperInterface
@Inject lateinit var repository: AppRepository
@Inject lateinit var uel: UserEntryLogger
private val disposable = CompositeDisposable()
private val millsToThePast = T.days(30).msecs()
private var _binding: TreatmentsCareportalFragmentBinding? = null
// This property is only valid between onCreateView and
@ -61,12 +75,17 @@ class TreatmentsCareportalFragment : DaggerFragment() {
super.onViewCreated(view, savedInstanceState)
binding.recyclerview.setHasFixedSize(true)
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
binding.recyclerview.adapter = RecyclerViewAdapter(databaseHelper.getCareportalEvents(false))
binding.refreshFromNightscout.setOnClickListener {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal), resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", Runnable {
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())
})
}
@ -75,34 +94,58 @@ class TreatmentsCareportalFragment : DaggerFragment() {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal), resourceHelper.gs(R.string.careportal_removestartedevents), Runnable {
uel.log("REMOVED RESTART EVENTS")
val events = databaseHelper.getCareportalEvents(false)
for (i in events.indices) {
val careportalEvent = events[i]
if (careportalEvent.json.contains(resourceHelper.gs(R.string.androidaps_start))) {
if (NSUpload.isIdValid(careportalEvent._id))
nsUpload.removeCareportalEntryFromNS(careportalEvent._id)
else
uploadQueue.removeID("dbAdd", careportalEvent._id)
databaseHelper.delete(careportalEvent)
}
}
// val events = databaseHelper.getCareportalEvents(false)
repository.runTransactionForResult(InvalidateAAPSStartedTherapyEventTransaction())
.subscribe({ result ->
result.invalidated.forEach { event ->
if (NSUpload.isIdValid(event.interfaceIDs.nightscoutId))
nsUpload.removeCareportalEntryFromNS(event.interfaceIDs.nightscoutId)
else
uploadQueue.removeID("dbAdd", event.timestamp.toString())
}
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while invalidating therapy event", it)
})
}, null)
}
}
val nsUploadOnly = sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode()
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
override fun onResume() {
super.onResume()
swapAdapter()
disposable.add(rxBus
.toObservable(EventCareportalEventChange::class.java)
.toObservable(EventTherapyEventChange::class.java)
.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
@ -114,53 +157,53 @@ class TreatmentsCareportalFragment : DaggerFragment() {
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
binding.recyclerview.adapter = null // avoid leaks
_binding = null
}
private fun updateGui() {
if (_binding == null) return
binding.recyclerview.swapAdapter(RecyclerViewAdapter(databaseHelper.getCareportalEvents(false)), false)
}
inner class RecyclerViewAdapter internal constructor(private var list: List<TherapyEvent>) : RecyclerView.Adapter<TherapyEventsViewHolder>() {
inner class RecyclerViewAdapter internal constructor(private var careportalEventList: List<CareportalEvent>) : RecyclerView.Adapter<CareportalEventsViewHolder>() {
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): CareportalEventsViewHolder {
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): TherapyEventsViewHolder {
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) {
val careportalEvent = careportalEventList[position]
holder.binding.ns.visibility = if (NSUpload.isIdValid(careportalEvent._id)) View.VISIBLE else View.GONE
holder.binding.date.text = dateUtil.dateAndTimeString(careportalEvent.date)
holder.binding.duration.text = if (careportalEvent.durationInMsec() == 0L) "" else DateUtil.niceTimeScalar(careportalEvent.durationInMsec(), resourceHelper)
holder.binding.note.text = careportalEvent.notes
holder.binding.type.text = translator.translate(careportalEvent.eventType)
holder.binding.remove.tag = careportalEvent
override fun onBindViewHolder(holder: TherapyEventsViewHolder, position: Int) {
val therapyEvent = list[position]
holder.binding.ns.visibility = (therapyEvent.interfaceIDs.nightscoutId != null).toVisibility()
holder.binding.invalid.visibility = therapyEvent.isValid.not().toVisibility()
holder.binding.date.text = dateUtil.dateAndTimeString(therapyEvent.timestamp)
holder.binding.duration.text = if (therapyEvent.duration == 0L) "" else DateUtil.niceTimeScalar(therapyEvent.duration, resourceHelper)
holder.binding.note.text = therapyEvent.note
holder.binding.type.text = translator.translate(therapyEvent.type.text)
holder.binding.remove.tag = therapyEvent
}
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)
init {
binding.remove.setOnClickListener { v: View ->
val careportalEvent = v.tag as CareportalEvent
val therapyEvent = v.tag as TherapyEvent
activity?.let { activity ->
val text = resourceHelper.gs(R.string.eventtype) + ": " + translator.translate(careportalEvent.eventType) + "\n" +
resourceHelper.gs(R.string.notes_label) + ": " + careportalEvent.notes + "\n" +
resourceHelper.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(careportalEvent.date)
val text = resourceHelper.gs(R.string.eventtype) + ": " + translator.translate(therapyEvent.type.text) + "\n" +
resourceHelper.gs(R.string.notes_label) + ": " + (therapyEvent.note ?: "") + "\n" +
resourceHelper.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(therapyEvent.timestamp)
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable {
uel.log("REMOVED CAREP", text)
if (NSUpload.isIdValid(careportalEvent._id))
nsUpload.removeCareportalEntryFromNS(careportalEvent._id)
else
uploadQueue.removeID("dbAdd", careportalEvent._id)
databaseHelper.delete(careportalEvent)
uel.log("REMOVED CAREPORTAL", text)
disposable += repository.runTransactionForResult(InvalidateTherapyEventTransaction(therapyEvent.id))
.subscribe({
val id = therapyEvent.interfaceIDs.nightscoutId
if (NSUpload.isIdValid(id)) nsUpload.removeCareportalEntryFromNS(id)
else uploadQueue.removeID("dbAdd", therapyEvent.timestamp.toString())
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while invalidating therapy event", it)
})
}, null)
}
}

View file

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

View file

@ -1,4 +1,5 @@
<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"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -14,7 +15,7 @@
android:id="@+id/refresh_from_nightscout"
style="?android:attr/buttonStyle"
android:layout_width="0px"
android:layout_height="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:drawableStart="@drawable/ic_refresh"
@ -24,12 +25,28 @@
android:id="@+id/remove_androidaps_started_events"
style="?android:attr/buttonStyle"
android:layout_width="0px"
android:layout_height="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:drawableStart="@drawable/ic_remove"
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>
<androidx.recyclerview.widget.RecyclerView

View file

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

View file

@ -42,8 +42,6 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
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.modules.junit4.PowerMockRunner
import java.util.*
@ -144,7 +142,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
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)
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)
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())
@ -184,7 +182,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
Assert.assertEquals(false, c.value())
`when`(sp.getString(R.string.key_aps_mode, "open")).thenReturn("open")
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(false, c.value())
}

View file

@ -7,7 +7,12 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R
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.configBuilder.ConstraintChecker
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.treatments.TreatmentsPlugin
import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -30,7 +36,7 @@ import org.powermock.modules.junit4.PowerMockRunner
@RunWith(PowerMockRunner::class)
@PrepareForTest(
ConstraintChecker::class, VirtualPumpPlugin::class, FabricPrivacy::class, ReceiverStatusStore::class,
IobCobCalculatorPlugin::class)
IobCobCalculatorPlugin::class, AppRepository::class)
class LoopPluginTest : TestBase() {
@Mock lateinit var sp: SP
@ -48,14 +54,15 @@ class LoopPluginTest : TestBase() {
@Mock lateinit var receiverStatusStore: ReceiverStatusStore
@Mock lateinit var nsUpload: NSUpload
@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
val injector = HasAndroidInjector { AndroidInjector { } }
@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`(context.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(notificationManager)
}

View file

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

View file

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

View file

@ -5,25 +5,32 @@ import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.data.GlucoseValueDataPoint
import info.nightscout.androidaps.data.Profile
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.plugins.aps.loop.APSResult
import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
@Module
@Suppress("unused")
abstract class CoreDataClassesModule {
@ContributesAndroidInjector abstract fun nsMbgInjector(): NSMbg
@ContributesAndroidInjector abstract fun pumpEnactResultInjector(): PumpEnactResult
@ContributesAndroidInjector abstract fun apsResultInjector(): APSResult
@ContributesAndroidInjector abstract fun autosensDataInjector(): AutosensData
@ContributesAndroidInjector abstract fun profileInjector(): Profile
@ContributesAndroidInjector abstract fun profileStoreInjector(): ProfileStore
@ContributesAndroidInjector abstract fun glucoseValueDataPointInjector(): GlucoseValueDataPoint
@ContributesAndroidInjector abstract fun treatmentInjector(): Treatment
@ContributesAndroidInjector abstract fun profileSwitchInjector(): ProfileSwitch
@ContributesAndroidInjector abstract fun temporaryBasalInjector(): TemporaryBasal
@ContributesAndroidInjector abstract fun careportalEventInjector(): CareportalEvent
@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 info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.database.entities.TherapyEvent;
import info.nightscout.androidaps.db.Source;
/**
@ -16,7 +16,7 @@ import info.nightscout.androidaps.db.Source;
public class DetailedBolusInfo {
public long date = System.currentTimeMillis();
public long lastKnownBolusTime;
public String eventType = CareportalEvent.MEALBOLUS;
public String eventType = TherapyEvent.Type.MEAL_BOLUS.getText();
public double insulin = 0;
public double carbs = 0;
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 createOrUpdate(careportalEvent: CareportalEvent)
fun createOrUpdate(extendedBolus: ExtendedBolus): Boolean
fun createOrUpdate(profileSwitch: ProfileSwitch)
fun createOrUpdate(record: DanaRHistoryRecord)
@ -26,7 +25,6 @@ interface DatabaseHelperInterface {
fun deleteDbRequest(id: String): Int
fun delete(tempBasal: TemporaryBasal)
fun delete(extendedBolus: ExtendedBolus)
fun delete(careportalEvent: CareportalEvent)
fun delete(profileSwitch: ProfileSwitch)
fun deleteDbRequestbyMongoId(action: String, _id: String)
fun getDbRequestIterator(): CloseableIterator<DbRequest>
@ -36,12 +34,6 @@ interface DatabaseHelperInterface {
fun findTempBasalByPumpId(id: Long): TemporaryBasal
fun getTemporaryBasalsDataFromTime(mills: Long, ascending: Boolean): List<TemporaryBasal>
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(mills: Long, ascending: Boolean): List<ProfileSwitch>
fun getAllOmnipodHistoryRecordsFromTimestamp(timestamp: Long, ascending: Boolean): List<OmnipodHistoryRecord>
@ -49,23 +41,19 @@ interface DatabaseHelperInterface {
fun getTDDsForLastXDays(days: Int): List<TDD>
fun getProfileSwitchData(from: Long, ascending: Boolean): List<ProfileSwitch>
fun getExtendedBolusByPumpId(pumpId: Long): ExtendedBolus?
fun getAllCareportalEvents(): List<CareportalEvent>
fun getAllExtendedBoluses(): List<ExtendedBolus>
fun getAllProfileSwitches(): List<ProfileSwitch>
fun getAllTDDs(): List<TDD>
fun getAllTemporaryBasals(): List<TemporaryBasal>
fun getAllOHQueueItems(maxEntries: Long): List<OHQueueItem>
fun resetCareportalEvents()
fun resetProfileSwitch()
// old DB model
fun deleteTempBasalById(_id: String)
fun deleteExtendedBolusById(_id: String)
fun deleteCareportalEventById(_id: String)
fun deleteProfileSwitchById(_id: String)
fun createTempBasalFromJsonIfNotExists(json: JSONObject)
fun createExtendedBolusFromJsonIfNotExists(json: JSONObject)
fun createCareportalEventFromJsonIfNotExists(json: JSONObject)
fun createProfileSwitchFromJsonIfNotExists(activePluginProvider: ActivePluginProvider, nsUpload: NSUpload, trJson: JSONObject)
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.database.entities.GlucoseValue;
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.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface;
import info.nightscout.androidaps.interfaces.LoopInterface;
import info.nightscout.androidaps.interfaces.ProfileFunction;
@ -51,12 +49,10 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP;
@Singleton
public class NSUpload {
private final HasAndroidInjector injector;
private final AAPSLogger aapsLogger;
private final ResourceHelper resourceHelper;
private final SP sp;
private final UploadQueueInterface uploadQueue;
private final DatabaseHelperInterface databaseHelper;
private final RunningConfiguration runningConfiguration;
private final ProfileFunction profileFunction;
@ -64,29 +60,25 @@ public class NSUpload {
@Inject
public NSUpload(
HasAndroidInjector injector,
AAPSLogger aapsLogger,
ResourceHelper resourceHelper,
SP sp,
UploadQueueInterface uploadQueue,
RunningConfiguration runningConfiguration,
DatabaseHelperInterface databaseHelper,
ProfileFunction profileFunction
) {
this.injector = injector;
this.aapsLogger = aapsLogger;
this.resourceHelper = resourceHelper;
this.sp = sp;
this.uploadQueue = uploadQueue;
this.runningConfiguration = runningConfiguration;
this.databaseHelper = databaseHelper;
this.profileFunction = profileFunction;
}
public void uploadTempBasalStartAbsolute(TemporaryBasal temporaryBasal, Double originalExtendedAmount) {
try {
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPBASAL);
data.put("eventType", TherapyEvent.Type.TEMPORARY_BASAL.getText());
data.put("duration", temporaryBasal.durationInMinutes);
data.put("absolute", temporaryBasal.absoluteRate);
data.put("rate", temporaryBasal.absoluteRate);
@ -118,7 +110,7 @@ public class NSUpload {
}
} else {
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPBASAL);
data.put("eventType", TherapyEvent.Type.TEMPORARY_BASAL.getText());
data.put("duration", temporaryBasal.durationInMinutes);
data.put("percent", temporaryBasal.percentRate - 100);
if (profile != null)
@ -137,7 +129,7 @@ public class NSUpload {
public void uploadTempBasalEnd(long time, boolean isFakedTempBasal, long pumpId) {
try {
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("enteredBy", "openaps://" + "AndroidAPS");
if (isFakedTempBasal)
@ -153,7 +145,7 @@ public class NSUpload {
public void uploadExtendedBolus(ExtendedBolus extendedBolus) {
try {
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.COMBOBOLUS);
data.put("eventType", TherapyEvent.Type.COMBO_BOLUS.getText());
data.put("duration", extendedBolus.durationInMinutes);
data.put("splitNow", 0);
data.put("splitExt", 100);
@ -172,7 +164,7 @@ public class NSUpload {
public void uploadExtendedBolusEnd(long time, long pumpId) {
try {
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.COMBOBOLUS);
data.put("eventType", TherapyEvent.Type.COMBO_BOLUS.getText());
data.put("duration", 0);
data.put("splitNow", 0);
data.put("splitExt", 100);
@ -293,7 +285,7 @@ public class NSUpload {
public void uploadTempTarget(TemporaryTarget tempTarget) {
try {
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(ISVALID, tempTarget.isValid());
if (tempTarget.getLowTarget() > 0) {
@ -313,7 +305,7 @@ public class NSUpload {
public void updateTempTarget(TemporaryTarget tempTarget) {
try {
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(ISVALID, tempTarget.isValid());
if (tempTarget.getLowTarget() > 0) {
@ -343,7 +335,7 @@ public class NSUpload {
private static JSONObject getJson(ProfileSwitch profileSwitch) throws JSONException {
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.PROFILESWITCH);
data.put("eventType", TherapyEvent.Type.PROFILE_SWITCH.getText());
data.put("duration", profileSwitch.durationInMinutes);
data.put("profile", profileSwitch.getCustomizedName());
data.put("profileJson", profileSwitch.profileJson);
@ -382,21 +374,11 @@ public class NSUpload {
}
// TODO replace with seting isValid = false
public void removeCareportalEntryFromNS(String _id) {
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) {
uploadError(error, new Date());
}
@ -473,6 +455,7 @@ public class NSUpload {
data.put("eventType", careportalEvent);
data.put("created_at", DateUtil.toISOString(time));
data.put("enteredBy", sp.getString("careportal_enteredby", "AndroidAPS"));
data.put("units", profileFunction.getUnits());
if (notes != null) {
data.put("notes", notes);
}
@ -482,6 +465,23 @@ public class NSUpload {
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) {
try {
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) {
if (JsonHelper.safeGetString(data, "eventType", "").equals(CareportalEvent.PROFILESWITCH)) {
if (JsonHelper.safeGetString(data, "eventType", "").equals(TherapyEvent.Type.PROFILE_SWITCH.getText())) {
ProfileSwitch profileSwitch = profileFunction.prepareProfileSwitch(
profileStore,
JsonHelper.safeGetString(data, "profile"),
@ -513,27 +513,4 @@ public class NSUpload {
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.JSONObject;
import org.slf4j.Logger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
import javax.inject.Inject;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.logging.AAPSLogger;
public class NSMbg {
private static final Logger log = StacktraceLoggerWrapper.getLogger(LTag.NSCLIENT);
@Inject public AAPSLogger aapsLogger;
public long date;
public double mbg;
public String json;
public NSMbg(JSONObject json) {
public NSMbg(HasAndroidInjector injector) {
injector.androidInjector().inject(this);
}
public NSMbg(HasAndroidInjector injector, JSONObject json) {
this(injector);
try {
date = json.getLong("mills");
mbg = json.getDouble("mgdl");
this.json = json.toString();
} catch (JSONException e) {
log.error("Unhandled exception", e);
log.error("Data: " + json.toString());
aapsLogger.error("Unhandled exception", e);
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
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 javax.inject.Inject
import javax.inject.Singleton
/**
* Created by mike on 15.07.2016.
*/
@Singleton
class Translator @Inject internal constructor(
private val resourceHelper: ResourceHelper
@ -16,31 +13,33 @@ class Translator @Inject internal constructor(
fun translate(text: String): String =
when (text) {
CareportalEvent.BGCHECK -> resourceHelper.gs(R.string.careportal_bgcheck)
CareportalEvent.SNACKBOLUS -> resourceHelper.gs(R.string.careportal_snackbolus)
CareportalEvent.MEALBOLUS -> resourceHelper.gs(R.string.careportal_mealbolus)
CareportalEvent.CORRECTIONBOLUS -> resourceHelper.gs(R.string.careportal_correctionbolus)
CareportalEvent.CARBCORRECTION -> resourceHelper.gs(R.string.careportal_carbscorrection)
CareportalEvent.COMBOBOLUS -> resourceHelper.gs(R.string.careportal_combobolus)
CareportalEvent.ANNOUNCEMENT -> resourceHelper.gs(R.string.careportal_announcement)
CareportalEvent.NOTE -> resourceHelper.gs(R.string.careportal_note)
CareportalEvent.QUESTION -> resourceHelper.gs(R.string.careportal_question)
CareportalEvent.EXERCISE -> resourceHelper.gs(R.string.careportal_exercise)
CareportalEvent.SITECHANGE -> resourceHelper.gs(R.string.careportal_pumpsitechange)
CareportalEvent.PUMPBATTERYCHANGE -> resourceHelper.gs(R.string.careportal_pumpbatterychange)
CareportalEvent.SENSORSTART -> resourceHelper.gs(R.string.careportal_cgmsensorstart)
CareportalEvent.SENSORCHANGE -> resourceHelper.gs(R.string.careportal_cgmsensorinsert)
CareportalEvent.INSULINCHANGE -> resourceHelper.gs(R.string.careportal_insulincartridgechange)
CareportalEvent.TEMPBASALSTART -> resourceHelper.gs(R.string.careportal_tempbasalstart)
CareportalEvent.TEMPBASALEND -> resourceHelper.gs(R.string.careportal_tempbasalend)
CareportalEvent.PROFILESWITCH -> resourceHelper.gs(R.string.careportal_profileswitch)
CareportalEvent.TEMPORARYTARGET -> resourceHelper.gs(R.string.careportal_temporarytarget)
CareportalEvent.TEMPBASALCANCEL -> resourceHelper.gs(R.string.careportal_temporarytargetcancel)
CareportalEvent.OPENAPSOFFLINE -> resourceHelper.gs(R.string.careportal_openapsoffline)
CareportalEvent.MBG -> resourceHelper.gs(R.string.careportal_mbg)
CareportalEvent.FINGER -> resourceHelper.gs(R.string.glucosetype_finger)
CareportalEvent.SENSOR -> resourceHelper.gs(R.string.glucosetype_sensor)
CareportalEvent.MANUAL -> resourceHelper.gs(R.string.manual)
else -> resourceHelper.gs(R.string.unknown)
TherapyEvent.Type.FINGER_STICK_BG_VALUE.text -> resourceHelper.gs(R.string.careportal_bgcheck)
TherapyEvent.Type.SNACK_BOLUS.text -> resourceHelper.gs(R.string.careportal_snackbolus)
TherapyEvent.Type.MEAL_BOLUS.text -> resourceHelper.gs(R.string.careportal_mealbolus)
TherapyEvent.Type.CORRECTION_BOLUS.text -> resourceHelper.gs(R.string.careportal_correctionbolus)
TherapyEvent.Type.CARBS_CORRECTION.text -> resourceHelper.gs(R.string.careportal_carbscorrection)
TherapyEvent.Type.COMBO_BOLUS.text -> resourceHelper.gs(R.string.careportal_combobolus)
TherapyEvent.Type.ANNOUNCEMENT.text -> resourceHelper.gs(R.string.careportal_announcement)
TherapyEvent.Type.NOTE.text -> resourceHelper.gs(R.string.careportal_note)
TherapyEvent.Type.QUESTION.text -> resourceHelper.gs(R.string.careportal_question)
TherapyEvent.Type.EXERCISE.text -> resourceHelper.gs(R.string.careportal_exercise)
TherapyEvent.Type.CANNULA_CHANGE.text -> resourceHelper.gs(R.string.careportal_pumpsitechange)
TherapyEvent.Type.PUMP_BATTERY_CHANGE.text -> resourceHelper.gs(R.string.careportal_pumpbatterychange)
TherapyEvent.Type.SENSOR_STARTED.text -> resourceHelper.gs(R.string.careportal_cgmsensorstart)
TherapyEvent.Type.SENSOR_STOPPED.text -> resourceHelper.gs(R.string.careportal_cgm_sensor_stop)
TherapyEvent.Type.SENSOR_CHANGE.text -> resourceHelper.gs(R.string.careportal_cgmsensorinsert)
TherapyEvent.Type.INSULIN_CHANGE.text -> resourceHelper.gs(R.string.careportal_insulincartridgechange)
TherapyEvent.Type.DAD_ALERT.text -> resourceHelper.gs(R.string.careportal_dad_alert)
TherapyEvent.Type.TEMPORARY_BASAL_START.text -> resourceHelper.gs(R.string.careportal_tempbasalstart)
TherapyEvent.Type.TEMPORARY_BASAL_END.text -> resourceHelper.gs(R.string.careportal_tempbasalend)
TherapyEvent.Type.PROFILE_SWITCH.text -> resourceHelper.gs(R.string.careportal_profileswitch)
TherapyEvent.Type.TEMPORARY_TARGET.text -> resourceHelper.gs(R.string.careportal_temporarytarget)
TherapyEvent.Type.TEMPORARY_TARGET_CANCEL.text -> resourceHelper.gs(R.string.careportal_temporarytargetcancel)
TherapyEvent.Type.APS_OFFLINE.text -> resourceHelper.gs(R.string.careportal_openapsoffline)
TherapyEvent.Type.NS_MBG.text -> resourceHelper.gs(R.string.careportal_mbg)
TherapyEvent.MeterType.FINGER.text -> resourceHelper.gs(R.string.glucosetype_finger)
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.widget.TextView
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 javax.inject.Inject
import javax.inject.Singleton
@ -29,10 +30,10 @@ class WarnColors @Inject constructor(val resourceHelper: ResourceHelper) {
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 {
careportalEvent.isOlderThan(urgentThreshold) -> resourceHelper.gc(R.color.low)
careportalEvent.isOlderThan(warnThreshold) -> resourceHelper.gc(R.color.high)
else -> Color.WHITE
therapyEvent.isOlderThan(urgentThreshold) -> resourceHelper.gc(R.color.low)
therapyEvent.isOlderThan(warnThreshold) -> resourceHelper.gc(R.color.high)
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_cgmsensorinsert">CGM Sensor Insert</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_profileswitch">Profile switch</string>
<string name="careportal_snackbolus">Snack Bolus</string>

View file

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

View file

@ -1,9 +1,13 @@
package info.nightscout.androidaps.danars.comm
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.dana.DanaPump
import info.nightscout.androidaps.danars.R
import info.nightscout.androidaps.danars.encryption.BleEncryption
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.Source
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.general.nsclient.NSUpload
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.resources.ResourceHelper
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.DateTimeZone
import java.util.*
import javax.inject.Inject
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 sp: SP
@Inject lateinit var nsUpload: NSUpload
@Inject lateinit var repository: AppRepository
private val disposable = CompositeDisposable()
init {
opCode = BleEncryption.DANAR_PACKET__OPCODE__APS_HISTORY_EVENTS
@ -174,7 +180,15 @@ open class DanaRS_Packet_APS_History_Events(
DanaPump.REFILL -> {
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))
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)
}
@ -202,11 +216,19 @@ open class DanaRS_Packet_APS_History_Events(
DanaPump.PRIMECANNULA -> {
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))
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)
}
DanaPump.TIMECHANGE -> {
DanaPump.TIMECHANGE -> {
val oldDateTime = intFromBuffMsbLsb(data, 7, 4) * 1000L
aapsLogger.debug(LTag.PUMPCOMM, "[" + id + "] " + "EVENT TIMECHANGE(" + recordCode + ") " + dateUtil.dateAndTimeString(datetime) + " (" + datetime + ")" + " Previous: " + dateUtil.dateAndTimeString(oldDateTime))
status = "TIMECHANGE " + dateUtil.timeString(datetime)

View file

@ -1,8 +1,8 @@
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "a1db89121451334b6eb389e8c702dd2c",
"version": 4,
"identityHash": "e8b8785efbd1699431eef90a5b441ed3",
"entities": [
{
"tableName": "apsResults",
@ -1714,7 +1714,7 @@
},
{
"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": [
{
"fieldPath": "id",
@ -1777,11 +1777,29 @@
"notNull": false
},
{
"fieldPath": "amount",
"columnName": "amount",
"fieldPath": "enteredBy",
"columnName": "enteredBy",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "glucose",
"columnName": "glucose",
"affinity": "REAL",
"notNull": false
},
{
"fieldPath": "glucoseType",
"columnName": "glucoseType",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "units",
"columnName": "units",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "interfaceIDs_backing.nightscoutSystemId",
"columnName": "nightscoutSystemId",
@ -2751,7 +2769,7 @@
"views": [],
"setupQueries": [
"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.entities.*
const val DATABASE_VERSION = 3
const val DATABASE_VERSION = 4
@Database(version = DATABASE_VERSION,
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.TemporaryTarget
import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.database.entities.UserEntry
import info.nightscout.androidaps.database.interfaces.DBEntry
import info.nightscout.androidaps.database.transactions.Transaction
@ -130,6 +131,45 @@ class AppRepository @Inject internal constructor(
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")

View file

@ -46,6 +46,12 @@ class Converters {
@TypeConverter
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
fun fromGlucoseUnit(glucoseUnit: ProfileSwitch.GlucoseUnit?) = glucoseUnit?.name
@ -91,24 +97,24 @@ class Converters {
@TypeConverter
fun anyToString(value: Any?) = when (value) {
null -> null
is String -> "S$value"
is Int -> "I$value"
is Long -> "L$value"
null -> null
is String -> "S$value"
is Int -> "I$value"
is Long -> "L$value"
is Boolean -> "B$value"
is Float -> "F$value"
else -> throw IllegalArgumentException("Type not supported")
is Float -> "F$value"
else -> throw IllegalArgumentException("Type not supported")
}
@TypeConverter
fun stringToAny(value: String?): Any? = when {
value == null -> null
value == null -> null
value.startsWith("S") -> value.substring(1)
value.startsWith("I") -> value.substring(1).toInt()
value.startsWith("L") -> value.substring(1).toLong()
value.startsWith("B") -> value.substring(1).toBoolean()
value.startsWith("F") -> value.substring(1).toFloat()
else -> throw IllegalArgumentException("Type not supported")
else -> throw IllegalArgumentException("Type not supported")
}
@TypeConverter

View file

@ -3,9 +3,7 @@ package info.nightscout.androidaps.database.daos
import androidx.room.Dao
import androidx.room.Query
import info.nightscout.androidaps.database.TABLE_THERAPY_EVENTS
import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.TherapyEvent
import io.reactivex.Flowable
import io.reactivex.Maybe
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")
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
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.embedments.InterfaceIDs
import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration
import info.nightscout.androidaps.database.interfaces.TraceableDBEntry
import java.util.TimeZone
import java.util.*
@Entity(tableName = TABLE_THERAPY_EVENTS,
foreignKeys = [ForeignKey(
entity = TherapyEvent::class,
parentColumns = ["id"],
childColumns = ["referenceId"])],
indices = [Index("referenceId"), Index("timestamp")])
foreignKeys = [ForeignKey(
entity = TherapyEvent::class,
parentColumns = ["id"],
childColumns = ["referenceId"])],
indices = [Index("referenceId"), Index("timestamp")])
data class TherapyEvent(
@PrimaryKey(autoGenerate = true)
override var id: Long = 0,
override var id: Long = 0,
override var version: Int = 0,
override var dateCreated: Long = -1,
override var isValid: Boolean = true,
override var referenceId: Long? = null,
@Embedded
override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(),
override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(),
override var timestamp: Long,
override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(),
override var duration: Long = 0,
var type: Type,
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 {
enum class Type {
CANNULA_CHANGED,
TUBE_CHANGED,
RESERVOIR_CHANGED,
BATTERY_CHANGED,
LEAKING_INFUSION_SET,
SENSOR_INSERTED,
SENSOR_STARTED,
SENSOR_STOPPED,
FINGER_STICK_BG_VALUE,
ACTIVITY,
FALLING_ASLEEP,
WAKING_UP,
SICKNESS,
STRESS,
PRE_PERIOD,
ALCOHOL,
CORTISON,
FEELING_LOW,
FEELING_HIGH,
ANNOUNCEMENT,
QUESTION,
NOTE,
APS_OFFLINE,
BATTERY_EMPTY,
RESERVOIR_EMPTY,
OCCLUSION,
PUMP_STOPPED,
PUMP_STARTED,
PUMP_PAUSED
enum class MeterType(val text: String) {
@SerializedName("Finger")
FINGER("Finger"),
@SerializedName("Sensor")
SENSOR("Sensor"),
@SerializedName("Manual")
MANUAL("Manual")
;
companion object {
fun fromString(text: String?) = values().firstOrNull { it.text == text } ?: MANUAL
}
}
@Suppress("unused")
enum class Type(val text: String, val nsNative: Boolean = false) {
@SerializedName("Site Change")
CANNULA_CHANGE("Site Change", nsNative = true),
@SerializedName("Insulin Change")
INSULIN_CHANGE("Insulin Change", nsNative = true),
@SerializedName("Pump Battery Change")
PUMP_BATTERY_CHANGE("Pump Battery Change", nsNative = true),
@SerializedName("Sensor Change")
SENSOR_CHANGE("Sensor Change", nsNative = true),
@SerializedName("Sensor Start")
SENSOR_STARTED("Sensor Start", nsNative = true),
@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(
timestamp = it.timestamp,
type = TherapyEvent.Type.FINGER_STICK_BG_VALUE,
amount = it.value
glucose = it.value
))
}
}
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(
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 {
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.Profile;
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.InsightBolusID;
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.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
@Singleton
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 DateUtil dateUtil;
private final DatabaseHelperInterface databaseHelper;
private final AppRepository repository;
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 boolean limitsFetched;
private double maximumBolusAmount;
private double maximumBasalAmount;
private double minimumBolusAmount;
private double minimumBasalAmount;
private long lastUpdated = -1;
private OperatingMode operatingMode;
private BatteryStatus batteryStatus;
private CartridgeStatus cartridgeStatus;
@ -198,6 +199,8 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
private boolean statusLoaded;
private TBROverNotificationBlock tbrOverNotificationBlock;
private final CompositeDisposable disposable = new CompositeDisposable();
@Inject
public LocalInsightPlugin(
HasAndroidInjector injector,
@ -213,7 +216,8 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
UploadQueueInterface uploadQueue,
ConfigInterface config,
DateUtil dateUtil,
DatabaseHelperInterface databaseHelper
DatabaseHelperInterface databaseHelper,
AppRepository repository
) {
super(new PluginDescription()
.pluginIcon(R.drawable.ic_insight_128)
@ -238,6 +242,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
this.uploadQueue = uploadQueue;
this.dateUtil = dateUtil;
this.databaseHelper = databaseHelper;
this.repository = repository;
pumpDescription = new PumpDescription();
pumpDescription.setPumpDescription(PumpType.AccuChekInsightBluetooth);
@ -247,10 +252,6 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
return tbrOverNotificationBlock;
}
public long getLastUpdated() {
return lastUpdated;
}
public InsightConnectionService getConnectionService() {
return connectionService;
}
@ -465,7 +466,6 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
}
statusLoaded = true;
}
lastUpdated = System.currentTimeMillis();
new Handler(Looper.getMainLooper()).post(() -> {
rxBus.send(new EventLocalInsightUpdateGUI());
rxBus.send(new EventRefreshOverview("LocalInsightPlugin::fetchStatus", false));
@ -474,9 +474,9 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
private void fetchLimitations() throws Exception {
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();
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.setBasalMinimumRate(minimumBasalAmount);
limitsFetched = true;
@ -1269,7 +1269,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
if (!sp.getBoolean("insight_log_site_changes", false)) return;
long timestamp = parseDate(event.getEventYear(), event.getEventMonth(), event.getEventDay(),
event.getEventHour(), event.getEventMinute(), event.getEventSecond()) + timeOffset;
uploadCareportalEvent(timestamp, CareportalEvent.SITECHANGE);
uploadCareportalEvent(timestamp, TherapyEvent.Type.CANNULA_CHANGE);
}
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;
long timestamp = parseDate(event.getEventYear(), event.getEventMonth(), event.getEventDay(),
event.getEventHour(), event.getEventMinute(), event.getEventSecond()) + timeOffset;
uploadCareportalEvent(timestamp, CareportalEvent.INSULINCHANGE);
uploadCareportalEvent(timestamp, TherapyEvent.Type.INSULIN_CHANGE);
}
private void processPowerUpEvent(PowerUpEvent event) {
if (!sp.getBoolean("insight_log_battery_changes", false)) return;
long timestamp = parseDate(event.getEventYear(), event.getEventMonth(), event.getEventDay(),
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) {
@ -1552,25 +1552,12 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
}
private void logNote(long date, String note) {
try {
if (databaseHelper.getCareportalEventFromTimestamp(date) != null)
return;
JSONObject data = new JSONObject();
String enteredBy = sp.getString("careportal_enteredby", "");
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);
}
if (repository.getTherapyEventByTimestamp(TherapyEvent.Type.NOTE, date) != null) return;
disposable.add(repository.runTransactionForResult(new InsertTherapyEventIfNewTransaction(date, TherapyEvent.Type.NOTE, 0, note, sp.getString("careportal_enteredby", "AndroidAPS"), null, null, null))
.subscribe(
result -> result.getInserted().forEach(nsUpload::uploadEvent),
error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error)
));
}
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();
}
private void uploadCareportalEvent(long date, String event) {
if (databaseHelper.getCareportalEventFromTimestamp(date) != null)
return;
try {
JSONObject data = new JSONObject();
String enteredBy = sp.getString("careportal_enteredby", "");
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);
}
private void uploadCareportalEvent(long date, TherapyEvent.Type event) {
if (repository.getTherapyEventByTimestamp(event, date) != null) return;
disposable.add(repository.runTransactionForResult(new InsertTherapyEventIfNewTransaction(date, event, 0, null, sp.getString("careportal_enteredby", "AndroidAPS"), null, null, null))
.subscribe(
result -> result.getInserted().forEach(nsUpload::uploadEvent),
error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error)
));
}
@NonNull @Override

View file

@ -17,4 +17,5 @@ android {
dependencies {
implementation project(':core')
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.joda.time.LocalDateTime;
import org.joda.time.Minutes;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Calendar;
@ -23,12 +21,15 @@ import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
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.ExtendedBolus;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TDD;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
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.util.MedtronicConst;
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.utils.DateUtil;
import info.nightscout.androidaps.utils.Round;
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 MedtronicPumpHistoryDecoder medtronicPumpHistoryDecoder;
private final DatabaseHelperInterface databaseHelper;
private final AppRepository repository;
private final List<PumpHistoryEntry> allHistory;
private List<PumpHistoryEntry> newHistory = null;
@ -94,6 +95,7 @@ public class MedtronicHistoryData {
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
* 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,
MedtronicUtil medtronicUtil,
MedtronicPumpHistoryDecoder medtronicPumpHistoryDecoder,
DatabaseHelperInterface databaseHelperInterface
DatabaseHelperInterface databaseHelperInterface,
AppRepository repository
) {
this.allHistory = new ArrayList<>();
@ -124,6 +127,7 @@ public class MedtronicHistoryData {
this.medtronicUtil = medtronicUtil;
this.medtronicPumpHistoryDecoder = medtronicPumpHistoryDecoder;
this.databaseHelper = databaseHelperInterface;
this.repository = repository;
}
private Gson gson() {
@ -549,7 +553,7 @@ public class MedtronicHistoryData {
long lastPrimeFromAAPS = sp.getLong(MedtronicConst.Statistics.LastPrime, 0L);
if (lastPrimeRecord != lastPrimeFromAAPS) {
uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastPrimeRecord), CareportalEvent.SITECHANGE);
uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastPrimeRecord), TherapyEvent.Type.CANNULA_CHANGE);
sp.putLong(MedtronicConst.Statistics.LastPrime, lastPrimeRecord);
}
@ -572,7 +576,7 @@ public class MedtronicHistoryData {
long lastRewindFromAAPS = sp.getLong(MedtronicConst.Statistics.LastRewind, 0L);
if (lastRewindRecord != lastRewindFromAAPS) {
uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastRewindRecord), CareportalEvent.INSULINCHANGE);
uploadCareportalEvent(DateTimeUtil.toMillisFromATD(lastRewindRecord), TherapyEvent.Type.INSULIN_CHANGE);
sp.putLong(MedtronicConst.Statistics.LastRewind, lastRewindRecord);
}
@ -580,28 +584,15 @@ public class MedtronicHistoryData {
}
private void uploadCareportalEvent(long date, String event) {
if (databaseHelper.getCareportalEventFromTimestamp(date) != null)
return;
try {
JSONObject data = new JSONObject();
String enteredBy = sp.getString("careportal_enteredby", "");
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 uploadCareportalEvent(long date, TherapyEvent.Type event) {
if (repository.getTherapyEventByTimestamp(event, date) != null) return;
disposable.add(repository.runTransactionForResult(new InsertTherapyEventIfNewTransaction(date, event, 0, null, sp.getString("careportal_enteredby", "AndroidAPS"), null, null, null))
.subscribe(
result -> result.getInserted().forEach(nsUpload::uploadEvent),
error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error)
));
}
private void processTDDs(List<PumpHistoryEntry> tddsIn) {
List<PumpHistoryEntry> tdds = filterTDDs(tddsIn);
@ -1523,7 +1514,7 @@ public class MedtronicHistoryData {
// HELPER METHODS
private void sort(List<PumpHistoryEntry> list) {
if (list!=null && !list.isEmpty()) {
if (list != null && !list.isEmpty()) {
Collections.sort(list, new PumpHistoryEntry.Comparator());
}
}

View file

@ -18,4 +18,5 @@ dependencies {
implementation project(':core')
implementation project(':omnipod-common')
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.Duration;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
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.Profile;
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.Source;
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.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
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.util.AapsOmnipodUtil;
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.rx.AapsSchedulers;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.subjects.SingleSubject;
@Singleton
@ -97,7 +96,6 @@ public class AapsOmnipodErosManager {
private final PodStateManager podStateManager;
private final AapsOmnipodUtil aapsOmnipodUtil;
private final AAPSLogger aapsLogger;
private final AapsSchedulers aapsSchedulers;
private final RxBusWrapper rxBus;
private final ResourceHelper resourceHelper;
private final HasAndroidInjector injector;
@ -107,8 +105,8 @@ public class AapsOmnipodErosManager {
private final DatabaseHelperInterface databaseHelper;
private final OmnipodAlertUtil omnipodAlertUtil;
private final NSUpload nsUpload;
private final ProfileFunction profileFunction;
private final Context context;
private final AppRepository repository;
private boolean basalBeepsEnabled;
private boolean bolusBeepsEnabled;
@ -125,6 +123,8 @@ public class AapsOmnipodErosManager {
private boolean showRileyLinkBatteryLevel;
private boolean batteryChangeLoggingEnabled;
private final CompositeDisposable disposable = new CompositeDisposable();
@Inject
public AapsOmnipodErosManager(OmnipodRileyLinkCommunicationManager communicationService,
PodStateManager podStateManager,
@ -139,13 +139,12 @@ public class AapsOmnipodErosManager {
DatabaseHelperInterface databaseHelper,
OmnipodAlertUtil omnipodAlertUtil,
NSUpload nsUpload,
ProfileFunction profileFunction,
Context context) {
Context context,
AppRepository repository) {
this.podStateManager = podStateManager;
this.aapsOmnipodUtil = aapsOmnipodUtil;
this.aapsLogger = aapsLogger;
this.aapsSchedulers = aapsSchedulers;
this.rxBus = rxBus;
this.sp = sp;
this.resourceHelper = resourceHelper;
@ -154,8 +153,8 @@ public class AapsOmnipodErosManager {
this.databaseHelper = databaseHelper;
this.omnipodAlertUtil = omnipodAlertUtil;
this.nsUpload = nsUpload;
this.profileFunction = profileFunction;
this.context = context;
this.repository = repository;
delegate = new OmnipodManager(aapsLogger, aapsSchedulers, communicationService, podStateManager);
@ -224,8 +223,8 @@ public class AapsOmnipodErosManager {
addToHistory(System.currentTimeMillis(), PodHistoryEntryType.INSERT_CANNULA, result.getComment(), result.getSuccess());
if (result.getSuccess()) {
uploadCareportalEvent(System.currentTimeMillis() - 1000, CareportalEvent.INSULINCHANGE);
uploadCareportalEvent(System.currentTimeMillis(), CareportalEvent.SITECHANGE);
uploadCareportalEvent(System.currentTimeMillis() - 1000, TherapyEvent.Type.INSULIN_CHANGE);
uploadCareportalEvent(System.currentTimeMillis(), TherapyEvent.Type.CANNULA_CHANGE);
dismissNotification(Notification.OMNIPOD_POD_NOT_ATTACHED);
@ -1003,28 +1002,12 @@ public class AapsOmnipodErosManager {
return new BasalSchedule(entries);
}
private void uploadCareportalEvent(long date, String event) {
if (databaseHelper.getCareportalEventFromTimestamp(date) != null)
return;
try {
JSONObject data = new JSONObject();
String enteredBy = sp.getString("careportal_enteredby", "");
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);
}
private void uploadCareportalEvent(long date, TherapyEvent.Type event) {
if (repository.getTherapyEventByTimestamp(event, date) != null) return;
disposable.add(repository.runTransactionForResult(new InsertTherapyEventIfNewTransaction(date, event, 0, null, sp.getString("careportal_enteredby", "AndroidAPS"), null, null, null))
.subscribe(
result -> result.getInserted().forEach(nsUpload::uploadEvent),
error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error)
));
}
}