Merge pull request #294 from nightscout/newdb

BG processing in new DB
This commit is contained in:
Milos Kozak 2021-02-08 16:12:18 +01:00 committed by GitHub
commit f1acf6449a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
72 changed files with 1812 additions and 2215 deletions

Binary file not shown.

View file

@ -18,6 +18,9 @@ import javax.inject.Inject;
import dagger.android.AndroidInjector; import dagger.android.AndroidInjector;
import dagger.android.DaggerApplication; import dagger.android.DaggerApplication;
import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.transactions.VersionChangeTransaction;
import info.nightscout.androidaps.db.CompatDBHelper;
import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.db.StaticInjector; import info.nightscout.androidaps.db.StaticInjector;
import info.nightscout.androidaps.dependencyInjection.DaggerAppComponent; import info.nightscout.androidaps.dependencyInjection.DaggerAppComponent;
@ -38,11 +41,14 @@ import info.nightscout.androidaps.services.Intents;
import info.nightscout.androidaps.utils.ActivityMonitor; import info.nightscout.androidaps.utils.ActivityMonitor;
import info.nightscout.androidaps.utils.locale.LocaleHelper; import info.nightscout.androidaps.utils.locale.LocaleHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
public class MainApp extends DaggerApplication { public class MainApp extends DaggerApplication {
static DatabaseHelper sDatabaseHelper = null; static DatabaseHelper sDatabaseHelper = null;
private final CompositeDisposable disposable = new CompositeDisposable();
@Inject PluginStore pluginStore; @Inject PluginStore pluginStore;
@Inject AAPSLogger aapsLogger; @Inject AAPSLogger aapsLogger;
@Inject ActivityMonitor activityMonitor; @Inject ActivityMonitor activityMonitor;
@ -54,6 +60,8 @@ public class MainApp extends DaggerApplication {
@Inject ConfigBuilderPlugin configBuilderPlugin; @Inject ConfigBuilderPlugin configBuilderPlugin;
@Inject KeepAliveReceiver.KeepAliveManager keepAliveManager; @Inject KeepAliveReceiver.KeepAliveManager keepAliveManager;
@Inject List<PluginBase> plugins; @Inject List<PluginBase> plugins;
@Inject CompatDBHelper compatDBHelper;
@Inject AppRepository repository;
@Inject StaticInjector staticInjector; // TODO avoid , here fake only to initialize @Inject StaticInjector staticInjector; // TODO avoid , here fake only to initialize
@ -73,6 +81,15 @@ public class MainApp extends DaggerApplication {
aapsLogger.error("Uncaught exception crashing app", ex); aapsLogger.error("Uncaught exception crashing app", ex);
}); });
*/ */
String gitRemote = BuildConfig.REMOTE;
String commitHash = BuildConfig.HEAD;
if (gitRemote.contains("NoGitSystemAvailable")) {
gitRemote = null;
commitHash = null;
}
disposable.add(repository.runTransaction(new VersionChangeTransaction(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, gitRemote, commitHash)).subscribe());
disposable.add(compatDBHelper.dbChangeDisposable());
registerActivityLifecycleCallbacks(activityMonitor); registerActivityLifecycleCallbacks(activityMonitor);
JodaTimeAndroid.init(this); JodaTimeAndroid.init(this);

View file

@ -0,0 +1,43 @@
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.events.EventNewBG
import info.nightscout.androidaps.events.EventTempTargetChange
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
import io.reactivex.disposables.Disposable
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class CompatDBHelper @Inject constructor(
val aapsLogger: AAPSLogger,
val repository: AppRepository,
val rxBus: RxBusWrapper
) {
fun dbChangeDisposable(): Disposable = repository
.changeObservable()
.doOnSubscribe {
rxBus.send(EventNewBG(null))
}
.subscribe {
it.filterIsInstance<GlucoseValue>().firstOrNull()?.let {
aapsLogger.debug(LTag.DATABASE, "Firing EventNewHistoryData")
rxBus.send(EventNewHistoryData(it.timestamp))
}
it.filterIsInstance<GlucoseValue>().lastOrNull()?.let {
aapsLogger.debug(LTag.DATABASE, "Firing EventNewBg")
rxBus.send(EventNewBG(it))
}
it.filterIsInstance<TemporaryTarget>().firstOrNull()?.let {
aapsLogger.debug(LTag.DATABASE, "Firing EventTempTargetChange")
rxBus.send(EventTempTargetChange())
}
}
}

View file

@ -33,13 +33,11 @@ import java.util.concurrent.TimeUnit;
import javax.inject.Inject; import javax.inject.Inject;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.dana.comm.RecordTypes; import info.nightscout.androidaps.dana.comm.RecordTypes;
import info.nightscout.androidaps.data.NonOverlappingIntervals; import info.nightscout.androidaps.data.NonOverlappingIntervals;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventCareportalEventChange; import info.nightscout.androidaps.events.EventCareportalEventChange;
import info.nightscout.androidaps.events.EventExtendedBolusChange; import info.nightscout.androidaps.events.EventExtendedBolusChange;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventProfileNeedsUpdate; import info.nightscout.androidaps.events.EventProfileNeedsUpdate;
import info.nightscout.androidaps.events.EventRefreshOverview; import info.nightscout.androidaps.events.EventRefreshOverview;
import info.nightscout.androidaps.events.EventReloadProfileSwitchData; import info.nightscout.androidaps.events.EventReloadProfileSwitchData;
@ -54,9 +52,7 @@ import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryBgData;
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader; import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.pump.insight.database.InsightBolusID; import info.nightscout.androidaps.plugins.pump.insight.database.InsightBolusID;
import info.nightscout.androidaps.plugins.pump.insight.database.InsightHistoryOffset; import info.nightscout.androidaps.plugins.pump.insight.database.InsightHistoryOffset;
@ -64,7 +60,6 @@ import info.nightscout.androidaps.plugins.pump.insight.database.InsightPumpID;
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
import info.nightscout.androidaps.utils.JsonHelper; import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.PercentageSplitter; import info.nightscout.androidaps.utils.PercentageSplitter;
import info.nightscout.androidaps.utils.T;
/** /**
* This Helper contains all resource to provide a central DB management functionality. Only methods handling * This Helper contains all resource to provide a central DB management functionality. Only methods handling
@ -81,7 +76,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
@Inject OpenHumansUploader openHumansUploader; @Inject OpenHumansUploader openHumansUploader;
public static final String DATABASE_NAME = "AndroidAPSDb"; public static final String DATABASE_NAME = "AndroidAPSDb";
public static final String DATABASE_BGREADINGS = "BgReadings";
public static final String DATABASE_TEMPORARYBASALS = "TemporaryBasals"; public static final String DATABASE_TEMPORARYBASALS = "TemporaryBasals";
public static final String DATABASE_EXTENDEDBOLUSES = "ExtendedBoluses"; public static final String DATABASE_EXTENDEDBOLUSES = "ExtendedBoluses";
public static final String DATABASE_TEMPTARGETS = "TempTargets"; public static final String DATABASE_TEMPTARGETS = "TempTargets";
@ -101,10 +95,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final ScheduledExecutorService bgWorker = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService bgWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledBgPost = null; private static ScheduledFuture<?> scheduledBgPost = null;
private static final ScheduledExecutorService bgHistoryWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledBgHistoryPost = null;
private static long oldestBgHistoryChange = 0;
private static final ScheduledExecutorService tempBasalsWorker = Executors.newSingleThreadScheduledExecutor(); private static final ScheduledExecutorService tempBasalsWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledTemBasalsPost = null; private static ScheduledFuture<?> scheduledTemBasalsPost = null;
@ -135,7 +125,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
try { try {
aapsLogger.info(LTag.DATABASE, "onCreate"); aapsLogger.info(LTag.DATABASE, "onCreate");
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class); TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class); //TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class); TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class); TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class); TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class);
@ -167,7 +157,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (oldVersion < 7) { if (oldVersion < 7) {
aapsLogger.info(LTag.DATABASE, "onUpgrade"); aapsLogger.info(LTag.DATABASE, "onUpgrade");
TableUtils.dropTable(connectionSource, TempTarget.class, true); TableUtils.dropTable(connectionSource, TempTarget.class, true);
TableUtils.dropTable(connectionSource, BgReading.class, true); //TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true); TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
TableUtils.dropTable(connectionSource, DbRequest.class, true); TableUtils.dropTable(connectionSource, DbRequest.class, true);
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true); TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
@ -217,7 +207,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void resetDatabases() { public void resetDatabases() {
try { try {
TableUtils.dropTable(connectionSource, TempTarget.class, true); TableUtils.dropTable(connectionSource, TempTarget.class, true);
TableUtils.dropTable(connectionSource, BgReading.class, true); //TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true); TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
TableUtils.dropTable(connectionSource, DbRequest.class, true); TableUtils.dropTable(connectionSource, DbRequest.class, true);
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true); TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
@ -227,7 +217,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.dropTable(connectionSource, TDD.class, true); TableUtils.dropTable(connectionSource, TDD.class, true);
TableUtils.dropTable(connectionSource, OmnipodHistoryRecord.class, true); TableUtils.dropTable(connectionSource, OmnipodHistoryRecord.class, true);
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class); TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class); //TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class); TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class); TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class); TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class);
@ -241,7 +231,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
aapsLogger.error("Unhandled exception", e); aapsLogger.error("Unhandled exception", e);
} }
virtualPumpPlugin.setFakingStatus(true); virtualPumpPlugin.setFakingStatus(true);
scheduleBgChange(null); // trigger refresh
scheduleTemporaryBasalChange(); scheduleTemporaryBasalChange();
scheduleExtendedBolusChange(); scheduleExtendedBolusChange();
scheduleTemporaryTargetChange(); scheduleTemporaryTargetChange();
@ -326,10 +315,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return getDao(TempTarget.class); return getDao(TempTarget.class);
} }
private Dao<BgReading, Long> getDaoBgReadings() throws SQLException {
return getDao(BgReading.class);
}
private Dao<DanaRHistoryRecord, String> getDaoDanaRHistory() throws SQLException { private Dao<DanaRHistoryRecord, String> getDaoDanaRHistory() throws SQLException {
return getDao(DanaRHistoryRecord.class); return getDao(DanaRHistoryRecord.class);
} }
@ -384,144 +369,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
aapsLogger.debug(LTag.DATABASE, "Rounding " + date + " to " + rounded); aapsLogger.debug(LTag.DATABASE, "Rounding " + date + " to " + rounded);
return rounded; return rounded;
} }
// ------------------- BgReading handling -----------------------
public boolean createIfNotExists(BgReading bgReading, String from) {
try {
bgReading.date = roundDateToSec(bgReading.date);
BgReading old = getDaoBgReadings().queryForId(bgReading.date);
if (old == null) {
getDaoBgReadings().create(bgReading);
openHumansUploader.enqueueBGReading(bgReading);
aapsLogger.debug(LTag.DATABASE, "BG: New record from: " + from + " " + bgReading.toString());
scheduleBgChange(bgReading);
return true;
}
if (!old.isEqual(bgReading)) {
aapsLogger.debug(LTag.DATABASE, "BG: Similiar found: " + old.toString());
old.copyFrom(bgReading);
getDaoBgReadings().update(old);
openHumansUploader.enqueueBGReading(old);
aapsLogger.debug(LTag.DATABASE, "BG: Updating record from: " + from + " New data: " + old.toString());
scheduleBgHistoryChange(old.date); // trigger cache invalidation
return false;
}
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return false;
}
public void update(BgReading bgReading) {
bgReading.date = roundDateToSec(bgReading.date);
try {
getDaoBgReadings().update(bgReading);
openHumansUploader.enqueueBGReading(bgReading);
aapsLogger.debug(LTag.DATABASE, "BG: Updating record from: "+ bgReading.toString());
scheduleBgHistoryChange(bgReading.date); // trigger cache invalidation
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
}
private void scheduleBgChange(@Nullable final BgReading bgReading) {
class PostRunnable implements Runnable {
public void run() {
aapsLogger.debug(LTag.DATABASE, "Firing EventNewBg");
rxBus.send(new EventNewBG(bgReading));
scheduledBgPost = null;
}
}
// prepare task for execution in 1 sec
// cancel waiting task to prevent sending multiple posts
if (scheduledBgPost != null)
scheduledBgPost.cancel(false);
Runnable task = new PostRunnable();
final int sec = 1;
scheduledBgPost = bgWorker.schedule(task, sec, TimeUnit.SECONDS);
}
private void scheduleBgHistoryChange(@Nullable final long timestamp) {
class PostRunnable implements Runnable {
public void run() {
aapsLogger.debug(LTag.DATABASE, "Firing EventNewBg");
rxBus.send(new EventNewHistoryBgData(oldestBgHistoryChange));
scheduledBgHistoryPost = null;
oldestBgHistoryChange = 0;
}
}
// prepare task for execution in 1 sec
// cancel waiting task to prevent sending multiple posts
if (scheduledBgHistoryPost != null)
scheduledBgHistoryPost.cancel(false);
Runnable task = new PostRunnable();
final int sec = 3;
if (oldestBgHistoryChange == 0 || oldestBgHistoryChange > timestamp)
oldestBgHistoryChange = timestamp;
scheduledBgHistoryPost = bgHistoryWorker.schedule(task, sec, TimeUnit.SECONDS);
}
public List<BgReading> getBgreadingsDataFromTime(long mills, boolean ascending) {
try {
Dao<BgReading, Long> daoBgreadings = getDaoBgReadings();
List<BgReading> bgReadings;
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills).and().ge("value", 39).and().eq("isValid", true);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public List<BgReading> getBgreadingsDataFromTime(long start, long end, boolean ascending) {
try {
Dao<BgReading, Long> daoBgreadings = getDaoBgReadings();
List<BgReading> bgReadings;
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.between("date", start, end).and().ge("value", 39).and().eq("isValid", true);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public List<BgReading> getAllBgreadingsDataFromTime(long mills, boolean ascending) {
try {
Dao<BgReading, Long> daoBgreadings = getDaoBgReadings();
List<BgReading> bgReadings;
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<BgReading>();
}
public List<BgReading> getAllBgReadings() {
try {
return getDaoBgReadings().queryForAll();
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return Collections.emptyList();
}
// ------------------- TDD handling ----------------------- // ------------------- TDD handling -----------------------
public void createOrUpdateTDD(TDD tdd) { public void createOrUpdateTDD(TDD tdd) {
@ -1672,6 +1519,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
return Collections.emptyList(); return Collections.emptyList();
} }
@Nullable @Nullable
private ProfileSwitch getLastProfileSwitchWithoutDuration() { private ProfileSwitch getLastProfileSwitchWithoutDuration() {
try { try {
@ -2010,7 +1858,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return null; return null;
} }
// Copied from xDrip+ /*
TODO implement again for database branch // Copied from xDrip+
String calculateDirection(BgReading bgReading) { String calculateDirection(BgReading bgReading) {
// Rework to get bgreaings from internal DB and calculate on that base // Rework to get bgreaings from internal DB and calculate on that base
@ -2056,7 +1905,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// aapsLogger.error(LTag.GLUCOSE, "Direction set to: " + arrow); // aapsLogger.error(LTag.GLUCOSE, "Direction set to: " + arrow);
return arrow; return arrow;
} }
*/
// ---------------- Open Humans Queue handling --------------- // ---------------- Open Humans Queue handling ---------------
public void clearOpenHumansQueue() { public void clearOpenHumansQueue() {
@ -2109,8 +1958,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public long getCountOfAllRows() { public long getCountOfAllRows() {
try { try {
return getDaoBgReadings().countOf() return getDaoCareportalEvents().countOf()
+ getDaoCareportalEvents().countOf()
+ getDaoExtendedBolus().countOf() + getDaoExtendedBolus().countOf()
+ getDaoCareportalEvents().countOf() + getDaoCareportalEvents().countOf()
+ getDaoProfileSwitch().countOf() + getDaoProfileSwitch().countOf()

View file

@ -20,10 +20,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
@Inject DatabaseHelperProvider() { @Inject DatabaseHelperProvider() {
} }
@NotNull @Override public List<BgReading> getAllBgreadingsDataFromTime(long mills, boolean ascending) {
return MainApp.getDbHelper().getAllBgreadingsDataFromTime(mills, ascending);
}
@Override public void createOrUpdate(@NotNull CareportalEvent careportalEvent) { @Override public void createOrUpdate(@NotNull CareportalEvent careportalEvent) {
MainApp.getDbHelper().createOrUpdate(careportalEvent); MainApp.getDbHelper().createOrUpdate(careportalEvent);
} }

View file

@ -9,6 +9,7 @@ import info.nightscout.androidaps.core.di.CoreModule
import info.nightscout.androidaps.dana.di.DanaModule import info.nightscout.androidaps.dana.di.DanaModule
import info.nightscout.androidaps.danar.di.DanaRModule import info.nightscout.androidaps.danar.di.DanaRModule
import info.nightscout.androidaps.danars.di.DanaRSModule import info.nightscout.androidaps.danars.di.DanaRSModule
import info.nightscout.androidaps.database.DatabaseModule
import info.nightscout.androidaps.plugins.pump.common.dagger.RileyLinkModule import info.nightscout.androidaps.plugins.pump.common.dagger.RileyLinkModule
import info.nightscout.androidaps.plugins.pump.omnipod.dagger.OmnipodModule import info.nightscout.androidaps.plugins.pump.omnipod.dagger.OmnipodModule
import javax.inject.Singleton import javax.inject.Singleton
@ -17,6 +18,7 @@ import javax.inject.Singleton
@Component( @Component(
modules = [ modules = [
AndroidInjectionModule::class, AndroidInjectionModule::class,
DatabaseModule::class,
PluginsModule::class, PluginsModule::class,
SkinsModule::class, SkinsModule::class,
ActivitiesModule::class, ActivitiesModule::class,

View file

@ -2,11 +2,9 @@ package info.nightscout.androidaps.dependencyInjection
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.db.DatabaseHelper
import info.nightscout.androidaps.db.*
import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.general.food.FoodService import info.nightscout.androidaps.plugins.general.food.FoodService
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.treatments.TreatmentService import info.nightscout.androidaps.plugins.treatments.TreatmentService
import info.nightscout.androidaps.utils.wizard.BolusWizard import info.nightscout.androidaps.utils.wizard.BolusWizard
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry import info.nightscout.androidaps.utils.wizard.QuickWizardEntry

View file

@ -13,13 +13,13 @@ import android.widget.AdapterView.OnItemSelectedListener
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.CompoundButton import android.widget.CompoundButton
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerDialogFragment import dagger.android.support.DaggerDialogFragment
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.databinding.DialogWizardBinding import info.nightscout.androidaps.databinding.DialogWizardBinding
import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
@ -38,6 +38,7 @@ import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.valueToUnits
import info.nightscout.androidaps.utils.wizard.BolusWizard import info.nightscout.androidaps.utils.wizard.BolusWizard
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import java.text.DecimalFormat import java.text.DecimalFormat
@ -47,6 +48,7 @@ import kotlin.math.abs
class WizardDialog : DaggerDialogFragment() { class WizardDialog : DaggerDialogFragment() {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var constraintChecker: ConstraintChecker @Inject lateinit var constraintChecker: ConstraintChecker
@ -233,6 +235,10 @@ class WizardDialog : DaggerDialogFragment() {
binding.cobcheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_cob, false) binding.cobcheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_cob, false)
} }
private fun valueToUnitsToString(value: Double, units: String): String =
if (units == Constants.MGDL) DecimalFormatter.to0Decimal(value)
else DecimalFormatter.to1Decimal(value * Constants.MGDL_TO_MMOLL)
private fun initDialog() { private fun initDialog() {
val profile = profileFunction.getProfile() val profile = profileFunction.getProfile()
val profileStore = activePlugin.activeProfileInterface.profile val profileStore = activePlugin.activeProfileInterface.profile
@ -243,8 +249,7 @@ class WizardDialog : DaggerDialogFragment() {
return return
} }
val profileList: ArrayList<CharSequence> val profileList: ArrayList<CharSequence> = profileStore.getProfileList()
profileList = profileStore.getProfileList()
profileList.add(0, resourceHelper.gs(R.string.active)) profileList.add(0, resourceHelper.gs(R.string.active))
context?.let { context -> context?.let { context ->
val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList) val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
@ -332,7 +337,7 @@ class WizardDialog : DaggerDialogFragment() {
binding.notes.text.toString(), carbTime) binding.notes.text.toString(), carbTime)
wizard?.let { wizard -> wizard?.let { wizard ->
binding.bg.text = String.format(resourceHelper.gs(R.string.format_bg_isf), BgReading().value(Profile.toMgdl(bg, profileFunction.getUnits())).valueToUnitsToString(profileFunction.getUnits()), wizard.sens) binding.bg.text = String.format(resourceHelper.gs(R.string.format_bg_isf), valueToUnitsToString(Profile.toMgdl(bg, profileFunction.getUnits()), profileFunction.getUnits()), wizard.sens)
binding.bginsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBG) binding.bginsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBG)
binding.carbs.text = String.format(resourceHelper.gs(R.string.format_carbs_ic), carbs.toDouble(), wizard.ic) binding.carbs.text = String.format(resourceHelper.gs(R.string.format_carbs_ic), carbs.toDouble(), wizard.ic)

View file

@ -1,5 +1,5 @@
package info.nightscout.androidaps.events package info.nightscout.androidaps.events
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.entities.GlucoseValue
class EventNewBG(val bgReading: BgReading?) : EventLoop() class EventNewBG(val glucoseValue: GlucoseValue?) : EventLoop()

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.historyBrowser package info.nightscout.androidaps.historyBrowser
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
@ -32,9 +33,10 @@ class IobCobCalculatorPluginHistory @Inject constructor(
sensitivityAAPSPlugin: SensitivityAAPSPlugin, sensitivityAAPSPlugin: SensitivityAAPSPlugin,
sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin, sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin,
fabricPrivacy: FabricPrivacy, fabricPrivacy: FabricPrivacy,
dateUtil: DateUtil dateUtil: DateUtil,
repository: AppRepository
) : IobCobCalculatorPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, resourceHelper, profileFunction, ) : IobCobCalculatorPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, resourceHelper, profileFunction,
activePlugin, treatmentsPluginHistory, sensitivityOref1Plugin, sensitivityAAPSPlugin, sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil) { activePlugin, treatmentsPluginHistory, sensitivityOref1Plugin, sensitivityAAPSPlugin, sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil, repository) {
override fun onStart() { // do not attach to rxbus override fun onStart() { // do not attach to rxbus
} }

View file

@ -30,7 +30,7 @@ import info.nightscout.androidaps.activities.ErrorHelperActivity;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
@ -201,14 +201,14 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
// Autosens calculation not triggered by a new BG // Autosens calculation not triggered by a new BG
if (!(event.getCause() instanceof EventNewBG)) return; if (!(event.getCause() instanceof EventNewBG)) return;
BgReading bgReading = iobCobCalculatorPlugin.actualBg(); GlucoseValue glucoseValue = iobCobCalculatorPlugin.actualBg();
// BG outdated // BG outdated
if (bgReading == null) return; if (glucoseValue == null) return;
// already looped with that value // already looped with that value
if (bgReading.date <= lastBgTriggeredRun) return; if (glucoseValue.getTimestamp() <= lastBgTriggeredRun) return;
lastBgTriggeredRun = bgReading.date; lastBgTriggeredRun = glucoseValue.getTimestamp();
invoke("AutosenseCalculation for " + bgReading, true); invoke("AutosenseCalculation for " + glucoseValue, true);
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
); );
} }
@ -392,30 +392,30 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
// Prepare for pumps using % basals // Prepare for pumps using % basals
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) { if (pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
result.usePercent = true; result.setUsePercent(true);
} }
result.percent = (int) (result.rate / profile.getBasal() * 100); result.setPercent((int) (result.getRate() / profile.getBasal() * 100));
// check rate for constraints // check rate for constraints
final APSResult resultAfterConstraints = result.newAndClone(injector); final APSResult resultAfterConstraints = result.newAndClone(injector);
resultAfterConstraints.rateConstraint = new Constraint<>(resultAfterConstraints.rate); resultAfterConstraints.setRateConstraint(new Constraint<>(resultAfterConstraints.getRate()));
resultAfterConstraints.rate = constraintChecker.applyBasalConstraints(resultAfterConstraints.rateConstraint, profile).value(); resultAfterConstraints.setRate(constraintChecker.applyBasalConstraints(resultAfterConstraints.getRateConstraint(), profile).value());
resultAfterConstraints.percentConstraint = new Constraint<>(resultAfterConstraints.percent); resultAfterConstraints.setPercentConstraint(new Constraint<>(resultAfterConstraints.getPercent()));
resultAfterConstraints.percent = constraintChecker.applyBasalPercentConstraints(resultAfterConstraints.percentConstraint, profile).value(); resultAfterConstraints.setPercent(constraintChecker.applyBasalPercentConstraints(resultAfterConstraints.getPercentConstraint(), profile).value());
resultAfterConstraints.smbConstraint = new Constraint<>(resultAfterConstraints.smb); resultAfterConstraints.setSmbConstraint(new Constraint<>(resultAfterConstraints.getSmb()));
resultAfterConstraints.smb = constraintChecker.applyBolusConstraints(resultAfterConstraints.smbConstraint).value(); resultAfterConstraints.setSmb(constraintChecker.applyBolusConstraints(resultAfterConstraints.getSmbConstraint()).value());
// safety check for multiple SMBs // safety check for multiple SMBs
long lastBolusTime = treatmentsPlugin.getLastBolusTime(); long lastBolusTime = treatmentsPlugin.getLastBolusTime();
if (lastBolusTime != 0 && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) { if (lastBolusTime != 0 && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) {
getAapsLogger().debug(LTag.APS, "SMB requested but still in 3 min interval"); getAapsLogger().debug(LTag.APS, "SMB requested but still in 3 min interval");
resultAfterConstraints.smb = 0; resultAfterConstraints.setSmb(0);
} }
if (lastRun != null && lastRun.getConstraintsProcessed() != null) { if (lastRun != null && lastRun.getConstraintsProcessed() != null) {
prevCarbsreq = lastRun.getConstraintsProcessed().carbsReq; prevCarbsreq = lastRun.getConstraintsProcessed().getCarbsReq();
} }
if (lastRun == null) lastRun = new LastRun(); if (lastRun == null) lastRun = new LastRun();
@ -449,7 +449,7 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
if (closedLoopEnabled.value()) { if (closedLoopEnabled.value()) {
if (allowNotification) { if (allowNotification) {
if (resultAfterConstraints.isCarbsRequired() if (resultAfterConstraints.isCarbsRequired()
&& resultAfterConstraints.carbsReq >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0) && resultAfterConstraints.getCarbsReq() >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0)
&& carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimethreshold(-15)) { && carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimethreshold(-15)) {
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) { if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
@ -519,9 +519,9 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
&& !commandQueue.isRunning(Command.CommandType.BOLUS)) { && !commandQueue.isRunning(Command.CommandType.BOLUS)) {
final PumpEnactResult waiting = new PumpEnactResult(getInjector()); final PumpEnactResult waiting = new PumpEnactResult(getInjector());
waiting.queued = true; waiting.queued = true;
if (resultAfterConstraints.tempBasalRequested) if (resultAfterConstraints.getTempBasalRequested())
lastRun.setTbrSetByPump(waiting); lastRun.setTbrSetByPump(waiting);
if (resultAfterConstraints.bolusRequested) if (resultAfterConstraints.getBolusRequested())
lastRun.setSmbSetByPump(waiting); lastRun.setSmbSetByPump(waiting);
rxBus.send(new EventLoopUpdateGui()); rxBus.send(new EventLoopUpdateGui());
fabricPrivacy.logCustom("APSRequest"); fabricPrivacy.logCustom("APSRequest");
@ -653,7 +653,7 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
private void applyTBRRequest(APSResult request, Profile profile, Callback callback) { private void applyTBRRequest(APSResult request, Profile profile, Callback callback) {
if (!request.tempBasalRequested) { if (!request.getTempBasalRequested()) {
if (callback != null) { if (callback != null) {
callback.result(new PumpEnactResult(getInjector()).enacted(false).success(true).comment(resourceHelper.gs(R.string.nochangerequested))).run(); callback.result(new PumpEnactResult(getInjector()).enacted(false).success(true).comment(resourceHelper.gs(R.string.nochangerequested))).run();
} }
@ -682,48 +682,48 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
TemporaryBasal activeTemp = treatmentsPlugin.getTempBasalFromHistory(now); TemporaryBasal activeTemp = treatmentsPlugin.getTempBasalFromHistory(now);
if (request.usePercent && allowPercentage()) { if (request.getUsePercent() && allowPercentage()) {
if (request.percent == 100 && request.duration == 0) { if (request.getPercent() == 100 && request.getDuration() == 0) {
if (activeTemp != null) { if (activeTemp != null) {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: cancelTempBasal()"); getAapsLogger().debug(LTag.APS, "applyAPSRequest: cancelTempBasal()");
commandQueue.cancelTempBasal(false, callback); commandQueue.cancelTempBasal(false, callback);
} else { } else {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Basal set correctly"); getAapsLogger().debug(LTag.APS, "applyAPSRequest: Basal set correctly");
if (callback != null) { if (callback != null) {
callback.result(new PumpEnactResult(getInjector()).percent(request.percent).duration(0) callback.result(new PumpEnactResult(getInjector()).percent(request.getPercent()).duration(0)
.enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly))).run(); .enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly))).run();
} }
} }
} else if (activeTemp != null } else if (activeTemp != null
&& activeTemp.getPlannedRemainingMinutes() > 5 && activeTemp.getPlannedRemainingMinutes() > 5
&& request.duration - activeTemp.getPlannedRemainingMinutes() < 30 && request.getDuration() - activeTemp.getPlannedRemainingMinutes() < 30
&& request.percent == activeTemp.percentRate) { && request.getPercent() == activeTemp.percentRate) {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Temp basal set correctly"); getAapsLogger().debug(LTag.APS, "applyAPSRequest: Temp basal set correctly");
if (callback != null) { if (callback != null) {
callback.result(new PumpEnactResult(getInjector()).percent(request.percent) callback.result(new PumpEnactResult(getInjector()).percent(request.getPercent())
.enacted(false).success(true).duration(activeTemp.getPlannedRemainingMinutes()) .enacted(false).success(true).duration(activeTemp.getPlannedRemainingMinutes())
.comment(resourceHelper.gs(R.string.let_temp_basal_run))).run(); .comment(resourceHelper.gs(R.string.let_temp_basal_run))).run();
} }
} else { } else {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: tempBasalPercent()"); getAapsLogger().debug(LTag.APS, "applyAPSRequest: tempBasalPercent()");
commandQueue.tempBasalPercent(request.percent, request.duration, false, profile, callback); commandQueue.tempBasalPercent(request.getPercent(), request.getDuration(), false, profile, callback);
} }
} else { } else {
if ((request.rate == 0 && request.duration == 0) || Math.abs(request.rate - pump.getBaseBasalRate()) < pump.getPumpDescription().basalStep) { if ((request.getRate() == 0 && request.getDuration() == 0) || Math.abs(request.getRate() - pump.getBaseBasalRate()) < pump.getPumpDescription().basalStep) {
if (activeTemp != null) { if (activeTemp != null) {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: cancelTempBasal()"); getAapsLogger().debug(LTag.APS, "applyAPSRequest: cancelTempBasal()");
commandQueue.cancelTempBasal(false, callback); commandQueue.cancelTempBasal(false, callback);
} else { } else {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Basal set correctly"); getAapsLogger().debug(LTag.APS, "applyAPSRequest: Basal set correctly");
if (callback != null) { if (callback != null) {
callback.result(new PumpEnactResult(getInjector()).absolute(request.rate).duration(0) callback.result(new PumpEnactResult(getInjector()).absolute(request.getRate()).duration(0)
.enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly))).run(); .enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly))).run();
} }
} }
} else if (activeTemp != null } else if (activeTemp != null
&& activeTemp.getPlannedRemainingMinutes() > 5 && activeTemp.getPlannedRemainingMinutes() > 5
&& request.duration - activeTemp.getPlannedRemainingMinutes() < 30 && request.getDuration() - activeTemp.getPlannedRemainingMinutes() < 30
&& Math.abs(request.rate - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.getPumpDescription().basalStep) { && Math.abs(request.getRate() - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.getPumpDescription().basalStep) {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Temp basal set correctly"); getAapsLogger().debug(LTag.APS, "applyAPSRequest: Temp basal set correctly");
if (callback != null) { if (callback != null) {
callback.result(new PumpEnactResult(getInjector()).absolute(activeTemp.tempBasalConvertedToAbsolute(now, profile)) callback.result(new PumpEnactResult(getInjector()).absolute(activeTemp.tempBasalConvertedToAbsolute(now, profile))
@ -732,13 +732,13 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
} }
} else { } else {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()"); getAapsLogger().debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()");
commandQueue.tempBasalAbsolute(request.rate, request.duration, false, profile, callback); commandQueue.tempBasalAbsolute(request.getRate(), request.getDuration(), false, profile, callback);
} }
} }
} }
private void applySMBRequest(APSResult request, Callback callback) { private void applySMBRequest(APSResult request, Callback callback) {
if (!request.bolusRequested) { if (!request.getBolusRequested()) {
return; return;
} }
@ -777,10 +777,10 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo(); DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
detailedBolusInfo.lastKnownBolusTime = treatmentsPlugin.getLastBolusTime(); detailedBolusInfo.lastKnownBolusTime = treatmentsPlugin.getLastBolusTime();
detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS; detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS;
detailedBolusInfo.insulin = request.smb; detailedBolusInfo.insulin = request.getSmb();
detailedBolusInfo.isSMB = true; detailedBolusInfo.isSMB = true;
detailedBolusInfo.source = Source.USER; detailedBolusInfo.source = Source.USER;
detailedBolusInfo.deliverAt = request.deliverAt; detailedBolusInfo.deliverAt = request.getDeliverAt();
getAapsLogger().debug(LTag.APS, "applyAPSRequest: bolus()"); getAapsLogger().debug(LTag.APS, "applyAPSRequest: bolus()");
commandQueue.bolus(detailedBolusInfo, callback); commandQueue.bolus(detailedBolusInfo, callback);
} }

View file

@ -1,77 +0,0 @@
package info.nightscout.androidaps.plugins.aps.openAPSAMA;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.javascript.NativeObject;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.utils.DateUtil;
public class DetermineBasalResultAMA extends APSResult {
private AAPSLogger aapsLogger;
private double eventualBG;
private double snoozeBG;
DetermineBasalResultAMA(HasAndroidInjector injector, NativeObject result, JSONObject j) {
this(injector);
date = DateUtil.now();
json = j;
if (result.containsKey("error")) {
reason = result.get("error").toString();
tempBasalRequested = false;
rate = -1;
duration = -1;
} else {
reason = result.get("reason").toString();
if (result.containsKey("eventualBG")) eventualBG = (Double) result.get("eventualBG");
if (result.containsKey("snoozeBG")) snoozeBG = (Double) result.get("snoozeBG");
if (result.containsKey("rate")) {
rate = (Double) result.get("rate");
if (rate < 0d) rate = 0d;
tempBasalRequested = true;
} else {
rate = -1;
tempBasalRequested = false;
}
if (result.containsKey("duration")) {
duration = ((Double) result.get("duration")).intValue();
//changeRequested as above
} else {
duration = -1;
tempBasalRequested = false;
}
}
bolusRequested = false;
}
private DetermineBasalResultAMA(HasAndroidInjector injector) {
super(injector);
hasPredictions = true;
}
@Override
public DetermineBasalResultAMA newAndClone(HasAndroidInjector injector) {
DetermineBasalResultAMA newResult = new DetermineBasalResultAMA(injector);
doClone(newResult);
newResult.eventualBG = eventualBG;
newResult.snoozeBG = snoozeBG;
return newResult;
}
@Override
public JSONObject json() {
try {
JSONObject ret = new JSONObject(this.json.toString());
return ret;
} catch (JSONException e) {
aapsLogger.error(LTag.APS, "Unhandled exception", e);
}
return null;
}
}

View file

@ -0,0 +1,67 @@
package info.nightscout.androidaps.plugins.aps.openAPSAMA
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.loop.APSResult
import info.nightscout.androidaps.utils.DateUtil
import org.json.JSONException
import org.json.JSONObject
import org.mozilla.javascript.NativeObject
class DetermineBasalResultAMA private constructor(injector: HasAndroidInjector) : APSResult(injector) {
private var eventualBG = 0.0
private var snoozeBG = 0.0
internal constructor(injector: HasAndroidInjector, result: NativeObject, j: JSONObject) : this(injector) {
date = DateUtil.now()
json = j
if (result.containsKey("error")) {
reason = result["error"].toString()
tempBasalRequested = false
rate = (-1).toDouble()
duration = -1
} else {
reason = result["reason"].toString()
if (result.containsKey("eventualBG")) eventualBG = result["eventualBG"] as Double
if (result.containsKey("snoozeBG")) snoozeBG = result["snoozeBG"] as Double
if (result.containsKey("rate")) {
rate = result["rate"] as Double
if (rate < 0.0) rate = 0.0
tempBasalRequested = true
} else {
rate = (-1).toDouble()
tempBasalRequested = false
}
if (result.containsKey("duration")) {
duration = (result["duration"] as Double).toInt()
//changeRequested as above
} else {
duration = -1
tempBasalRequested = false
}
}
bolusRequested = false
}
override fun newAndClone(injector: HasAndroidInjector): DetermineBasalResultAMA {
val newResult = DetermineBasalResultAMA(injector)
doClone(newResult)
newResult.eventualBG = eventualBG
newResult.snoozeBG = snoozeBG
return newResult
}
override fun json(): JSONObject? {
try {
return JSONObject(json.toString())
} catch (e: JSONException) {
aapsLogger.error(LTag.APS, "Unhandled exception", e)
}
return null
}
init {
hasPredictions = true
}
}

View file

@ -18,20 +18,20 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui; import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui; import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.FabricPrivacy;
@ -238,15 +238,15 @@ public class OpenAPSAMAPlugin extends PluginBase implements APSInterface {
lastAPSResult = null; lastAPSResult = null;
lastAPSRun = 0; lastAPSRun = 0;
} else { } else {
if (determineBasalResultAMA.rate == 0d && determineBasalResultAMA.duration == 0 && !treatmentsPlugin.isTempBasalInProgress()) if (determineBasalResultAMA.getRate() == 0d && determineBasalResultAMA.getDuration() == 0 && !treatmentsPlugin.isTempBasalInProgress())
determineBasalResultAMA.tempBasalRequested = false; determineBasalResultAMA.setTempBasalRequested(false);
determineBasalResultAMA.iob = iobArray[0]; determineBasalResultAMA.setIob(iobArray[0]);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
try { try {
determineBasalResultAMA.json.put("timestamp", DateUtil.toISOString(now)); determineBasalResultAMA.getJson().put("timestamp", DateUtil.toISOString(now));
} catch (JSONException e) { } catch (JSONException e) {
aapsLogger.error(LTag.APS, "Unhandled exception", e); aapsLogger.error(LTag.APS, "Unhandled exception", e);
} }

View file

@ -1,97 +0,0 @@
package info.nightscout.androidaps.plugins.aps.openAPSSMB;
import org.json.JSONException;
import org.json.JSONObject;
import javax.inject.Inject;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
public class DetermineBasalResultSMB extends APSResult {
@Inject SP sp;
private double eventualBG;
private double snoozeBG;
private DetermineBasalResultSMB(HasAndroidInjector injector) {
super(injector);
hasPredictions = true;
}
DetermineBasalResultSMB(HasAndroidInjector injector, JSONObject result) {
this(injector);
date = DateUtil.now();
json = result;
try {
if (result.has("error")) {
reason = result.getString("error");
return;
}
reason = result.getString("reason");
if (result.has("eventualBG")) eventualBG = result.getDouble("eventualBG");
if (result.has("snoozeBG")) snoozeBG = result.getDouble("snoozeBG");
//if (result.has("insulinReq")) insulinReq = result.getDouble("insulinReq");
if (result.has("carbsReq")) carbsReq = result.getInt("carbsReq");
if (result.has("carbsReqWithin")) carbsReqWithin = result.getInt("carbsReqWithin");
if (result.has("rate") && result.has("duration")) {
tempBasalRequested = true;
rate = result.getDouble("rate");
if (rate < 0d) rate = 0d;
duration = result.getInt("duration");
} else {
rate = -1;
duration = -1;
}
if (result.has("units")) {
bolusRequested = true;
smb = result.getDouble("units");
} else {
smb = 0d;
}
if (result.has("targetBG")) {
targetBG = result.getDouble("targetBG");
}
if (result.has("deliverAt")) {
String date = result.getString("deliverAt");
try {
deliverAt = DateUtil.fromISODateString(date).getTime();
} catch (Exception e) {
aapsLogger.error(LTag.APS, "Error parsing 'deliverAt' date: " + date, e);
}
}
} catch (JSONException e) {
aapsLogger.error(LTag.APS, "Error parsing determine-basal result JSON", e);
}
}
@Override
public DetermineBasalResultSMB newAndClone(HasAndroidInjector injector) {
DetermineBasalResultSMB newResult = new DetermineBasalResultSMB(injector);
doClone(newResult);
newResult.eventualBG = eventualBG;
newResult.snoozeBG = snoozeBG;
return newResult;
}
@Override
public JSONObject json() {
try {
return new JSONObject(this.json.toString());
} catch (JSONException e) {
aapsLogger.error(LTag.APS, "Error converting determine-basal result to JSON", e);
}
return null;
}
}

View file

@ -0,0 +1,80 @@
package info.nightscout.androidaps.plugins.aps.openAPSSMB
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.loop.APSResult
import info.nightscout.androidaps.utils.DateUtil
import org.json.JSONException
import org.json.JSONObject
class DetermineBasalResultSMB private constructor(injector: HasAndroidInjector) : APSResult(injector) {
private var eventualBG = 0.0
private var snoozeBG = 0.0
internal constructor(injector: HasAndroidInjector, result: JSONObject) : this(injector) {
date = DateUtil.now()
json = result
try {
if (result.has("error")) {
reason = result.getString("error")
return
}
reason = result.getString("reason")
if (result.has("eventualBG")) eventualBG = result.getDouble("eventualBG")
if (result.has("snoozeBG")) snoozeBG = result.getDouble("snoozeBG")
//if (result.has("insulinReq")) insulinReq = result.getDouble("insulinReq");
if (result.has("carbsReq")) carbsReq = result.getInt("carbsReq")
if (result.has("carbsReqWithin")) carbsReqWithin = result.getInt("carbsReqWithin")
if (result.has("rate") && result.has("duration")) {
tempBasalRequested = true
rate = result.getDouble("rate")
if (rate < 0.0) rate = 0.0
duration = result.getInt("duration")
} else {
rate = (-1).toDouble()
duration = -1
}
if (result.has("units")) {
bolusRequested = true
smb = result.getDouble("units")
} else {
smb = 0.0
}
if (result.has("targetBG")) {
targetBG = result.getDouble("targetBG")
}
if (result.has("deliverAt")) {
val date = result.getString("deliverAt")
try {
deliverAt = DateUtil.fromISODateString(date).time
} catch (e: Exception) {
aapsLogger.error(LTag.APS, "Error parsing 'deliverAt' date: $date", e)
}
}
} catch (e: JSONException) {
aapsLogger.error(LTag.APS, "Error parsing determine-basal result JSON", e)
}
}
override fun newAndClone(injector: HasAndroidInjector): DetermineBasalResultSMB {
val newResult = DetermineBasalResultSMB(injector)
doClone(newResult)
newResult.eventualBG = eventualBG
newResult.snoozeBG = snoozeBG
return newResult
}
override fun json(): JSONObject? {
try {
return JSONObject(json.toString())
} catch (e: JSONException) {
aapsLogger.error(LTag.APS, "Error converting determine-basal result to JSON", e)
}
return null
}
init {
hasPredictions = true
}
}

View file

@ -24,20 +24,20 @@ import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui; import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui; import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.FabricPrivacy;
@ -291,18 +291,18 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, Constr
} else { } else {
// TODO still needed with oref1? // TODO still needed with oref1?
// Fix bug determine basal // Fix bug determine basal
if (determineBasalResultSMB.rate == 0d && determineBasalResultSMB.duration == 0 && !treatmentsPlugin.isTempBasalInProgress()) if (determineBasalResultSMB.getRate() == 0d && determineBasalResultSMB.getDuration() == 0 && !treatmentsPlugin.isTempBasalInProgress())
determineBasalResultSMB.tempBasalRequested = false; determineBasalResultSMB.setTempBasalRequested(false);
determineBasalResultSMB.iob = iobArray[0]; determineBasalResultSMB.setIob(iobArray[0]);
try { try {
determineBasalResultSMB.json.put("timestamp", DateUtil.toISOString(now)); determineBasalResultSMB.getJson().put("timestamp", DateUtil.toISOString(now));
} catch (JSONException e) { } catch (JSONException e) {
getAapsLogger().error(LTag.APS, "Unhandled exception", e); getAapsLogger().error(LTag.APS, "Unhandled exception", e);
} }
determineBasalResultSMB.inputConstraints = inputConstraints; determineBasalResultSMB.setInputConstraints(inputConstraints);
lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS; lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS;
lastAPSResult = determineBasalResultSMB; lastAPSResult = determineBasalResultSMB;

View file

@ -8,7 +8,6 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.events.Event import info.nightscout.androidaps.events.Event
import info.nightscout.androidaps.events.EventExtendedBolusChange import info.nightscout.androidaps.events.EventExtendedBolusChange
import info.nightscout.androidaps.events.EventNewBasalProfile import info.nightscout.androidaps.events.EventNewBasalProfile
@ -123,13 +122,13 @@ class DataBroadcastPlugin @Inject constructor(
} }
private fun bgStatus(bundle: Bundle) { private fun bgStatus(bundle: Bundle) {
val lastBG: BgReading = iobCobCalculatorPlugin.lastBg() ?: return val lastBG = iobCobCalculatorPlugin.lastBg() ?: return
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData ?: return val glucoseStatus = GlucoseStatus(injector).glucoseStatusData ?: return
bundle.putDouble("glucoseMgdl", lastBG.value) // last BG in mgdl bundle.putDouble("glucoseMgdl", lastBG.value) // last BG in mgdl
bundle.putLong("glucoseTimeStamp", lastBG.date) // timestamp bundle.putLong("glucoseTimeStamp", lastBG.timestamp) // timestamp
bundle.putString("units", profileFunction.getUnits()) // units used in AAPS "mg/dl" or "mmol" bundle.putString("units", profileFunction.getUnits()) // units used in AAPS "mg/dl" or "mmol"
bundle.putString("slopeArrow", lastBG.directionToSymbol(databaseHelper)) // direction arrow as string bundle.putString("slopeArrow", lastBG.trendArrow.text) // direction arrow as string
bundle.putDouble("deltaMgdl", glucoseStatus.delta) // bg delta in mgdl bundle.putDouble("deltaMgdl", glucoseStatus.delta) // bg delta in mgdl
bundle.putDouble("avgDeltaMgdl", glucoseStatus.avgdelta) // average bg delta bundle.putDouble("avgDeltaMgdl", glucoseStatus.avgdelta) // average bg delta
bundle.putDouble("high", defaultValueHelper.determineHighLine()) // predefined top value of in range (green area) bundle.putDouble("high", defaultValueHelper.determineHighLine()) // predefined top value of in range (green area)

View file

@ -8,23 +8,36 @@ import android.view.ViewGroup
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding
import info.nightscout.androidaps.events.EventNewBG
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.food.FoodPlugin import info.nightscout.androidaps.plugins.general.food.FoodPlugin
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.Completable.fromAction
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.subscribeBy
import javax.inject.Inject import javax.inject.Inject
class MaintenanceFragment : DaggerFragment() { class MaintenanceFragment : DaggerFragment() {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var maintenancePlugin: MaintenancePlugin @Inject lateinit var maintenancePlugin: MaintenancePlugin
@Inject lateinit var mainApp: MainApp @Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var foodPlugin: FoodPlugin @Inject lateinit var foodPlugin: FoodPlugin
@Inject lateinit var importExportPrefs: ImportExportPrefsInterface @Inject lateinit var importExportPrefs: ImportExportPrefsInterface
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var repository: AppRepository
private val compositeDisposable = CompositeDisposable()
private var _binding: MaintenanceFragmentBinding? = null private var _binding: MaintenanceFragmentBinding? = null
@ -40,25 +53,42 @@ class MaintenanceFragment : DaggerFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() } binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() }
binding.logDelete.setOnClickListener { maintenancePlugin.deleteLogs() } binding.logDelete.setOnClickListener {
aapsLogger.debug("USER ENTRY: DELETE LOGS")
maintenancePlugin.deleteLogs()
}
binding.navResetdb.setOnClickListener { binding.navResetdb.setOnClickListener {
activity?.let { activity -> activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable {
aapsLogger.debug("USER ENTRY: RESET DATABASES")
compositeDisposable.add(
fromAction {
MainApp.getDbHelper().resetDatabases() MainApp.getDbHelper().resetDatabases()
// should be handled by Plugin-Interface and // should be handled by Plugin-Interface and
// additional service interface and plugin registry // additional service interface and plugin registry
foodPlugin.service?.resetFood() foodPlugin.service?.resetFood()
treatmentsPlugin.service.resetTreatments() treatmentsPlugin.service.resetTreatments()
repository.clearDatabases()
}
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.main)
.subscribeBy(
onError = { aapsLogger.error("Error clearing databases", it) },
onComplete = { rxBus.send(EventNewBG(null)) }
)
)
}) })
} }
} }
binding.navExport.setOnClickListener { binding.navExport.setOnClickListener {
aapsLogger.debug("USER ENTRY: EXPORT SETTINGS")
// start activity for checking permissions... // start activity for checking permissions...
importExportPrefs.verifyStoragePermissions(this) { importExportPrefs.verifyStoragePermissions(this) {
importExportPrefs.exportSharedPreferences(this) importExportPrefs.exportSharedPreferences(this)
} }
} }
binding.navImport.setOnClickListener { binding.navImport.setOnClickListener {
aapsLogger.debug("USER ENTRY: IMPORT SETTINGS")
// start activity for checking permissions... // start activity for checking permissions...
importExportPrefs.verifyStoragePermissions(this) { importExportPrefs.verifyStoragePermissions(this) {
importExportPrefs.importSharedPreferences(this) importExportPrefs.importSharedPreferences(this)
@ -70,6 +100,7 @@ class MaintenanceFragment : DaggerFragment() {
@Synchronized @Synchronized
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
compositeDisposable.clear()
_binding = null _binding = null
} }
} }

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.general.nsclient.data; package info.nightscout.androidaps.plugins.general.nsclient.data;
import android.text.Html;
import android.text.Spanned; import android.text.Spanned;
import org.json.JSONArray; import org.json.JSONArray;
@ -15,7 +14,6 @@ import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import dagger.android.HasAndroidInjector; import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.ConfigInterface; import info.nightscout.androidaps.interfaces.ConfigInterface;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
@ -475,8 +473,8 @@ public class NSDeviceStatus {
public static APSResult getAPSResult(HasAndroidInjector injector) { public static APSResult getAPSResult(HasAndroidInjector injector) {
APSResult result = new APSResult(injector); APSResult result = new APSResult(injector);
result.json = deviceStatusOpenAPSData.suggested; result.setJson(deviceStatusOpenAPSData.suggested);
result.date = deviceStatusOpenAPSData.clockSuggested; result.setDate(deviceStatusOpenAPSData.clockSuggested);
return result; return result;
} }

View file

@ -16,6 +16,8 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.BuildConfig import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.db.* import info.nightscout.androidaps.db.*
import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
@ -56,7 +58,8 @@ class OpenHumansUploader @Inject constructor(
private val sp: SP, private val sp: SP,
private val rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private val context: Context, private val context: Context,
private val treatmentsPlugin: TreatmentsPlugin private val treatmentsPlugin: TreatmentsPlugin,
val repository: AppRepository
) : PluginBase( ) : PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
@ -161,15 +164,15 @@ class OpenHumansUploader @Inject constructor(
super.onStop() super.onStop()
} }
fun enqueueBGReading(bgReading: BgReading?) = bgReading?.let { fun enqueueBGReading(glucoseValue: GlucoseValue?) = glucoseValue?.let {
insertQueueItem("BgReadings") { insertQueueItem("BgReadings") {
put("date", bgReading.date) put("date", glucoseValue.timestamp)
put("isValid", bgReading.isValid) put("isValid", glucoseValue.isValid)
put("value", bgReading.value) put("value", glucoseValue.value)
put("direction", bgReading.direction) put("direction", glucoseValue.trendArrow)
put("raw", bgReading.raw) put("raw", glucoseValue.raw)
put("source", bgReading.source) put("source", glucoseValue.sourceSensor)
put("nsId", bgReading._id) put("nsId", glucoseValue.interfaceIDs.nightscoutId)
} }
} }
@ -363,7 +366,7 @@ class OpenHumansUploader @Inject constructor(
.flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.treatmentData) } } .flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.treatmentData) } }
.map { enqueueTreatment(it); increaseCounter() } .map { enqueueTreatment(it); increaseCounter() }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allBgReadings) }) .andThen(Observable.defer { Observable.fromIterable(repository.compatGetBgReadingsDataFromTime(0, true).blockingGet()) })
.map { enqueueBGReading(it); increaseCounter() } .map { enqueueBGReading(it); increaseCounter() }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allCareportalEvents) }) .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allCareportalEvents) })

View file

@ -56,6 +56,7 @@ import info.nightscout.androidaps.skins.SkinProvider
import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.directionToIcon
import info.nightscout.androidaps.utils.extensions.toVisibility import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.protection.ProtectionCheck import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
@ -94,6 +95,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
@Inject lateinit var dexcomPlugin: DexcomPlugin @Inject lateinit var dexcomPlugin: DexcomPlugin
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
@Inject lateinit var xdripPlugin: XdripPlugin @Inject lateinit var xdripPlugin: XdripPlugin
@Inject lateinit var notificationStore: NotificationStore @Inject lateinit var notificationStore: NotificationStore
@Inject lateinit var actionStringHandler: ActionStringHandler @Inject lateinit var actionStringHandler: ActionStringHandler
@ -308,7 +310,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (xdripPlugin.isEnabled(PluginType.BGSOURCE)) if (xdripPlugin.isEnabled(PluginType.BGSOURCE))
openCgmApp("com.eveningoutpost.dexdrip") openCgmApp("com.eveningoutpost.dexdrip")
else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) { else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) {
dexcomPlugin.findDexcomPackageName()?.let { dexcomMediator.findDexcomPackageName()?.let {
openCgmApp(it) openCgmApp(it)
} }
?: ToastUtils.showToastInUiThread(activity, resourceHelper.gs(R.string.dexcom_app_not_installed)) ?: ToastUtils.showToastInUiThread(activity, resourceHelper.gs(R.string.dexcom_app_not_installed))
@ -320,7 +322,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
CalibrationDialog().show(childFragmentManager, "CalibrationDialog") CalibrationDialog().show(childFragmentManager, "CalibrationDialog")
} else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) { } else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) {
try { try {
dexcomPlugin.findDexcomPackageName()?.let { dexcomMediator.findDexcomPackageName()?.let {
startActivity(Intent("com.dexcom.cgm.activities.MeterEntryActivity").setPackage(it)) startActivity(Intent("com.dexcom.cgm.activities.MeterEntryActivity").setPackage(it))
} }
?: ToastUtils.showToastInUiThread(activity, resourceHelper.gs(R.string.dexcom_app_not_installed)) ?: ToastUtils.showToastInUiThread(activity, resourceHelper.gs(R.string.dexcom_app_not_installed))
@ -575,9 +577,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
else -> resourceHelper.gc(R.color.inrange) else -> resourceHelper.gc(R.color.inrange)
} }
binding.infoLayout.bg.text = lastBG.valueToUnitsToString(units) binding.infoLayout.bg.text = lastBG.valueToUnitsString(units)
binding.infoLayout.bg.setTextColor(color) binding.infoLayout.bg.setTextColor(color)
binding.infoLayout.arrow.setImageResource(lastBG.directionToIcon(databaseHelper)) binding.infoLayout.arrow.setImageResource(lastBG.trendArrow.directionToIcon())
binding.infoLayout.arrow.setColorFilter(color) binding.infoLayout.arrow.setColorFilter(color)
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
@ -601,8 +603,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} else flag and Paint.STRIKE_THRU_TEXT_FLAG.inv() } else flag and Paint.STRIKE_THRU_TEXT_FLAG.inv()
overview_bg.paintFlags = flag overview_bg.paintFlags = flag
} }
binding.infoLayout.timeAgo.text = DateUtil.minAgo(resourceHelper, lastBG.date) binding.infoLayout.timeAgo.text = DateUtil.minAgo(resourceHelper, lastBG.timestamp)
binding.infoLayout.timeAgoShort.text = "(" + DateUtil.minAgoShort(lastBG.date) + ")" binding.infoLayout.timeAgoShort.text = "(" + DateUtil.minAgoShort(lastBG.timestamp) + ")"
} }
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed() val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()

View file

@ -12,9 +12,10 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.GlucoseValueDataPoint
import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.LoopInterface import info.nightscout.androidaps.interfaces.LoopInterface
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
@ -35,7 +36,7 @@ import kotlin.math.max
import kotlin.math.min import kotlin.math.min
class GraphData( class GraphData(
injector: HasAndroidInjector, private val injector: HasAndroidInjector,
private val graph: GraphView, private val graph: GraphView,
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
private val treatmentsPlugin: TreatmentsInterface private val treatmentsPlugin: TreatmentsInterface
@ -50,7 +51,7 @@ class GraphData(
var maxY = Double.MIN_VALUE var maxY = Double.MIN_VALUE
private var minY = Double.MAX_VALUE private var minY = Double.MAX_VALUE
private var bgReadingsArray: List<BgReading>? = null private var bgReadingsArray: List<GlucoseValue>? = null
private val units: String private val units: String
private val series: MutableList<Series<*>> = ArrayList() private val series: MutableList<Series<*>> = ArrayList()
@ -60,7 +61,7 @@ class GraphData(
} }
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
fun addBgReadings(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double, predictions: MutableList<BgReading>?) { fun addBgReadings(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double, predictions: MutableList<GlucoseValueDataPoint>?) {
var maxBgValue = Double.MIN_VALUE var maxBgValue = Double.MIN_VALUE
bgReadingsArray = iobCobCalculatorPlugin.bgReadings bgReadingsArray = iobCobCalculatorPlugin.bgReadings
if (bgReadingsArray?.isEmpty() != false) { if (bgReadingsArray?.isEmpty() != false) {
@ -71,13 +72,13 @@ class GraphData(
} }
val bgListArray: MutableList<DataPointWithLabelInterface> = ArrayList() val bgListArray: MutableList<DataPointWithLabelInterface> = ArrayList()
for (bg in bgReadingsArray!!) { for (bg in bgReadingsArray!!) {
if (bg.date < fromTime || bg.date > toTime) continue if (bg.timestamp < fromTime || bg.timestamp > toTime) continue
if (bg.value > maxBgValue) maxBgValue = bg.value if (bg.value > maxBgValue) maxBgValue = bg.value
bgListArray.add(bg) bgListArray.add(GlucoseValueDataPoint(injector, bg))
} }
if (predictions != null) { if (predictions != null) {
predictions.sortWith(Comparator { o1: BgReading, o2: BgReading -> o1.x.compareTo(o2.x) }) predictions.sortWith(Comparator { o1: GlucoseValueDataPoint, o2: GlucoseValueDataPoint -> o1.x.compareTo(o2.x) })
for (prediction in predictions) if (prediction.value >= 40) bgListArray.add(prediction) for (prediction in predictions) if (prediction.data.value >= 40) bgListArray.add(prediction)
} }
maxBgValue = Profile.fromMgdlToUnits(maxBgValue, units) maxBgValue = Profile.fromMgdlToUnits(maxBgValue, units)
maxBgValue = addUpperChartMargin(maxBgValue) maxBgValue = addUpperChartMargin(maxBgValue)
@ -212,8 +213,7 @@ class GraphData(
var time = fromTime var time = fromTime
while (time < toTime) { while (time < toTime) {
val tt = treatmentsPlugin.getTempTargetFromHistory(time) val tt = treatmentsPlugin.getTempTargetFromHistory(time)
var value: Double val value: Double = if (tt == null) {
value = if (tt == null) {
Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, units) Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, units)
} else { } else {
Profile.fromMgdlToUnits(tt.target(), units) Profile.fromMgdlToUnits(tt.target(), units)
@ -282,7 +282,7 @@ class GraphData(
bgReadingsArray?.let { bgReadingsArray -> bgReadingsArray?.let { bgReadingsArray ->
for (r in bgReadingsArray.indices) { for (r in bgReadingsArray.indices) {
val reading = bgReadingsArray[r] val reading = bgReadingsArray[r]
if (reading.date > date) continue if (reading.timestamp > date) continue
return Profile.fromMgdlToUnits(reading.value, units) return Profile.fromMgdlToUnits(reading.value, units)
} }
return if (bgReadingsArray.isNotEmpty()) Profile.fromMgdlToUnits(bgReadingsArray[0].value, units) else Profile.fromMgdlToUnits(100.0, units) return if (bgReadingsArray.isNotEmpty()) Profile.fromMgdlToUnits(bgReadingsArray[0].value, units) else Profile.fromMgdlToUnits(100.0, units)

View file

@ -25,6 +25,7 @@ import info.nightscout.androidaps.utils.androidNotification.openAppIntent
import info.nightscout.androidaps.utils.resources.IconsProvider import info.nightscout.androidaps.utils.resources.IconsProvider
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.valueToUnitsString
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -135,12 +136,12 @@ class PersistentNotificationPlugin @Inject constructor(
val lastBG = iobCobCalculatorPlugin.lastBg() val lastBG = iobCobCalculatorPlugin.lastBg()
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
if (lastBG != null) { if (lastBG != null) {
line1aa = lastBG.valueToUnitsToString(units) line1aa = lastBG.valueToUnitsString(units)
line1 = line1aa line1 = line1aa
if (glucoseStatus != null) { if (glucoseStatus != null) {
line1 += (" Δ" + Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) line1 += (" Δ" + Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
+ " avgΔ" + Profile.toSignedUnitsString(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units)) + " avgΔ" + Profile.toSignedUnitsString(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units))
line1aa += " " + lastBG.directionToSymbol(databaseHelper) line1aa += " " + lastBG.trendArrow.symbol
} else { } else {
line1 += " " + line1 += " " +
resourceHelper.gs(R.string.old_data) + resourceHelper.gs(R.string.old_data) +

View file

@ -305,11 +305,11 @@ class SmsCommunicatorPlugin @Inject constructor(
var reply = "" var reply = ""
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
if (actualBG != null) { if (actualBG != null) {
reply = resourceHelper.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsToString(units) + ", " reply = resourceHelper.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsString(units) + ", "
} else if (lastBG != null) { } else if (lastBG != null) {
val agoMsec = System.currentTimeMillis() - lastBG.date val agoMsec = System.currentTimeMillis() - lastBG.timestamp
val agoMin = (agoMsec / 60.0 / 1000.0).toInt() val agoMin = (agoMsec / 60.0 / 1000.0).toInt()
reply = resourceHelper.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsToString(units) + " " + String.format(resourceHelper.gs(R.string.sms_minago), agoMin) + ", " reply = resourceHelper.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsString(units) + " " + String.format(resourceHelper.gs(R.string.sms_minago), agoMin) + ", "
} }
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
if (glucoseStatus != null) reply += resourceHelper.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", " if (glucoseStatus != null) reply += resourceHelper.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", "

View file

@ -93,11 +93,11 @@ class TidepoolPlugin @Inject constructor(
disposable += rxBus disposable += rxBus
.toObservable(EventNewBG::class.java) .toObservable(EventNewBG::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.filter { it.bgReading != null } // better would be optional in API level >24 .filter { it.glucoseValue != null } // better would be optional in API level >24
.map { it.bgReading } .map { it.glucoseValue }
.subscribe({ bgReading -> .subscribe({ bgReading ->
if (bgReading!!.date < uploadChunk.getLastEnd()) if (bgReading!!.timestamp < uploadChunk.getLastEnd())
uploadChunk.setLastEnd(bgReading.date) uploadChunk.setLastEnd(bgReading.timestamp )
if (isEnabled(PluginType.GENERAL) if (isEnabled(PluginType.GENERAL)
&& (!sp.getBoolean(R.string.key_tidepool_only_while_charging, false) || receiverStatusStore.isCharging) && (!sp.getBoolean(R.string.key_tidepool_only_while_charging, false) || receiverStatusStore.isCharging)
&& (!sp.getBoolean(R.string.key_tidepool_only_while_unmetered, false) || receiverStatusStore.isWifiConnected) && (!sp.getBoolean(R.string.key_tidepool_only_while_unmetered, false) || receiverStatusStore.isWifiConnected)

View file

@ -1,15 +1,17 @@
package info.nightscout.androidaps.plugins.general.tidepool.comm package info.nightscout.androidaps.plugins.general.tidepool.comm
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Intervals import info.nightscout.androidaps.data.Intervals
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.db.TemporaryBasal import info.nightscout.androidaps.db.TemporaryBasal
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.tidepool.elements.* import info.nightscout.androidaps.plugins.general.tidepool.elements.*
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus
import info.nightscout.androidaps.plugins.general.tidepool.utils.GsonInstance import info.nightscout.androidaps.plugins.general.tidepool.utils.GsonInstance
@ -24,12 +26,14 @@ import kotlin.math.max
@Singleton @Singleton
class UploadChunk @Inject constructor( class UploadChunk @Inject constructor(
private val injector: HasAndroidInjector,
private val sp: SP, private val sp: SP,
private val rxBus: RxBusWrapper, private val rxBus: RxBusWrapper,
private val aapsLogger: AAPSLogger, private val aapsLogger: AAPSLogger,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val treatmentsPlugin: TreatmentsPlugin, private val treatmentsPlugin: TreatmentsPlugin,
private val activePlugin: ActivePluginProvider, private val activePlugin: ActivePluginProvider,
private val repository: AppRepository,
private val dateUtil: DateUtil private val dateUtil: DateUtil
) { ) {
@ -102,9 +106,10 @@ class UploadChunk @Inject constructor(
val start: Long = 0 val start: Long = 0
val end = DateUtil.now() val end = DateUtil.now()
val bgReadingList = MainApp.getDbHelper().getBgreadingsDataFromTime(start, end, true) val bgReadingList = repository.compatGetBgReadingsDataFromTime(start, end, true)
return if (bgReadingList.size > 0) .blockingGet()
bgReadingList[0].date return if (bgReadingList.isNotEmpty())
bgReadingList[0].timestamp
else -1 else -1
} }
@ -131,7 +136,8 @@ class UploadChunk @Inject constructor(
} }
private fun getBgReadings(start: Long, end: Long): List<SensorGlucoseElement> { private fun getBgReadings(start: Long, end: Long): List<SensorGlucoseElement> {
val readings = MainApp.getDbHelper().getBgreadingsDataFromTime(start, end, true) val readings = repository.compatGetBgReadingsDataFromTime(start, end, true)
.blockingGet()
val selection = SensorGlucoseElement.fromBgReadings(readings) val selection = SensorGlucoseElement.fromBgReadings(readings)
if (selection.isNotEmpty()) if (selection.isNotEmpty())
rxBus.send(EventTidepoolStatus("${selection.size} CGMs selected for upload")) rxBus.send(EventTidepoolStatus("${selection.size} CGMs selected for upload"))

View file

@ -1,14 +1,15 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose import com.google.gson.annotations.Expose
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.entities.GlucoseValue
import java.util.* import java.util.*
class SensorGlucoseElement(bgReading: BgReading) class SensorGlucoseElement(bgReading: GlucoseValue)
: BaseElement(bgReading.date, UUID.nameUUIDFromBytes(("AAPS-cgm" + bgReading.date).toByteArray()).toString()) { : BaseElement(bgReading.timestamp, UUID.nameUUIDFromBytes(("AAPS-cgm" + bgReading.timestamp).toByteArray()).toString()) {
@Expose @Expose
internal var units: String = "mg/dL" internal var units: String = "mg/dL"
@Expose @Expose
internal var value: Int = 0 internal var value: Int = 0
@ -18,7 +19,8 @@ class SensorGlucoseElement(bgReading: BgReading)
} }
companion object { companion object {
internal fun fromBgReadings(bgReadingList: List<BgReading>): List<SensorGlucoseElement> {
internal fun fromBgReadings(bgReadingList: List<GlucoseValue>): List<SensorGlucoseElement> {
val results = LinkedList<SensorGlucoseElement>() val results = LinkedList<SensorGlucoseElement>()
for (bgReading in bgReadingList) { for (bgReading in bgReadingList) {
results.add(SensorGlucoseElement(bgReading)) results.add(SensorGlucoseElement(bgReading))

View file

@ -31,11 +31,7 @@ import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
import info.nightscout.androidaps.plugins.treatments.CarbsGenerator import info.nightscout.androidaps.plugins.treatments.CarbsGenerator
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.wizard.BolusWizard import info.nightscout.androidaps.utils.wizard.BolusWizard

View file

@ -31,32 +31,33 @@ import dagger.android.AndroidInjection;
import dagger.android.HasAndroidInjector; import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.GlucoseValueDataPoint;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin; import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus; import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler; import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
import info.nightscout.androidaps.plugins.general.wear.WearPlugin; import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.receivers.ReceiverStatusStore; import info.nightscout.androidaps.receivers.ReceiverStatusStore;
import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.DefaultValueHelper; import info.nightscout.androidaps.utils.DefaultValueHelper;
import info.nightscout.androidaps.utils.GlucoseValueUtilsKt;
import info.nightscout.androidaps.utils.ToastUtils; import info.nightscout.androidaps.utils.ToastUtils;
import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.sharedPreferences.SP;
import kotlin.Suppress;
public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
@Inject public HasAndroidInjector injector; @Inject public HasAndroidInjector injector;
@ -72,6 +73,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
@Inject public IobCobCalculatorPlugin iobCobCalculatorPlugin; @Inject public IobCobCalculatorPlugin iobCobCalculatorPlugin;
@Inject public TreatmentsPlugin treatmentsPlugin; @Inject public TreatmentsPlugin treatmentsPlugin;
@Inject public ActionStringHandler actionStringHandler; @Inject public ActionStringHandler actionStringHandler;
@Inject public AppRepository repository;
@Inject ReceiverStatusStore receiverStatusStore; @Inject ReceiverStatusStore receiverStatusStore;
@Inject Config config; @Inject Config config;
@ -275,7 +277,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
private void sendData() { private void sendData() {
BgReading lastBG = iobCobCalculatorPlugin.lastBg(); GlucoseValue lastBG = iobCobCalculatorPlugin.lastBg();
// Log.d(TAG, logPrefix + "LastBg=" + lastBG); // Log.d(TAG, logPrefix + "LastBg=" + lastBG);
if (lastBG != null) { if (lastBG != null) {
GlucoseStatus glucoseStatus = new GlucoseStatus(injector).getGlucoseStatusData(); GlucoseStatus glucoseStatus = new GlucoseStatus(injector).getGlucoseStatusData();
@ -297,25 +299,25 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
} }
private DataMap dataMapSingleBG(BgReading lastBG, GlucoseStatus glucoseStatus) { private DataMap dataMapSingleBG(GlucoseValue lastBG, GlucoseStatus glucoseStatus) {
String units = profileFunction.getUnits(); String units = profileFunction.getUnits();
double convert2MGDL = 1.0; double convert2MGDL = 1.0;
if (units.equals(Constants.MMOL)) if (units.equals(Constants.MMOL))
convert2MGDL = Constants.MMOLL_TO_MGDL; convert2MGDL = Constants.MMOLL_TO_MGDL;
double lowLine = defaultValueHelper.determineLowLine()*convert2MGDL; double lowLine = defaultValueHelper.determineLowLine() * convert2MGDL;
double highLine = defaultValueHelper.determineHighLine()*convert2MGDL; double highLine = defaultValueHelper.determineHighLine() * convert2MGDL;
long sgvLevel = 0L; long sgvLevel = 0L;
if (lastBG.value > highLine) { if (lastBG.getValue() > highLine) {
sgvLevel = 1; sgvLevel = 1;
} else if (lastBG.value < lowLine) { } else if (lastBG.getValue() < lowLine) {
sgvLevel = -1; sgvLevel = -1;
} }
DataMap dataMap = new DataMap(); DataMap dataMap = new DataMap();
dataMap.putString("sgvString", lastBG.valueToUnitsToString(units)); dataMap.putString("sgvString", GlucoseValueUtilsKt.valueToUnitsString(lastBG, units));
dataMap.putString("glucoseUnits", units); dataMap.putString("glucoseUnits", units);
dataMap.putLong("timestamp", lastBG.date); dataMap.putLong("timestamp", lastBG.getTimestamp());
if (glucoseStatus == null) { if (glucoseStatus == null) {
dataMap.putString("slopeArrow", ""); dataMap.putString("slopeArrow", "");
dataMap.putString("delta", "--"); dataMap.putString("delta", "--");
@ -326,7 +328,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
dataMap.putString("avgDelta", deltastring(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units)); dataMap.putString("avgDelta", deltastring(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units));
} }
dataMap.putLong("sgvLevel", sgvLevel); dataMap.putLong("sgvLevel", sgvLevel);
dataMap.putDouble("sgvDouble", lastBG.value); dataMap.putDouble("sgvDouble", lastBG.getValue());
dataMap.putDouble("high", highLine); dataMap.putDouble("high", highLine);
dataMap.putDouble("low", lowLine); dataMap.putDouble("low", lowLine);
return dataMap; return dataMap;
@ -381,11 +383,11 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
googleApiConnect(); googleApiConnect();
} }
long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5); long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5);
BgReading last_bg = iobCobCalculatorPlugin.lastBg(); GlucoseValue last_bg = iobCobCalculatorPlugin.lastBg();
if (last_bg == null) return; if (last_bg == null) return;
List<BgReading> graph_bgs = MainApp.getDbHelper().getBgreadingsDataFromTime(startTime, true); List<GlucoseValue> graph_bgs = repository.compatGetBgReadingsDataFromTime(startTime, true).blockingGet();
GlucoseStatus glucoseStatus = new GlucoseStatus(injector).getGlucoseStatusData(true); GlucoseStatus glucoseStatus = new GlucoseStatus(injector).getGlucoseStatusData(true);
if (!graph_bgs.isEmpty()) { if (!graph_bgs.isEmpty()) {
@ -395,7 +397,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
return; return;
} }
final ArrayList<DataMap> dataMaps = new ArrayList<>(graph_bgs.size()); final ArrayList<DataMap> dataMaps = new ArrayList<>(graph_bgs.size());
for (BgReading bg : graph_bgs) { for (GlucoseValue bg : graph_bgs) {
DataMap dataMap = dataMapSingleBG(bg, glucoseStatus); DataMap dataMap = dataMapSingleBG(bg, glucoseStatus);
if (dataMap != null) { if (dataMap != null) {
dataMaps.add(dataMap); dataMaps.add(dataMap);
@ -535,14 +537,14 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
} }
final LoopPlugin.LastRun finalLastRun = loopPlugin.getLastRun(); final LoopPlugin.LastRun finalLastRun = loopPlugin.getLastRun();
if (sp.getBoolean("wear_predictions", true) && finalLastRun != null && finalLastRun.getRequest().hasPredictions && finalLastRun.getConstraintsProcessed() != null) { if (sp.getBoolean("wear_predictions", true) && finalLastRun != null && finalLastRun.getRequest().getHasPredictions() && finalLastRun.getConstraintsProcessed() != null) {
List<BgReading> predArray = finalLastRun.getConstraintsProcessed().getPredictions(); List<GlucoseValueDataPoint> predArray = finalLastRun.getConstraintsProcessed().getPredictions();
if (!predArray.isEmpty()) { if (!predArray.isEmpty()) {
final String units = profileFunction.getUnits(); final String units = profileFunction.getUnits();
for (BgReading bg : predArray) { for (GlucoseValueDataPoint bg : predArray) {
if (bg.value < 40) continue; if (bg.getData().getValue() < 40) continue;
predictions.add(predictionMap(bg.date, bg.value, bg.getPredectionColor())); predictions.add(predictionMap(bg.getData().getTimestamp(), bg.getData().getValue(), bg.getPredictionColor()));
} }
} }
} }

View file

@ -8,7 +8,7 @@ import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import dagger.android.HasAndroidInjector; import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
@ -71,7 +71,7 @@ public class GlucoseStatus {
synchronized (iobCobCalculatorPlugin.getDataLock()) { synchronized (iobCobCalculatorPlugin.getDataLock()) {
List<BgReading> data = iobCobCalculatorPlugin.getBgReadings(); List<GlucoseValue> data = iobCobCalculatorPlugin.getBgReadings();
if (data == null) { if (data == null) {
aapsLogger.debug(LTag.GLUCOSE, "data=null"); aapsLogger.debug(LTag.GLUCOSE, "data=null");
@ -84,18 +84,18 @@ public class GlucoseStatus {
return null; return null;
} }
if (data.get(0).date < DateUtil.now() - 7 * 60 * 1000L && !allowOldData) { if (data.get(0).getTimestamp() < DateUtil.now() - 7 * 60 * 1000L && !allowOldData) {
aapsLogger.debug(LTag.GLUCOSE, "olddata"); aapsLogger.debug(LTag.GLUCOSE, "olddata");
return null; return null;
} }
BgReading now = data.get(0); GlucoseValue now = data.get(0);
long now_date = now.date; long now_date = now.getTimestamp();
double change; double change;
if (sizeRecords == 1) { if (sizeRecords == 1) {
GlucoseStatus status = new GlucoseStatus(injector); GlucoseStatus status = new GlucoseStatus(injector);
status.glucose = now.value; status.glucose = now.getValue();
status.noise = 0d; status.noise = 0d;
status.short_avgdelta = 0d; status.short_avgdelta = 0d;
status.delta = 0d; status.delta = 0d;
@ -112,18 +112,18 @@ public class GlucoseStatus {
ArrayList<Double> long_deltas = new ArrayList<>(); ArrayList<Double> long_deltas = new ArrayList<>();
// Use the latest sgv value in the now calculations // Use the latest sgv value in the now calculations
now_value_list.add(now.value); now_value_list.add(now.getValue());
for (int i = 1; i < sizeRecords; i++) { for (int i = 1; i < sizeRecords; i++) {
if (data.get(i).value > 38) { if (data.get(i).getValue() > 38) {
BgReading then = data.get(i); GlucoseValue then = data.get(i);
long then_date = then.date; long then_date = then.getTimestamp();
double avgdelta; double avgdelta;
long minutesago; long minutesago;
minutesago = Math.round((now_date - then_date) / (1000d * 60)); minutesago = Math.round((now_date - then_date) / (1000d * 60));
// multiply by 5 to get the same units as delta, i.e. mg/dL/5m // multiply by 5 to get the same units as delta, i.e. mg/dL/5m
change = now.value - then.value; change = now.getValue() - then.getValue();
avgdelta = change / minutesago * 5; avgdelta = change / minutesago * 5;
aapsLogger.debug(LTag.GLUCOSE, then.toString() + " minutesago=" + minutesago + " avgdelta=" + avgdelta); aapsLogger.debug(LTag.GLUCOSE, then.toString() + " minutesago=" + minutesago + " avgdelta=" + avgdelta);
@ -131,8 +131,8 @@ public class GlucoseStatus {
// use the average of all data points in the last 2.5m for all further "now" calculations // use the average of all data points in the last 2.5m for all further "now" calculations
if (0 < minutesago && minutesago < 2.5) { if (0 < minutesago && minutesago < 2.5) {
// Keep and average all values within the last 2.5 minutes // Keep and average all values within the last 2.5 minutes
now_value_list.add(then.value); now_value_list.add(then.getValue());
now.value = average(now_value_list); now.setValue(average(now_value_list));
// short_deltas are calculated from everything ~5-15 minutes ago // short_deltas are calculated from everything ~5-15 minutes ago
} else if (2.5 < minutesago && minutesago < 17.5) { } else if (2.5 < minutesago && minutesago < 17.5) {
//console.error(minutesago, avgdelta); //console.error(minutesago, avgdelta);
@ -152,7 +152,7 @@ public class GlucoseStatus {
} }
GlucoseStatus status = new GlucoseStatus(injector); GlucoseStatus status = new GlucoseStatus(injector);
status.glucose = now.value; status.glucose = now.getValue();
status.date = now_date; status.date = now_date;
status.noise = 0d; //for now set to nothing as not all CGMs report noise status.noise = 0d; //for now set to nothing as not all CGMs report noise

View file

@ -1,9 +1,9 @@
package info.nightscout.androidaps.plugins.iob.iobCobCalculator package info.nightscout.androidaps.plugins.iob.iobCobCalculator
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.entities.GlucoseValue
class InMemoryGlucoseValue @JvmOverloads constructor(var timestamp: Long = 0L, var value: Double = 0.0, var interpolated : Boolean = false) { class InMemoryGlucoseValue @JvmOverloads constructor(var timestamp: Long = 0L, var value: Double = 0.0, var interpolated: Boolean = false) {
constructor(gv: BgReading) : this(gv.date, gv.value) constructor(gv: GlucoseValue) : this(gv.timestamp, gv.value)
// var generated : value doesn't correspond to real value with timestamp close to real BG // var generated : value doesn't correspond to real value with timestamp close to real BG
} }

View file

@ -10,18 +10,19 @@ import org.json.JSONArray;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import dagger.android.HasAndroidInjector; import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData; import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.Event; import info.nightscout.androidaps.events.Event;
@ -72,6 +73,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
private final SensitivityWeightedAveragePlugin sensitivityWeightedAveragePlugin; private final SensitivityWeightedAveragePlugin sensitivityWeightedAveragePlugin;
private final FabricPrivacy fabricPrivacy; private final FabricPrivacy fabricPrivacy;
private final DateUtil dateUtil; private final DateUtil dateUtil;
private final AppRepository repository;
private final CompositeDisposable disposable = new CompositeDisposable(); private final CompositeDisposable disposable = new CompositeDisposable();
@ -80,14 +82,14 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
private LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>(); // oldest at index 0 private LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>(); // oldest at index 0
private LongSparseArray<BasalData> basalDataTable = new LongSparseArray<>(); // oldest at index 0 private LongSparseArray<BasalData> basalDataTable = new LongSparseArray<>(); // oldest at index 0
private volatile List<GlucoseValue> bgReadings = null; // newest at index 0
private volatile List<InMemoryGlucoseValue> bucketed_data = null;
// we need to make sure that bucketed_data will always have the same timestamp for correct use of cached values // we need to make sure that bucketed_data will always have the same timestamp for correct use of cached values
// once referenceTime != null all bucketed data should be (x * 5min) from referenceTime // once referenceTime != null all bucketed data should be (x * 5min) from referenceTime
Long referenceTime = null; Long referenceTime = null;
private Boolean lastUsed5minCalculation = null; // true if used 5min bucketed data private Boolean lastUsed5minCalculation = null; // true if used 5min bucketed data
private volatile List<BgReading> bgReadings = null; // newest at index 0
private volatile List<InMemoryGlucoseValue> bucketed_data = null;
private final Object dataLock = new Object(); private final Object dataLock = new Object();
boolean stopCalculationTrigger = false; boolean stopCalculationTrigger = false;
@ -108,7 +110,8 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
SensitivityAAPSPlugin sensitivityAAPSPlugin, SensitivityAAPSPlugin sensitivityAAPSPlugin,
SensitivityWeightedAveragePlugin sensitivityWeightedAveragePlugin, SensitivityWeightedAveragePlugin sensitivityWeightedAveragePlugin,
FabricPrivacy fabricPrivacy, FabricPrivacy fabricPrivacy,
DateUtil dateUtil DateUtil dateUtil,
AppRepository repository
) { ) {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
@ -131,6 +134,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
this.sensitivityWeightedAveragePlugin = sensitivityWeightedAveragePlugin; this.sensitivityWeightedAveragePlugin = sensitivityWeightedAveragePlugin;
this.fabricPrivacy = fabricPrivacy; this.fabricPrivacy = fabricPrivacy;
this.dateUtil = dateUtil; this.dateUtil = dateUtil;
this.repository = repository;
} }
@Override @Override
@ -169,6 +173,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventNewBG.class) .toObservable(EventNewBG.class)
.observeOn(aapsSchedulers.getIo()) .observeOn(aapsSchedulers.getIo())
.debounce(1L, TimeUnit.SECONDS)
.subscribe(event -> { .subscribe(event -> {
stopCalculation("onEventNewBG"); stopCalculation("onEventNewBG");
runCalculation("onEventNewBG", System.currentTimeMillis(), true, true, event); runCalculation("onEventNewBG", System.currentTimeMillis(), true, true, event);
@ -227,11 +232,11 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
return autosensDataTable; return autosensDataTable;
} }
public List<BgReading> getBgReadings() { public List<GlucoseValue> getBgReadings() {
return bgReadings; return bgReadings;
} }
public void setBgReadings(List<BgReading> bgReadings) { public void setBgReadings(List<GlucoseValue> bgReadings) {
this.bgReadings = bgReadings; this.bgReadings = bgReadings;
} }
@ -272,10 +277,10 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
if (DateUtil.isCloseToNow(to)) { if (DateUtil.isCloseToNow(to)) {
// if close to now expect there can be some readings with time in close future (caused by wrong time setting) // if close to now expect there can be some readings with time in close future (caused by wrong time setting)
// so read all records // so read all records
bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime(start, false); bgReadings = repository.compatGetBgReadingsDataFromTime(start, false).blockingGet();
getAapsLogger().debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size() + " Start date: " + dateUtil.dateAndTimeString(start)); getAapsLogger().debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size() + " Start date: " + dateUtil.dateAndTimeString(start));
} else { } else {
bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime(start, to, false); bgReadings = repository.compatGetBgReadingsDataFromTime(start, to, false).blockingGet();
getAapsLogger().debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size() + " Start date: " + dateUtil.dateAndTimeString(start) + " End date: " + dateUtil.dateAndTimeString(to)); getAapsLogger().debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size() + " Start date: " + dateUtil.dateAndTimeString(start) + " End date: " + dateUtil.dateAndTimeString(to));
} }
} }
@ -287,8 +292,8 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
} }
long totalDiff = 0; long totalDiff = 0;
for (int i = 1; i < bgReadings.size(); ++i) { for (int i = 1; i < bgReadings.size(); ++i) {
long bgTime = bgReadings.get(i).date; long bgTime = bgReadings.get(i).getTimestamp();
long lastbgTime = bgReadings.get(i - 1).date; long lastbgTime = bgReadings.get(i - 1).getTimestamp();
long diff = lastbgTime - bgTime; long diff = lastbgTime - bgTime;
diff %= T.mins(5).msecs(); diff %= T.mins(5).msecs();
if (diff > T.mins(2).plus(T.secs(30)).msecs()) if (diff > T.mins(2).plus(T.secs(30)).msecs())
@ -331,27 +336,27 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
} }
@Nullable @Nullable
public BgReading findNewer(long time) { public GlucoseValue findNewer(long time) {
BgReading lastFound = bgReadings.get(0); GlucoseValue lastFound = bgReadings.get(0);
if (lastFound.date < time) return null; if (lastFound.getTimestamp() < time) return null;
for (int i = 1; i < bgReadings.size(); ++i) { for (int i = 1; i < bgReadings.size(); ++i) {
if (bgReadings.get(i).date == time) return bgReadings.get(i); if (bgReadings.get(i).getTimestamp() == time) return bgReadings.get(i);
if (bgReadings.get(i).date > time) continue; if (bgReadings.get(i).getTimestamp() > time) continue;
lastFound = bgReadings.get(i - 1); lastFound = bgReadings.get(i - 1);
if (bgReadings.get(i).date < time) break; if (bgReadings.get(i).getTimestamp() < time) break;
} }
return lastFound; return lastFound;
} }
@Nullable @Nullable
public BgReading findOlder(long time) { public GlucoseValue findOlder(long time) {
BgReading lastFound = bgReadings.get(bgReadings.size() - 1); GlucoseValue lastFound = bgReadings.get(bgReadings.size() - 1);
if (lastFound.date > time) return null; if (lastFound.getTimestamp() > time) return null;
for (int i = bgReadings.size() - 2; i >= 0; --i) { for (int i = bgReadings.size() - 2; i >= 0; --i) {
if (bgReadings.get(i).date == time) return bgReadings.get(i); if (bgReadings.get(i).getTimestamp() == time) return bgReadings.get(i);
if (bgReadings.get(i).date < time) continue; if (bgReadings.get(i).getTimestamp() < time) continue;
lastFound = bgReadings.get(i + 1); lastFound = bgReadings.get(i + 1);
if (bgReadings.get(i).date > time) break; if (bgReadings.get(i).getTimestamp() > time) break;
} }
return lastFound; return lastFound;
} }
@ -363,25 +368,25 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
} }
bucketed_data = new ArrayList<>(); bucketed_data = new ArrayList<>();
long currentTime = bgReadings.get(0).date - bgReadings.get(0).date % T.mins(5).msecs(); long currentTime = bgReadings.get(0).getTimestamp() - bgReadings.get(0).getTimestamp() % T.mins(5).msecs();
currentTime = adjustToReferenceTime(currentTime); currentTime = adjustToReferenceTime(currentTime);
getAapsLogger().debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(currentTime)); getAapsLogger().debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(currentTime));
//log.debug("First reading: " + new Date(currentTime).toLocaleString()); //log.debug("First reading: " + new Date(currentTime).toLocaleString());
while (true) { while (true) {
// test if current value is older than current time // test if current value is older than current time
BgReading newer = findNewer(currentTime); GlucoseValue newer = findNewer(currentTime);
BgReading older = findOlder(currentTime); GlucoseValue older = findOlder(currentTime);
if (newer == null || older == null) if (newer == null || older == null)
break; break;
if (older.date == newer.date) { // direct hit if (older.getTimestamp() == newer.getTimestamp()) { // direct hit
bucketed_data.add(new InMemoryGlucoseValue(newer)); bucketed_data.add(new InMemoryGlucoseValue(newer));
} else { } else {
double bgDelta = newer.value - older.value; double bgDelta = newer.getValue() - older.getValue();
long timeDiffToNew = newer.date - currentTime; long timeDiffToNew = newer.getTimestamp() - currentTime;
double currentBg = newer.value - (double) timeDiffToNew / (newer.date - older.date) * bgDelta; double currentBg = newer.getValue() - (double) timeDiffToNew / (newer.getTimestamp() - older.getTimestamp()) * bgDelta;
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(currentTime, Math.round(currentBg), true); InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(currentTime, Math.round(currentBg), true);
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
//log.debug("BG: " + newBgreading.value + " (" + new Date(newBgreading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")"); //log.debug("BG: " + newBgreading.value + " (" + new Date(newBgreading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")");
@ -400,27 +405,27 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
bucketed_data = new ArrayList<>(); bucketed_data = new ArrayList<>();
bucketed_data.add(new InMemoryGlucoseValue(bgReadings.get(0))); bucketed_data.add(new InMemoryGlucoseValue(bgReadings.get(0)));
getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgReadings.get(0).date) + " lastbgTime: " + "none-first-value" + " " + bgReadings.get(0).toString()); getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgReadings.get(0).getTimestamp()) + " lastbgTime: " + "none-first-value" + " " + bgReadings.get(0).toString());
int j = 0; int j = 0;
for (int i = 1; i < bgReadings.size(); ++i) { for (int i = 1; i < bgReadings.size(); ++i) {
long bgTime = bgReadings.get(i).date; long bgTime = bgReadings.get(i).getTimestamp();
long lastbgTime = bgReadings.get(i - 1).date; long lastbgTime = bgReadings.get(i - 1).getTimestamp();
//log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value); //log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value);
if (bgReadings.get(i).value < 39 || bgReadings.get(i - 1).value < 39) { if (bgReadings.get(i).getValue() < 39 || bgReadings.get(i - 1).getValue() < 39) {
throw new IllegalStateException("<39"); throw new IllegalStateException("<39");
} }
long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000); long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
if (Math.abs(elapsed_minutes) > 8) { if (Math.abs(elapsed_minutes) > 8) {
// interpolate missing data points // interpolate missing data points
double lastbg = bgReadings.get(i - 1).value; double lastbg = bgReadings.get(i - 1).getValue();
elapsed_minutes = Math.abs(elapsed_minutes); elapsed_minutes = Math.abs(elapsed_minutes);
//console.error(elapsed_minutes); //console.error(elapsed_minutes);
long nextbgTime; long nextbgTime;
while (elapsed_minutes > 5) { while (elapsed_minutes > 5) {
nextbgTime = lastbgTime - 5 * 60 * 1000; nextbgTime = lastbgTime - 5 * 60 * 1000;
j++; j++;
double gapDelta = bgReadings.get(i).value - lastbg; double gapDelta = bgReadings.get(i).getValue() - lastbg;
//console.error(gapDelta, lastbg, elapsed_minutes); //console.error(gapDelta, lastbg, elapsed_minutes);
double nextbg = lastbg + (5d / elapsed_minutes * gapDelta); double nextbg = lastbg + (5d / elapsed_minutes * gapDelta);
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(nextbgTime, Math.round(nextbg), true); InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(nextbgTime, Math.round(nextbg), true);
@ -433,16 +438,16 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
lastbgTime = nextbgTime; lastbgTime = nextbgTime;
} }
j++; j++;
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(bgTime, bgReadings.get(i).value); InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(bgTime, bgReadings.get(i).getValue());
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString()); getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
} else if (Math.abs(elapsed_minutes) > 2) { } else if (Math.abs(elapsed_minutes) > 2) {
j++; j++;
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(bgTime, bgReadings.get(i).value); InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(bgTime, bgReadings.get(i).getValue());
bucketed_data.add(newBgreading); bucketed_data.add(newBgreading);
getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString()); getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
} else { } else {
bucketed_data.get(j).setValue((bucketed_data.get(j).getValue() + bgReadings.get(i).value) / 2); bucketed_data.get(j).setValue((bucketed_data.get(j).getValue() + bgReadings.get(i).getValue()) / 2);
//log.error("***** Average"); //log.error("***** Average");
} }
} }
@ -914,14 +919,14 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
* Return last BgReading from database or null if db is empty * Return last BgReading from database or null if db is empty
*/ */
@Nullable @Nullable
public BgReading lastBg() { public GlucoseValue lastBg() {
List<BgReading> bgList = getBgReadings(); List<GlucoseValue> bgList = getBgReadings();
if (bgList == null) if (bgList == null)
return null; return null;
for (int i = 0; i < bgList.size(); i++) for (int i = 0; i < bgList.size(); i++)
if (bgList.get(i).value >= 39) if (bgList.get(i).getValue() >= 39)
return bgList.get(i); return bgList.get(i);
return null; return null;
} }
@ -931,13 +936,13 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
* or null if older * or null if older
*/ */
@Nullable @Nullable
public BgReading actualBg() { public GlucoseValue actualBg() {
BgReading lastBg = lastBg(); GlucoseValue lastBg = lastBg();
if (lastBg == null) if (lastBg == null)
return null; return null;
if (lastBg.date > System.currentTimeMillis() - 9 * 60 * 1000) if (lastBg.getTimestamp() > System.currentTimeMillis() - 9 * 60 * 1000)
return lastBg; return lastBg;
return null; return null;

View file

@ -18,15 +18,14 @@ import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.Event; import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults; import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
@ -35,7 +34,6 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutos
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.DecimalFormatter;

View file

@ -16,15 +16,14 @@ import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.Event; import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults; import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
@ -33,7 +32,6 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutos
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin; import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.DecimalFormatter;

View file

@ -5,32 +5,31 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.InvalidateGlucoseValueTransaction
import info.nightscout.androidaps.databinding.BgsourceFragmentBinding import info.nightscout.androidaps.databinding.BgsourceFragmentBinding
import info.nightscout.androidaps.databinding.BgsourceItemBinding import info.nightscout.androidaps.databinding.BgsourceItemBinding
import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.events.EventNewBG import info.nightscout.androidaps.events.EventNewBG
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryBgData
import info.nightscout.androidaps.plugins.source.BGSourceFragment.RecyclerViewAdapter.BgReadingsViewHolder
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.ListDiffCallback
import info.nightscout.androidaps.utils.ListUpdateCallbackHelper
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.directionToIcon
import info.nightscout.androidaps.utils.extensions.toVisibility import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.valueToUnitsString
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
class BGSourceFragment : DaggerFragment() { class BGSourceFragment : DaggerFragment() {
@ -41,6 +40,7 @@ class BGSourceFragment : DaggerFragment() {
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var databaseHelper: DatabaseHelperInterface @Inject lateinit var databaseHelper: DatabaseHelperInterface
@Inject lateinit var repository: AppRepository
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
@ -60,24 +60,27 @@ class BGSourceFragment : DaggerFragment() {
binding.recyclerview.setHasFixedSize(true) binding.recyclerview.setHasFixedSize(true)
binding.recyclerview.layoutManager = LinearLayoutManager(view.context) binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
val now = System.currentTimeMillis()
binding.recyclerview.adapter = RecyclerViewAdapter(getBgData(now))
} }
@Synchronized @Synchronized
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
disposable.add(rxBus val now = System.currentTimeMillis()
disposable += repository
.compatGetBgReadingsDataFromTime(now - millsToThePast, false)
.observeOn(aapsSchedulers.main)
.subscribe { list -> binding.recyclerview.adapter = RecyclerViewAdapter(list) }
disposable += rxBus
.toObservable(EventNewBG::class.java) .toObservable(EventNewBG::class.java)
.observeOn(aapsSchedulers.io)
.debounce(1L, TimeUnit.SECONDS)
.subscribe({
disposable += repository
.compatGetBgReadingsDataFromTime(now - millsToThePast, false)
.observeOn(aapsSchedulers.main) .observeOn(aapsSchedulers.main)
.subscribe({ updateGUI() }, fabricPrivacy::logException) .subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) }
) }, fabricPrivacy::logException)
disposable.add(rxBus
.toObservable(EventNewHistoryBgData::class.java)
.observeOn(aapsSchedulers.main)
.subscribe({ updateGUI() }, fabricPrivacy::logException)
)
updateGUI()
} }
@Synchronized @Synchronized
@ -89,87 +92,45 @@ class BGSourceFragment : DaggerFragment() {
@Synchronized @Synchronized
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
_binding = null
binding.recyclerview.adapter = null // avoid leaks binding.recyclerview.adapter = null // avoid leaks
_binding = null
} }
private fun updateGUI() { inner class RecyclerViewAdapter internal constructor(private var glucoseValues: List<GlucoseValue>) : RecyclerView.Adapter<RecyclerViewAdapter.GlucoseValuesViewHolder>() {
if (_binding == null) return
val now = System.currentTimeMillis()
(binding.recyclerview.adapter as? RecyclerViewAdapter)?.setData(getBgData(now))
}
private fun getBgData(now: Long) = MainApp.getDbHelper() override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): GlucoseValuesViewHolder {
.getAllBgreadingsDataFromTime(now - millsToThePast, false)
inner class RecyclerViewAdapter internal constructor(bgReadings: List<BgReading>) : RecyclerView.Adapter<BgReadingsViewHolder>() {
private var callbackHelper = ListUpdateCallbackHelper(this) { binding.recyclerview.smoothScrollToPosition(0) }
private val currentData: MutableList<BgReading> = mutableListOf<BgReading>().also { it.addAll(bgReadings) }
fun setData(newList: List<BgReading>) {
val diffResult = DiffUtil.calculateDiff(getListDiffCallback(ArrayList(newList), ArrayList(currentData)))
currentData.clear()
currentData.addAll(newList)
diffResult.dispatchUpdatesTo(callbackHelper)
}
private fun getListDiffCallback(newItems: List<BgReading>, oldItems: List<BgReading>): ListDiffCallback<BgReading> =
object : ListDiffCallback<BgReading>(newItems, oldItems) {
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val new = newItems[newItemPosition]
val old = oldItems[oldItemPosition]
return new.hasValidNS == old.hasValidNS &&
new.isValid == old.isValid &&
new.date == old.date &&
new.value == old.value
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
newItems[newItemPosition].date == oldItems[oldItemPosition].date
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): BgReadingsViewHolder {
val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.bgsource_item, viewGroup, false) val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.bgsource_item, viewGroup, false)
return BgReadingsViewHolder(v) return GlucoseValuesViewHolder(v)
} }
override fun onBindViewHolder(holder: BgReadingsViewHolder, position: Int) { override fun onBindViewHolder(holder: GlucoseValuesViewHolder, position: Int) {
val bgReading = currentData[position] val glucoseValue = glucoseValues[position]
holder.binding.ns.visibility = (NSUpload.isIdValid(bgReading._id)).toVisibility() holder.binding.ns.visibility = (glucoseValue.interfaceIDs.nightscoutId != null).toVisibility()
holder.binding.invalid.visibility = bgReading.isValid.not().toVisibility() holder.binding.invalid.visibility = (!glucoseValue.isValid).toVisibility()
holder.binding.date.text = dateUtil.dateAndTimeString(bgReading.date) holder.binding.date.text = dateUtil.dateAndTimeString(glucoseValue.timestamp)
holder.binding.value.text = bgReading.valueToUnitsToString(profileFunction.getUnits()) holder.binding.value.text = glucoseValue.valueToUnitsString(profileFunction.getUnits())
holder.binding.direction.setImageResource(bgReading.directionToIcon(databaseHelper)) holder.binding.direction.setImageResource(glucoseValue.trendArrow.directionToIcon())
holder.binding.remove.tag = bgReading holder.binding.remove.tag = glucoseValue
holder.binding.remove.visibility = bgReading.isValid.toVisibility()
} }
override fun getItemCount(): Int { override fun getItemCount(): Int = glucoseValues.size
return currentData.size
}
inner class BgReadingsViewHolder(view: View) : RecyclerView.ViewHolder(view) { inner class GlucoseValuesViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val binding = BgsourceItemBinding.bind(view) val binding = BgsourceItemBinding.bind(view)
init { init {
binding.remove.paintFlags = binding.remove.paintFlags or Paint.UNDERLINE_TEXT_FLAG
binding.remove.setOnClickListener { v: View -> binding.remove.setOnClickListener { v: View ->
val bgReading = v.tag as BgReading val glucoseValue = v.tag as GlucoseValue
activity?.let { activity -> activity?.let { activity ->
val text = dateUtil.dateAndTimeString(bgReading.date) + "\n" + bgReading.valueToUnitsToString(profileFunction.getUnits()) val text = dateUtil.dateAndTimeString(glucoseValue.timestamp) + "\n" + glucoseValue.valueToUnitsString(profileFunction.getUnits())
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable {
bgReading.isValid = false disposable += repository.runTransaction(InvalidateGlucoseValueTransaction(glucoseValue.id)).subscribe()
MainApp.getDbHelper().update(bgReading)
}) })
} }
} }
binding.remove.paintFlags = binding.remove.paintFlags or Paint.UNDERLINE_TEXT_FLAG
} }
} }
} }
} }
val BgReading.hasValidNS
get() = NSUpload.isIdValid(this._id)

View file

@ -8,34 +8,35 @@ import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.RequestDexcomPermissionActivity import info.nightscout.androidaps.activities.RequestDexcomPermissionActivity
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.db.Source import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.receivers.BundleStore import info.nightscout.androidaps.receivers.BundleStore
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.XDripBroadcast
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONObject import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class DexcomPlugin @Inject constructor( class DexcomPlugin @Inject constructor(
injector: HasAndroidInjector, injector: HasAndroidInjector,
private val mainApp: MainApp,
resourceHelper: ResourceHelper, resourceHelper: ResourceHelper,
aapsLogger: AAPSLogger, aapsLogger: AAPSLogger,
private val dexcomMediator: DexcomMediator,
config: Config config: Config
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.BGSOURCE) .mainType(PluginType.BGSOURCE)
@ -48,6 +49,8 @@ class DexcomPlugin @Inject constructor(
aapsLogger, resourceHelper, injector aapsLogger, resourceHelper, injector
), BgSourceInterface { ), BgSourceInterface {
private val disposable = CompositeDisposable()
init { init {
if (!config.NSCLIENT) { if (!config.NSCLIENT) {
pluginDescription.setDefault() pluginDescription.setDefault()
@ -60,19 +63,12 @@ class DexcomPlugin @Inject constructor(
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
if (ContextCompat.checkSelfPermission(mainApp, PERMISSION) != PackageManager.PERMISSION_GRANTED) { dexcomMediator.requestPermissionIfNeeded()
val intent = Intent(mainApp, RequestDexcomPermissionActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
mainApp.startActivity(intent)
}
} }
fun findDexcomPackageName(): String? { override fun onStop() {
val packageManager = mainApp.packageManager disposable.clear()
for (packageInfo in packageManager.getInstalledPackages(0)) { super.onStop()
if (PACKAGE_NAMES.contains(packageInfo.packageName)) return packageInfo.packageName
}
return null
} }
// cannot be inner class because of needed injection // cannot be inner class because of needed injection
@ -87,6 +83,8 @@ class DexcomPlugin @Inject constructor(
@Inject lateinit var nsUpload: NSUpload @Inject lateinit var nsUpload: NSUpload
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var bundleStore: BundleStore @Inject lateinit var bundleStore: BundleStore
@Inject lateinit var broadcastToXDrip: XDripBroadcast
@Inject lateinit var repository: AppRepository
init { init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this) (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
@ -97,72 +95,61 @@ class DexcomPlugin @Inject constructor(
val bundle = bundleStore.pickup(inputData.getLong("storeKey", -1)) val bundle = bundleStore.pickup(inputData.getLong("storeKey", -1))
?: return Result.failure() ?: return Result.failure()
try { try {
val sensorType = bundle.getString("sensorType") ?: "" val sourceSensor = when (bundle.getString("sensorType") ?: "") {
val glucoseValues = bundle.getBundle("glucoseValues") ?: return Result.failure() "G6" -> GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE
for (i in 0 until glucoseValues.size()) { "G5" -> GlucoseValue.SourceSensor.DEXCOM_G5_NATIVE
glucoseValues.getBundle(i.toString())?.let { glucoseValue -> else -> GlucoseValue.SourceSensor.DEXCOM_NATIVE_UNKNOWN
val bgReading = BgReading()
bgReading.value = glucoseValue.getInt("glucoseValue").toDouble()
bgReading.direction = glucoseValue.getString("trendArrow")
bgReading.date = glucoseValue.getLong("timestamp") * 1000
bgReading.raw = 0.0
if (MainApp.getDbHelper().createIfNotExists(bgReading, "Dexcom$sensorType")) {
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) {
nsUpload.uploadBg(bgReading, "AndroidAPS-Dexcom$sensorType")
}
if (sp.getBoolean(R.string.key_dexcomg5_xdripupload, false)) {
nsUpload.sendToXdrip(bgReading)
}
}
} }
val glucoseValuesBundle = bundle.getBundle("glucoseValues")
?: return Result.failure()
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
for (i in 0 until glucoseValuesBundle.size()) {
val glucoseValueBundle = glucoseValuesBundle.getBundle(i.toString())!!
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
timestamp = glucoseValueBundle.getLong("timestamp") * 1000,
value = glucoseValueBundle.getInt("glucoseValue").toDouble(),
noise = null,
raw = null,
trendArrow = GlucoseValue.TrendArrow.fromString(glucoseValueBundle.getString("trendArrow")!!),
sourceSensor = sourceSensor
)
} }
val calibrations = mutableListOf<CgmSourceTransaction.Calibration>()
bundle.getBundle("meters")?.let { meters -> bundle.getBundle("meters")?.let { meters ->
for (i in 0 until meters.size()) { for (i in 0 until meters.size()) {
val meter = meters.getBundle(i.toString()) meters.getBundle(i.toString())?.let {
meter?.let {
val timestamp = it.getLong("timestamp") * 1000 val timestamp = it.getLong("timestamp") * 1000
val now = DateUtil.now() val now = DateUtil.now()
if (timestamp > now - T.months(1).msecs() && timestamp < now) if (timestamp > now - T.months(1).msecs() && timestamp < now) {
if (MainApp.getDbHelper().getCareportalEventFromTimestamp(timestamp) == null) { calibrations.add(CgmSourceTransaction.Calibration(it.getLong("timestamp") * 1000,
val jsonObject = JSONObject() it.getInt("meterValue").toDouble()))
jsonObject.put("enteredBy", "AndroidAPS-Dexcom$sensorType")
jsonObject.put("created_at", DateUtil.toISOString(timestamp))
jsonObject.put("eventType", CareportalEvent.BGCHECK)
jsonObject.put("glucoseType", "Finger")
jsonObject.put("glucose", meter.getInt("meterValue"))
jsonObject.put("units", Constants.MGDL)
val careportalEvent = CareportalEvent(injector)
careportalEvent.date = timestamp
careportalEvent.source = Source.USER
careportalEvent.eventType = CareportalEvent.BGCHECK
careportalEvent.json = jsonObject.toString()
MainApp.getDbHelper().createOrUpdate(careportalEvent)
nsUpload.uploadCareportalEntryToNS(jsonObject)
} }
} }
} }
} }
if (sp.getBoolean(R.string.key_dexcom_lognssensorchange, false) && bundle.containsKey("sensorInsertionTime")) { val sensorStartTime = if (sp.getBoolean(R.string.key_dexcom_lognssensorchange, false) && bundle.containsKey("sensorInsertionTime")) {
bundle.let { bundle.getLong("sensorInsertionTime", 0) * 1000
val sensorInsertionTime = it.getLong("sensorInsertionTime") * 1000 } else {
val now = DateUtil.now() null
if (sensorInsertionTime > now - T.months(1).msecs() && sensorInsertionTime < now) }
if (MainApp.getDbHelper().getCareportalEventFromTimestamp(sensorInsertionTime) == null) { dexcomPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, calibrations, sensorStartTime)).subscribe({ result ->
val jsonObject = JSONObject() result.inserted.forEach {
jsonObject.put("enteredBy", "AndroidAPS-Dexcom$sensorType") broadcastToXDrip(it)
jsonObject.put("created_at", DateUtil.toISOString(sensorInsertionTime)) if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) {
jsonObject.put("eventType", CareportalEvent.SENSORCHANGE) nsUpload.uploadBg(it, sourceSensor.text)
val careportalEvent = CareportalEvent(injector) //aapsLogger.debug("XXXXX: dbAdd $it")
careportalEvent.date = sensorInsertionTime
careportalEvent.source = Source.USER
careportalEvent.eventType = CareportalEvent.SENSORCHANGE
careportalEvent.json = jsonObject.toString()
MainApp.getDbHelper().createOrUpdate(careportalEvent)
nsUpload.uploadCareportalEntryToNS(jsonObject)
} }
} }
result.updated.forEach {
broadcastToXDrip(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) {
nsUpload.updateBg(it, sourceSensor.text)
//aapsLogger.debug("XXXXX: dpUpdate $it")
} }
}
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Dexcom App", it)
})
} catch (e: Exception) { } catch (e: Exception) {
aapsLogger.error("Error while processing intent from Dexcom App", e) aapsLogger.error("Error while processing intent from Dexcom App", e)
} }
@ -178,4 +165,23 @@ class DexcomPlugin @Inject constructor(
"com.dexcom.g6.region3.mgdl", "com.dexcom.g6.region3.mmol") "com.dexcom.g6.region3.mgdl", "com.dexcom.g6.region3.mmol")
const val PERMISSION = "com.dexcom.cgm.EXTERNAL_PERMISSION" const val PERMISSION = "com.dexcom.cgm.EXTERNAL_PERMISSION"
} }
class DexcomMediator @Inject constructor(val context: Context) {
fun requestPermissionIfNeeded() {
if (ContextCompat.checkSelfPermission(context, PERMISSION) != PackageManager.PERMISSION_GRANTED) {
val intent = Intent(context, RequestDexcomPermissionActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
}
}
fun findDexcomPackageName(): String? {
val packageManager = context.packageManager
for (packageInfo in packageManager.getInstalledPackages(0)) {
if (PACKAGE_NAMES.contains(packageInfo.packageName)) return packageInfo.packageName
}
return null
}
}
} }

View file

@ -7,7 +7,9 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
@ -18,8 +20,11 @@ import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.receivers.BundleStore import info.nightscout.androidaps.receivers.BundleStore
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.XDripBroadcast
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.util.* import java.util.*
@ -44,18 +49,28 @@ class EversensePlugin @Inject constructor(
override var sensorBatteryLevel = -1 override var sensorBatteryLevel = -1
private val disposable = CompositeDisposable()
override fun onStop() {
disposable.clear()
super.onStop()
}
// cannot be inner class because of needed injection // cannot be inner class because of needed injection
class EversenseWorker( class EversenseWorker(
context: Context, context: Context,
params: WorkerParameters params: WorkerParameters
) : Worker(context, params) { ) : Worker(context, params) {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var eversensePlugin: EversensePlugin @Inject lateinit var eversensePlugin: EversensePlugin
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var nsUpload: NSUpload @Inject lateinit var nsUpload: NSUpload
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var bundleStore: BundleStore @Inject lateinit var bundleStore: BundleStore
@Inject lateinit var repository: AppRepository
@Inject lateinit var broadcastToXDrip: XDripBroadcast
init { init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this) (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
@ -73,7 +88,7 @@ class EversensePlugin @Inject constructor(
if (bundle.containsKey("batteryLevel")) { if (bundle.containsKey("batteryLevel")) {
aapsLogger.debug(LTag.BGSOURCE, "batteryLevel: " + bundle.getString("batteryLevel")) aapsLogger.debug(LTag.BGSOURCE, "batteryLevel: " + bundle.getString("batteryLevel"))
//sensorBatteryLevel = bundle.getString("batteryLevel").toInt() //sensorBatteryLevel = bundle.getString("batteryLevel").toInt()
// TODO: Philoul: Line to check I don't have eversense so I don't know what kind of information is sent... // TODO: Line to check I don't have eversense so I don't know what kind of information is sent...
} }
if (bundle.containsKey("signalStrength")) aapsLogger.debug(LTag.BGSOURCE, "signalStrength: " + bundle.getString("signalStrength")) if (bundle.containsKey("signalStrength")) aapsLogger.debug(LTag.BGSOURCE, "signalStrength: " + bundle.getString("signalStrength"))
if (bundle.containsKey("transmitterVersionNumber")) aapsLogger.debug(LTag.BGSOURCE, "transmitterVersionNumber: " + bundle.getString("transmitterVersionNumber")) if (bundle.containsKey("transmitterVersionNumber")) aapsLogger.debug(LTag.BGSOURCE, "transmitterVersionNumber: " + bundle.getString("transmitterVersionNumber"))
@ -85,6 +100,7 @@ class EversensePlugin @Inject constructor(
if (bundle.containsKey("transmitterVersionNumber")) aapsLogger.debug(LTag.BGSOURCE, "transmitterVersionNumber: " + bundle.getString("transmitterVersionNumber")) if (bundle.containsKey("transmitterVersionNumber")) aapsLogger.debug(LTag.BGSOURCE, "transmitterVersionNumber: " + bundle.getString("transmitterVersionNumber"))
if (bundle.containsKey("transmitterConnectionState")) aapsLogger.debug(LTag.BGSOURCE, "transmitterConnectionState: " + bundle.getString("transmitterConnectionState")) if (bundle.containsKey("transmitterConnectionState")) aapsLogger.debug(LTag.BGSOURCE, "transmitterConnectionState: " + bundle.getString("transmitterConnectionState"))
if (bundle.containsKey("glucoseLevels")) { if (bundle.containsKey("glucoseLevels")) {
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
val glucoseLevels = bundle.getIntArray("glucoseLevels") val glucoseLevels = bundle.getIntArray("glucoseLevels")
val glucoseRecordNumbers = bundle.getIntArray("glucoseRecordNumbers") val glucoseRecordNumbers = bundle.getIntArray("glucoseRecordNumbers")
val glucoseTimestamps = bundle.getLongArray("glucoseTimestamps") val glucoseTimestamps = bundle.getLongArray("glucoseTimestamps")
@ -92,19 +108,24 @@ class EversensePlugin @Inject constructor(
aapsLogger.debug(LTag.BGSOURCE, "glucoseLevels" + Arrays.toString(glucoseLevels)) aapsLogger.debug(LTag.BGSOURCE, "glucoseLevels" + Arrays.toString(glucoseLevels))
aapsLogger.debug(LTag.BGSOURCE, "glucoseRecordNumbers" + Arrays.toString(glucoseRecordNumbers)) aapsLogger.debug(LTag.BGSOURCE, "glucoseRecordNumbers" + Arrays.toString(glucoseRecordNumbers))
aapsLogger.debug(LTag.BGSOURCE, "glucoseTimestamps" + Arrays.toString(glucoseTimestamps)) aapsLogger.debug(LTag.BGSOURCE, "glucoseTimestamps" + Arrays.toString(glucoseTimestamps))
for (i in glucoseLevels.indices) { for (i in glucoseLevels.indices)
val bgReading = BgReading() glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
bgReading.value = glucoseLevels[i].toDouble() timestamp = glucoseTimestamps[i],
bgReading.date = glucoseTimestamps[i] value = glucoseLevels[i].toDouble(),
bgReading.raw = 0.0 raw = glucoseLevels[i].toDouble(),
val isNew = MainApp.getDbHelper().createIfNotExists(bgReading, "Eversense") noise = null,
if (isNew && sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { trendArrow = GlucoseValue.TrendArrow.NONE,
nsUpload.uploadBg(bgReading, "AndroidAPS-Eversense") sourceSensor = GlucoseValue.SourceSensor.EVERSENSE
} )
if (isNew && sp.getBoolean(R.string.key_dexcomg5_xdripupload, false)) { eversensePlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues ->
nsUpload.sendToXdrip(bgReading) savedValues.inserted.forEach {
} broadcastToXDrip(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false))
nsUpload.uploadBg(it, GlucoseValue.SourceSensor.EVERSENSE.text)
} }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Eversense App", it)
})
} }
} }
if (bundle.containsKey("calibrationGlucoseLevels")) { if (bundle.containsKey("calibrationGlucoseLevels")) {

View file

@ -4,16 +4,22 @@ import android.content.Context
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.utils.XDripBroadcast
import info.nightscout.androidaps.utils.resources.ResourceHelper 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 javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -32,14 +38,26 @@ class GlimpPlugin @Inject constructor(
aapsLogger, resourceHelper, injector aapsLogger, resourceHelper, injector
), BgSourceInterface { ), BgSourceInterface {
private val disposable = CompositeDisposable()
override fun onStop() {
disposable.clear()
super.onStop()
}
// cannot be inner class because of needed injection // cannot be inner class because of needed injection
class GlimpWorker( class GlimpWorker(
context: Context, context: Context,
params: WorkerParameters params: WorkerParameters
) : Worker(context, params) { ) : Worker(context, params) {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var glimpPlugin: GlimpPlugin @Inject lateinit var glimpPlugin: GlimpPlugin
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var repository: AppRepository
@Inject lateinit var broadcastToXDrip: XDripBroadcast
@Inject lateinit var sp: SP
@Inject lateinit var nsUpload: NSUpload
init { init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this) (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
@ -48,12 +66,24 @@ class GlimpPlugin @Inject constructor(
override fun doWork(): Result { override fun doWork(): Result {
if (!glimpPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() if (!glimpPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure()
aapsLogger.debug(LTag.BGSOURCE, "Received Glimp Data: $inputData}") aapsLogger.debug(LTag.BGSOURCE, "Received Glimp Data: $inputData}")
val bgReading = BgReading() val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
bgReading.value = inputData.getDouble("mySGV", 0.0) glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
bgReading.direction = inputData.getString("myTrend") timestamp = inputData.getLong("myTimestamp", 0),
bgReading.date = inputData.getLong("myTimestamp", 0) value = inputData.getDouble("mySGV", 0.0),
bgReading.raw = 0.0 raw = inputData.getDouble("mySGV", 0.0),
MainApp.getDbHelper().createIfNotExists(bgReading, "GLIMP") noise = null,
trendArrow = GlucoseValue.TrendArrow.fromString(inputData.getString("myTrend")),
sourceSensor = GlucoseValue.SourceSensor.GLIMP
)
glimpPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues ->
savedValues.inserted.forEach {
broadcastToXDrip(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false))
nsUpload.uploadBg(it, GlucoseValue.SourceSensor.GLIMP.text)
}
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Glimp App", it)
})
return Result.success() return Result.success()
} }
} }

View file

@ -4,16 +4,24 @@ import android.content.Context
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.receivers.BundleStore
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.XDripBroadcast
import info.nightscout.androidaps.utils.resources.ResourceHelper 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.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import javax.inject.Inject import javax.inject.Inject
@ -33,6 +41,13 @@ class MM640gPlugin @Inject constructor(
aapsLogger, resourceHelper, injector aapsLogger, resourceHelper, injector
), BgSourceInterface { ), BgSourceInterface {
private val disposable = CompositeDisposable()
override fun onStop() {
disposable.clear()
super.onStop()
}
// cannot be inner class because of needed injection // cannot be inner class because of needed injection
class MM640gWorker( class MM640gWorker(
context: Context, context: Context,
@ -40,7 +55,14 @@ class MM640gPlugin @Inject constructor(
) : Worker(context, params) { ) : Worker(context, params) {
@Inject lateinit var mM640gPlugin: MM640gPlugin @Inject lateinit var mM640gPlugin: MM640gPlugin
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var sp: SP
@Inject lateinit var nsUpload: NSUpload
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var bundleStore: BundleStore
@Inject lateinit var repository: AppRepository
@Inject lateinit var broadcastToXDrip: XDripBroadcast
init { init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this) (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
@ -54,22 +76,32 @@ class MM640gPlugin @Inject constructor(
aapsLogger.debug(LTag.BGSOURCE, "Received MM640g Data: $data") aapsLogger.debug(LTag.BGSOURCE, "Received MM640g Data: $data")
if (data != null && data.isNotEmpty()) { if (data != null && data.isNotEmpty()) {
try { try {
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
val jsonArray = JSONArray(data) val jsonArray = JSONArray(data)
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(i) val jsonObject = jsonArray.getJSONObject(i)
when (val type = jsonObject.getString("type")) { when (val type = jsonObject.getString("type")) {
"sgv" -> { "sgv" ->
val bgReading = BgReading() glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
bgReading.value = jsonObject.getDouble("sgv") timestamp = jsonObject.getLong("sgv"),
bgReading.direction = jsonObject.getString("direction") value = jsonObject.getDouble("sgv"),
bgReading.date = jsonObject.getLong("date") raw = jsonObject.getDouble("sgv"),
bgReading.raw = jsonObject.getDouble("sgv") noise = null,
MainApp.getDbHelper().createIfNotExists(bgReading, "MM640g") trendArrow = GlucoseValue.TrendArrow.fromString(jsonObject.getString("direction")),
} sourceSensor = GlucoseValue.SourceSensor.MM_600_SERIES
)
else -> aapsLogger.debug(LTag.BGSOURCE, "Unknown entries type: $type") else -> aapsLogger.debug(LTag.BGSOURCE, "Unknown entries type: $type")
} }
} }
mM640gPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues ->
savedValues.all().forEach {
broadcastToXDrip(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false))
nsUpload.uploadBg(it, GlucoseValue.SourceSensor.MM_600_SERIES.text)
}
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Eversense App", it)
})
} catch (e: JSONException) { } catch (e: JSONException) {
aapsLogger.error("Exception: ", e) aapsLogger.error("Exception: ", e)
} }

View file

@ -5,20 +5,25 @@ import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv
import info.nightscout.androidaps.utils.JsonHelper.safeGetLong import info.nightscout.androidaps.receivers.BundleStore
import info.nightscout.androidaps.utils.JsonHelper.safeGetString import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.XDripBroadcast
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import javax.inject.Inject import javax.inject.Inject
@ -50,21 +55,27 @@ class NSClientSourcePlugin @Inject constructor(
} }
} }
private val disposable = CompositeDisposable()
override fun onStop() {
disposable.clear()
super.onStop()
}
override fun advancedFilteringSupported(): Boolean { override fun advancedFilteringSupported(): Boolean {
return isAdvancedFilteringEnabled return isAdvancedFilteringEnabled
} }
private fun storeSgv(sgvJson: JSONObject) { private fun detectSource(glucoseValue: GlucoseValue) {
val nsSgv = NSSgv(sgvJson) if (glucoseValue.timestamp > lastBGTimeStamp) {
val bgReading = BgReading(injector, nsSgv) isAdvancedFilteringEnabled = arrayOf(
MainApp.getDbHelper().createIfNotExists(bgReading, "NS") GlucoseValue.SourceSensor.DEXCOM_NATIVE_UNKNOWN,
detectSource(safeGetString(sgvJson, "device", "none"), safeGetLong(sgvJson, "mills")) GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
} GlucoseValue.SourceSensor.DEXCOM_G5_NATIVE,
GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE_XDRIP,
private fun detectSource(source: String, timeStamp: Long) { GlucoseValue.SourceSensor.DEXCOM_G5_NATIVE_XDRIP
if (timeStamp > lastBGTimeStamp) { ).any { it == glucoseValue.sourceSensor }
isAdvancedFilteringEnabled = source.contains("G5 Native") || source.contains("G6 Native") || source.contains("AndroidAPS-DexcomG5") || source.contains("AndroidAPS-DexcomG6") lastBGTimeStamp = glucoseValue.timestamp
lastBGTimeStamp = timeStamp
} }
} }
@ -75,29 +86,61 @@ class NSClientSourcePlugin @Inject constructor(
) : Worker(context, params) { ) : Worker(context, params) {
@Inject lateinit var nsClientSourcePlugin: NSClientSourcePlugin @Inject lateinit var nsClientSourcePlugin: NSClientSourcePlugin
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var nsUpload: NSUpload
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var bundleStore: BundleStore
@Inject lateinit var repository: AppRepository
@Inject lateinit var broadcastToXDrip: XDripBroadcast
@Inject lateinit var dexcomPlugin: DexcomPlugin
init { init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this) (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
} }
private fun toGv(jsonObject: JSONObject): CgmSourceTransaction.TransactionGlucoseValue {
val sgv = NSSgv(jsonObject)
return CgmSourceTransaction.TransactionGlucoseValue(
timestamp = sgv.mills,
value = sgv.mgdl.toDouble(),
noise = null,
raw = if (sgv.filtered != null) sgv.filtered.toDouble() else sgv.mgdl.toDouble(),
trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction),
nightscoutId = sgv.id,
sourceSensor = GlucoseValue.SourceSensor.fromString(sgv.device)
)
}
override fun doWork(): Result { override fun doWork(): Result {
if (!nsClientSourcePlugin.isEnabled(PluginType.BGSOURCE) && !sp.getBoolean(R.string.key_ns_autobackfill, true)) return Result.failure() if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_autobackfill, true) && !dexcomPlugin.isEnabled()) return Result.failure()
try { try {
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
inputData.getString("sgv")?.let { sgvString -> inputData.getString("sgv")?.let { sgvString ->
aapsLogger.debug(LTag.BGSOURCE, "Received NS Data: $sgvString") aapsLogger.debug(LTag.BGSOURCE, "Received NS Data: $sgvString")
val sgvJson = JSONObject(sgvString) glucoseValues += toGv(JSONObject(sgvString))
nsClientSourcePlugin.storeSgv(sgvJson)
} }
inputData.getString("sgvs")?.let { sgvString -> inputData.getString("sgvs")?.let { sgvString ->
aapsLogger.debug(LTag.BGSOURCE, "Received NS Data: $sgvString") aapsLogger.debug(LTag.BGSOURCE, "Received NS Data: $sgvString")
val jsonArray = JSONArray(sgvString) val jsonArray = JSONArray(sgvString)
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length())
val sgvJson = jsonArray.getJSONObject(i) glucoseValues += toGv(jsonArray.getJSONObject(i))
nsClientSourcePlugin.storeSgv(sgvJson)
} }
nsClientSourcePlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null, !nsClientSourcePlugin.isEnabled())).subscribe({ result ->
result.updated.forEach {
//aapsLogger.debug("XXXXX: Updated $it")
broadcastToXDrip(it)
nsClientSourcePlugin.detectSource(it)
} }
result.inserted.forEach {
//aapsLogger.debug("XXXXX: Inserted $it")
broadcastToXDrip(it)
nsClientSourcePlugin.detectSource(it)
}
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from NSClient App", it)
})
} catch (e: Exception) { } catch (e: Exception) {
aapsLogger.error("Unhandled exception", e) aapsLogger.error("Unhandled exception", e)
return Result.failure() return Result.failure()

View file

@ -5,9 +5,10 @@ import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
@ -16,8 +17,11 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.utils.JsonHelper.safeGetString import info.nightscout.androidaps.utils.JsonHelper.safeGetString
import info.nightscout.androidaps.utils.XDripBroadcast
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import javax.inject.Inject import javax.inject.Inject
@ -38,16 +42,26 @@ class PoctechPlugin @Inject constructor(
aapsLogger, resourceHelper, injector aapsLogger, resourceHelper, injector
), BgSourceInterface { ), BgSourceInterface {
private val disposable = CompositeDisposable()
override fun onStop() {
disposable.clear()
super.onStop()
}
// cannot be inner class because of needed injection // cannot be inner class because of needed injection
class PoctechWorker( class PoctechWorker(
context: Context, context: Context,
params: WorkerParameters params: WorkerParameters
) : Worker(context, params) { ) : Worker(context, params) {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var poctechPlugin: PoctechPlugin @Inject lateinit var poctechPlugin: PoctechPlugin
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var nsUpload: NSUpload @Inject lateinit var nsUpload: NSUpload
@Inject lateinit var repository: AppRepository
@Inject lateinit var broadcastToXDrip: XDripBroadcast
init { init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this) (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
@ -57,24 +71,30 @@ class PoctechPlugin @Inject constructor(
if (!poctechPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() if (!poctechPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure()
aapsLogger.debug(LTag.BGSOURCE, "Received Poctech Data $inputData") aapsLogger.debug(LTag.BGSOURCE, "Received Poctech Data $inputData")
try { try {
val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
val jsonArray = JSONArray(inputData.getString("data")) val jsonArray = JSONArray(inputData.getString("data"))
aapsLogger.debug(LTag.BGSOURCE, "Received Poctech Data size:" + jsonArray.length()) aapsLogger.debug(LTag.BGSOURCE, "Received Poctech Data size:" + jsonArray.length())
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val json = jsonArray.getJSONObject(i) val json = jsonArray.getJSONObject(i)
val bgReading = BgReading() glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
bgReading.value = json.getDouble("current") timestamp = json.getLong("date"),
bgReading.direction = json.getString("direction") value = if (safeGetString(json, "units", Constants.MGDL) == "mmol/L") json.getDouble("current")
bgReading.date = json.getLong("date") else json.getDouble("current") * Constants.MMOLL_TO_MGDL,
bgReading.raw = json.getDouble("raw") raw = json.getDouble("raw"),
if (safeGetString(json, "units", Constants.MGDL) == "mmol/L") bgReading.value = bgReading.value * Constants.MMOLL_TO_MGDL noise = null,
val isNew = MainApp.getDbHelper().createIfNotExists(bgReading, "Poctech") trendArrow = GlucoseValue.TrendArrow.fromString(json.getString("direction")),
if (isNew && sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { sourceSensor = GlucoseValue.SourceSensor.POCTECH_NATIVE
nsUpload.uploadBg(bgReading, "AndroidAPS-Poctech") )
}
if (isNew && sp.getBoolean(R.string.key_dexcomg5_xdripupload, false)) {
nsUpload.sendToXdrip(bgReading)
} }
poctechPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues ->
savedValues.inserted.forEach {
broadcastToXDrip(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false))
nsUpload.uploadBg(it, GlucoseValue.SourceSensor.POCTECH_NATIVE.text)
} }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Poctech App", it)
})
} catch (e: JSONException) { } catch (e: JSONException) {
aapsLogger.error("Exception: ", e) aapsLogger.error("Exception: ", e)
return Result.failure() return Result.failure()

View file

@ -3,9 +3,10 @@ package info.nightscout.androidaps.plugins.source
import android.os.Handler import android.os.Handler
import android.os.HandlerThread import android.os.HandlerThread
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
@ -16,10 +17,13 @@ import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.XDripBroadcast
import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.isRunningTest import info.nightscout.androidaps.utils.extensions.isRunningTest
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -34,7 +38,10 @@ class RandomBgPlugin @Inject constructor(
private val virtualPumpPlugin: VirtualPumpPlugin, private val virtualPumpPlugin: VirtualPumpPlugin,
private val buildHelper: BuildHelper, private val buildHelper: BuildHelper,
private val sp: SP, private val sp: SP,
private val nsUpload: NSUpload private val nsUpload: NSUpload,
private val dateUtil: DateUtil,
private val repository: AppRepository,
private val xDripBroadcast: XDripBroadcast
) : PluginBase(PluginDescription() ) : PluginBase(PluginDescription()
.mainType(PluginType.BGSOURCE) .mainType(PluginType.BGSOURCE)
.fragmentClass(BGSourceFragment::class.java.name) .fragmentClass(BGSourceFragment::class.java.name)
@ -61,6 +68,8 @@ class RandomBgPlugin @Inject constructor(
} }
} }
private val disposable = CompositeDisposable()
override fun advancedFilteringSupported(): Boolean { override fun advancedFilteringSupported(): Boolean {
return true return true
} }
@ -68,6 +77,7 @@ class RandomBgPlugin @Inject constructor(
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
loopHandler.postDelayed(refreshLoop, T.mins(interval).msecs()) loopHandler.postDelayed(refreshLoop, T.mins(interval).msecs())
disposable.clear()
} }
override fun onStop() { override fun onStop() {
@ -88,16 +98,24 @@ class RandomBgPlugin @Inject constructor(
val currentMinute = cal.get(Calendar.MINUTE) + (cal.get(Calendar.HOUR_OF_DAY) % 2) * 60 val currentMinute = cal.get(Calendar.MINUTE) + (cal.get(Calendar.HOUR_OF_DAY) % 2) * 60
val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / 120.0 * 2 * PI)) / 2 val bgMgdl = min + ((max - min) + (max - min) * sin(currentMinute / 120.0 * 2 * PI)) / 2
val bgReading = BgReading() val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
bgReading.value = bgMgdl glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
bgReading.date = DateUtil.now() timestamp = dateUtil._now(),
bgReading.raw = bgMgdl value = bgMgdl,
if (MainApp.getDbHelper().createIfNotExists(bgReading, "RandomBG")) { raw = 0.0,
noise = null,
trendArrow = GlucoseValue.TrendArrow.NONE,
sourceSensor = GlucoseValue.SourceSensor.RANDOM
)
disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues ->
savedValues.inserted.forEach {
xDripBroadcast(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false))
nsUpload.uploadBg(bgReading, "AndroidAPS-RandomBG") nsUpload.uploadBg(it, GlucoseValue.SourceSensor.RANDOM.text)
if (sp.getBoolean(R.string.key_dexcomg5_xdripupload, false))
nsUpload.sendToXdrip(bgReading)
} }
aapsLogger.debug(LTag.BGSOURCE, "Generated BG: $bgReading") }, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Random plugin", it)
})
aapsLogger.debug(LTag.BGSOURCE, "Generated BG: $bgMgdl ${Date()}")
} }
} }

View file

@ -4,9 +4,10 @@ import android.content.Context
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
@ -14,8 +15,11 @@ import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.utils.XDripBroadcast
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -35,16 +39,26 @@ class TomatoPlugin @Inject constructor(
aapsLogger, resourceHelper, injector aapsLogger, resourceHelper, injector
), BgSourceInterface { ), BgSourceInterface {
private val disposable = CompositeDisposable()
override fun onStop() {
disposable.clear()
super.onStop()
}
// cannot be inner class because of needed injection // cannot be inner class because of needed injection
class TomatoWorker( class TomatoWorker(
context: Context, context: Context,
params: WorkerParameters params: WorkerParameters
) : Worker(context, params) { ) : Worker(context, params) {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var tomatoPlugin: TomatoPlugin @Inject lateinit var tomatoPlugin: TomatoPlugin
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var nsUpload: NSUpload @Inject lateinit var nsUpload: NSUpload
@Inject lateinit var repository: AppRepository
@Inject lateinit var broadcastToXDrip: XDripBroadcast
init { init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this) (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
@ -52,17 +66,24 @@ class TomatoPlugin @Inject constructor(
override fun doWork(): Result { override fun doWork(): Result {
if (!tomatoPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() if (!tomatoPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure()
val bgReading = BgReading() val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
aapsLogger.debug(LTag.BGSOURCE, "Received Tomato Data") glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
bgReading.value = inputData.getDouble("com.fanqies.tomatofn.Extras.BgEstimate", 0.0) timestamp = inputData.getLong("com.fanqies.tomatofn.Extras.Time", 0),
bgReading.date = inputData.getLong("com.fanqies.tomatofn.Extras.Time", 0) value = inputData.getDouble("com.fanqies.tomatofn.Extras.BgEstimate", 0.0),
val isNew = MainApp.getDbHelper().createIfNotExists(bgReading, "Tomato") raw = 0.0,
if (isNew && sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { noise = null,
nsUpload.uploadBg(bgReading, "AndroidAPS-Tomato") trendArrow = GlucoseValue.TrendArrow.NONE,
} sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_TOMATO
if (isNew && sp.getBoolean(R.string.key_dexcomg5_xdripupload, false)) { )
nsUpload.sendToXdrip(bgReading) tomatoPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues ->
savedValues.inserted.forEach {
broadcastToXDrip(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false))
nsUpload.uploadBg(it, GlucoseValue.SourceSensor.LIBRE_1_TOMATO.text)
} }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Tomato App", it)
})
return Result.success() return Result.success()
} }
} }

View file

@ -4,9 +4,10 @@ import android.content.Context
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
@ -15,6 +16,8 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.services.Intents import info.nightscout.androidaps.services.Intents
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -39,8 +42,21 @@ class XdripPlugin @Inject constructor(
return advancedFiltering return advancedFiltering
} }
private fun setSource(source: String) { private fun detectSource(glucoseValue: GlucoseValue) {
advancedFiltering = source.contains("G5 Native") || source.contains("G6 Native") advancedFiltering = arrayOf(
GlucoseValue.SourceSensor.DEXCOM_NATIVE_UNKNOWN,
GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE,
GlucoseValue.SourceSensor.DEXCOM_G5_NATIVE,
GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE_XDRIP,
GlucoseValue.SourceSensor.DEXCOM_G5_NATIVE_XDRIP
).any { it == glucoseValue.sourceSensor }
}
private val disposable = CompositeDisposable()
override fun onStop() {
disposable.clear()
super.onStop()
} }
// cannot be inner class because of needed injection // cannot be inner class because of needed injection
@ -50,6 +66,7 @@ class XdripPlugin @Inject constructor(
) : Worker(context, params) { ) : Worker(context, params) {
@Inject lateinit var xdripPlugin: XdripPlugin @Inject lateinit var xdripPlugin: XdripPlugin
@Inject lateinit var repository: AppRepository
init { init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this) (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
@ -58,15 +75,24 @@ class XdripPlugin @Inject constructor(
override fun doWork(): Result { override fun doWork(): Result {
if (!xdripPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() if (!xdripPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure()
xdripPlugin.aapsLogger.debug(LTag.BGSOURCE, "Received xDrip data: $inputData") xdripPlugin.aapsLogger.debug(LTag.BGSOURCE, "Received xDrip data: $inputData")
val bgReading = BgReading() val glucoseValues = mutableListOf<CgmSourceTransaction.TransactionGlucoseValue>()
bgReading.value = inputData.getDouble(Intents.EXTRA_BG_ESTIMATE, 0.0) glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
bgReading.direction = inputData.getString(Intents.EXTRA_BG_SLOPE_NAME) timestamp = inputData.getLong(Intents.EXTRA_TIMESTAMP, 0),
bgReading.date = inputData.getLong(Intents.EXTRA_TIMESTAMP, 0) value = inputData.getDouble(Intents.EXTRA_BG_ESTIMATE, 0.0),
bgReading.raw = inputData.getDouble(Intents.EXTRA_RAW, 0.0) raw = inputData.getDouble(Intents.EXTRA_RAW, 0.0),
noise = null,
trendArrow = GlucoseValue.TrendArrow.fromString(inputData.getString(Intents.EXTRA_BG_SLOPE_NAME)),
sourceSensor = GlucoseValue.SourceSensor.fromString(inputData.getString(Intents.XDRIP_DATA_SOURCE_DESCRIPTION)
?: "")
)
xdripPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues ->
savedValues.all().forEach {
xdripPlugin.detectSource(it)
}
}, {
xdripPlugin.aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Eversense App", it)
})
xdripPlugin.sensorBatteryLevel = inputData.getInt(Intents.EXTRA_SENSOR_BATTERY, -1) xdripPlugin.sensorBatteryLevel = inputData.getInt(Intents.EXTRA_SENSOR_BATTERY, -1)
val source = inputData.getString(Intents.XDRIP_DATA_SOURCE_DESCRIPTION) ?: ""
xdripPlugin.setSource(source)
MainApp.getDbHelper().createIfNotExists(bgReading, "XDRIP")
return Result.success() return Result.success()
} }
} }

View file

@ -0,0 +1,12 @@
package info.nightscout.androidaps.utils
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.database.entities.GlucoseValue
fun GlucoseValue.valueToUnits(units: String): Double =
if (units == Constants.MGDL) value
else value * Constants.MGDL_TO_MMOLL
fun GlucoseValue.valueToUnitsString(units: String): String =
if (units == Constants.MGDL) DecimalFormatter.to0Decimal(value)
else DecimalFormatter.to1Decimal(value * Constants.MGDL_TO_MMOLL)

View file

@ -3,7 +3,6 @@ package info.nightscout.androidaps.utils
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
@ -106,9 +105,9 @@ class LocalAlertUtils @Inject constructor(
} }
fun checkStaleBGAlert() { fun checkStaleBGAlert() {
val bgReading: BgReading? = iobCobCalculatorPlugin.lastBg() val bgReading = iobCobCalculatorPlugin.lastBg()
if (sp.getBoolean(R.string.key_enable_missed_bg_readings_alert, false) if (sp.getBoolean(R.string.key_enable_missed_bg_readings_alert, false)
&& bgReading != null && bgReading.date + missedReadingsThreshold() < System.currentTimeMillis() && sp.getLong("nextMissedReadingsAlarm", 0L) < System.currentTimeMillis()) { && bgReading != null && bgReading.timestamp + missedReadingsThreshold() < System.currentTimeMillis() && sp.getLong("nextMissedReadingsAlarm", 0L) < System.currentTimeMillis()) {
val n = Notification(Notification.BG_READINGS_MISSED, resourceHelper.gs(R.string.missed_bg_readings), Notification.URGENT) val n = Notification(Notification.BG_READINGS_MISSED, resourceHelper.gs(R.string.missed_bg_readings), Notification.URGENT)
n.soundId = R.raw.alarm n.soundId = R.raw.alarm
sp.putLong("nextMissedReadingsAlarm", System.currentTimeMillis() + missedReadingsThreshold()) sp.putLong("nextMissedReadingsAlarm", System.currentTimeMillis() + missedReadingsThreshold())

View file

@ -0,0 +1,60 @@
package info.nightscout.androidaps.utils
import android.content.Context
import android.content.Intent
import android.os.Bundle
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.text.SimpleDateFormat
import java.util.*
import javax.inject.Inject
class XDripBroadcast @Inject constructor(
private val context: Context,
private val aapsLogger: AAPSLogger,
private val sp: SP
) {
operator fun invoke(glucoseValue: GlucoseValue) {
if (sp.getBoolean(R.string.key_dexcomg5_xdripupload, false)) {
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US)
try {
val entriesBody = JSONArray()
val json = JSONObject()
json.put("sgv", glucoseValue.value)
json.put("direction", glucoseValue.trendArrow.text)
json.put("device", "G5")
json.put("type", "sgv")
json.put("date", glucoseValue.timestamp)
json.put("dateString", format.format(glucoseValue.timestamp))
entriesBody.put(json)
val bundle = Bundle()
bundle.putString("action", "add")
bundle.putString("collection", "entries")
bundle.putString("data", entriesBody.toString())
val intent = Intent(XDRIP_PLUS_NS_EMULATOR)
intent.putExtras(bundle).addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
context.sendBroadcast(intent)
val receivers = context.packageManager.queryBroadcastReceivers(intent, 0)
if (receivers.size < 1) {
//NSUpload.log.debug("No xDrip receivers found. ")
aapsLogger.debug(LTag.BGSOURCE, "No xDrip receivers found.")
} else {
aapsLogger.debug(LTag.BGSOURCE, "${receivers.size} xDrip receivers")
}
} catch (e: JSONException) {
aapsLogger.error(LTag.BGSOURCE, "Unhandled exception", e)
}
}
}
companion object {
const val XDRIP_PLUS_NS_EMULATOR = "com.eveningoutpost.dexdrip.NS_EMULATOR"
}
}

View file

@ -3,9 +3,9 @@ package info.nightscout.androidaps.utils.stats
import android.text.Spanned import android.text.Spanned
import android.util.LongSparseArray import android.util.LongSparseArray
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HtmlHelper import info.nightscout.androidaps.utils.HtmlHelper
@ -19,18 +19,20 @@ import javax.inject.Singleton
class TirCalculator @Inject constructor( class TirCalculator @Inject constructor(
private val resourceHelper: ResourceHelper, private val resourceHelper: ResourceHelper,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil private val dateUtil: DateUtil,
){ private val repository: AppRepository
) {
fun calculate(days: Long, lowMgdl: Double, highMgdl: Double): LongSparseArray<TIR> { fun calculate(days: Long, lowMgdl: Double, highMgdl: Double): LongSparseArray<TIR> {
if (lowMgdl < 39) throw RuntimeException("Low below 39") if (lowMgdl < 39) throw RuntimeException("Low below 39")
if (lowMgdl > highMgdl) throw RuntimeException("Low > High") if (lowMgdl > highMgdl) throw RuntimeException("Low > High")
val startTime = MidnightTime.calc(DateUtil.now() - T.days(days).msecs()) val startTime = MidnightTime.calc(DateUtil.now() - T.days(days).msecs())
val endTime = MidnightTime.calc(DateUtil.now()) val endTime = MidnightTime.calc(DateUtil.now())
val bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime(startTime, endTime, true) val bgReadings = repository.compatGetBgReadingsDataFromTime(startTime, endTime, true).blockingGet()
val result = LongSparseArray<TIR>() val result = LongSparseArray<TIR>()
for (bg in bgReadings) { for (bg in bgReadings) {
val midnight = MidnightTime.calc(bg.date) val midnight = MidnightTime.calc(bg.timestamp)
var tir = result[midnight] var tir = result[midnight]
if (tir == null) { if (tir == null) {
tir = TIR(midnight, lowMgdl, highMgdl) tir = TIR(midnight, lowMgdl, highMgdl)

View file

@ -3,10 +3,10 @@ package info.nightscout.androidaps.utils.wizard
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
@ -14,6 +14,7 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper.safeGetInt import info.nightscout.androidaps.utils.JsonHelper.safeGetInt
import info.nightscout.androidaps.utils.JsonHelper.safeGetString import info.nightscout.androidaps.utils.JsonHelper.safeGetString
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.valueToUnits
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.util.* import java.util.*
@ -71,7 +72,7 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
fun isActive(): Boolean = Profile.secondsFromMidnight() >= validFrom() && Profile.secondsFromMidnight() <= validTo() fun isActive(): Boolean = Profile.secondsFromMidnight() >= validFrom() && Profile.secondsFromMidnight() <= validTo()
fun doCalc(profile: Profile, profileName: String, lastBG: BgReading, _synchronized: Boolean): BolusWizard { fun doCalc(profile: Profile, profileName: String, lastBG: GlucoseValue, _synchronized: Boolean): BolusWizard {
val tempTarget = treatmentsPlugin.tempTargetFromHistory val tempTarget = treatmentsPlugin.tempTargetFromHistory
//BG //BG
var bg = 0.0 var bg = 0.0

View file

@ -1,185 +0,0 @@
package info.nightscout.androidaps.db
import android.content.Context
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBase
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
import java.util.*
import java.util.logging.Logger
@RunWith(PowerMockRunner::class)
@PrepareForTest(MainApp::class, Logger::class, L::class, GlucoseStatus::class)
class BgReadingTest : TestBase() {
@Mock lateinit var defaultValueHelper: DefaultValueHelper
@Mock lateinit var profileFunction: ProfileFunction
@Mock lateinit var resourceHelper: ResourceHelper
@Mock lateinit var databaseHelper: DatabaseHelperInterface
var injector: HasAndroidInjector = HasAndroidInjector {
AndroidInjector {
if (it is BgReading) {
it.aapsLogger = aapsLogger
it.resourceHelper = resourceHelper
it.defaultValueHelper = defaultValueHelper
it.profileFunction = profileFunction
}
}
}
@Test
fun valueToUnits() {
val bgReading = BgReading(injector)
bgReading.value = 18.0
Assert.assertEquals(18.0, bgReading.valueToUnits(Constants.MGDL) * 1, 0.01)
Assert.assertEquals(1.0, bgReading.valueToUnits(Constants.MMOL) * 1, 0.01)
}
@Test
fun directionToSymbol() {
val bgReading = BgReading(injector)
bgReading.direction = "DoubleDown"
Assert.assertEquals("\u21ca", bgReading.directionToSymbol(databaseHelper))
bgReading.direction = "SingleDown"
Assert.assertEquals("\u2193", bgReading.directionToSymbol(databaseHelper))
bgReading.direction = "FortyFiveDown"
Assert.assertEquals("\u2198", bgReading.directionToSymbol(databaseHelper))
bgReading.direction = "Flat"
Assert.assertEquals("\u2192", bgReading.directionToSymbol(databaseHelper))
bgReading.direction = "FortyFiveUp"
Assert.assertEquals("\u2197", bgReading.directionToSymbol(databaseHelper))
bgReading.direction = "SingleUp"
Assert.assertEquals("\u2191", bgReading.directionToSymbol(databaseHelper))
bgReading.direction = "DoubleUp"
Assert.assertEquals("\u21c8", bgReading.directionToSymbol(databaseHelper))
bgReading.direction = "OUT OF RANGE"
Assert.assertEquals("??", bgReading.directionToSymbol(databaseHelper))
}
@Test
fun directionToIcon() {
val bgReading = BgReading(injector)
bgReading.direction = "DoubleDown"
Assert.assertEquals(R.drawable.ic_doubledown, bgReading.directionToIcon(databaseHelper))
bgReading.direction = "SingleDown"
Assert.assertEquals(R.drawable.ic_singledown, bgReading.directionToIcon(databaseHelper))
bgReading.direction = "FortyFiveDown"
Assert.assertEquals(R.drawable.ic_fortyfivedown, bgReading.directionToIcon(databaseHelper))
bgReading.direction = "Flat"
Assert.assertEquals(R.drawable.ic_flat, bgReading.directionToIcon(databaseHelper))
bgReading.direction = "FortyFiveUp"
Assert.assertEquals(R.drawable.ic_fortyfiveup, bgReading.directionToIcon(databaseHelper))
bgReading.direction = "SingleUp"
Assert.assertEquals(R.drawable.ic_singleup, bgReading.directionToIcon(databaseHelper))
bgReading.direction = "DoubleUp"
Assert.assertEquals(R.drawable.ic_doubleup, bgReading.directionToIcon(databaseHelper))
bgReading.direction = "OUT OF RANGE"
Assert.assertEquals(R.drawable.ic_invalid, bgReading.directionToIcon(databaseHelper))
}
@Test fun dateTest() {
val bgReading = BgReading(injector)
val now = System.currentTimeMillis()
bgReading.date = now
val nowDate = Date(now)
Assert.assertEquals(now, bgReading.date(now).date)
Assert.assertEquals(now, bgReading.date(nowDate).date)
}
@Test fun valueTest() {
val bgReading = BgReading(injector)
val valueToSet = 81.0 // 4.5 mmol
Assert.assertEquals(81.0, bgReading.value(valueToSet).value, 0.01)
}
@Test fun copyFromTest() {
// val databaseHelper = Mockito.mock(DatabaseHelper::class.java)
// `when`(MainApp.getDbHelper()).thenReturn(databaseHelper)
setReadings(72, 0)
val bgReading = BgReading(injector)
val copy = BgReading(injector)
bgReading.value = 81.0
val now = System.currentTimeMillis()
bgReading.date = now
copy.date = now
copy.copyFrom(bgReading)
Assert.assertEquals(81.0, copy.value, 0.1)
Assert.assertEquals(now, copy.date)
Assert.assertEquals(bgReading.directionToSymbol(databaseHelper), copy.directionToSymbol(databaseHelper))
}
@Test
fun isEqualTest() {
val bgReading = BgReading(injector)
val copy = BgReading(injector)
bgReading.value = 81.0
val now = System.currentTimeMillis()
bgReading.date = now
copy.date = now
copy.copyFrom(bgReading)
Assert.assertTrue(copy.isEqual(bgReading))
Assert.assertFalse(copy.isEqual(BgReading(injector)))
}
@Test fun calculateDirection() {
val bgReading = BgReading(injector)
val bgReadingsList: List<BgReading>? = null
// val databaseHelper = Mockito.mock(DatabaseHelper::class.java)
// `when`(MainApp.getDbHelper()).thenReturn(databaseHelper)
`when`(databaseHelper.getAllBgreadingsDataFromTime(ArgumentMatchers.anyLong(), ArgumentMatchers.anyBoolean())).thenReturn(bgReadingsList)
Assert.assertEquals("NONE", bgReading.calculateDirection(databaseHelper))
setReadings(72, 0)
Assert.assertEquals("DoubleUp", bgReading.calculateDirection(databaseHelper))
setReadings(76, 60)
Assert.assertEquals("SingleUp", bgReading.calculateDirection(databaseHelper))
setReadings(74, 65)
Assert.assertEquals("FortyFiveUp", bgReading.calculateDirection(databaseHelper))
setReadings(72, 72)
Assert.assertEquals("Flat", bgReading.calculateDirection(databaseHelper))
setReadings(0, 72)
Assert.assertEquals("DoubleDown", bgReading.calculateDirection(databaseHelper))
setReadings(60, 76)
Assert.assertEquals("SingleDown", bgReading.calculateDirection(databaseHelper))
setReadings(65, 74)
Assert.assertEquals("FortyFiveDown", bgReading.calculateDirection(databaseHelper))
}
@Before
fun prepareMock() {
}
fun setReadings(current_value: Int, previous_value: Int) {
val now = BgReading(injector)
now.value = current_value.toDouble()
now.date = System.currentTimeMillis()
val previous = BgReading(injector)
previous.value = previous_value.toDouble()
previous.date = System.currentTimeMillis() - 6 * 60 * 1000L
val bgReadings: MutableList<BgReading> = mutableListOf()
bgReadings.add(now)
bgReadings.add(previous)
`when`(databaseHelper.getAllBgreadingsDataFromTime(ArgumentMatchers.anyLong(), ArgumentMatchers.anyBoolean())).thenReturn(bgReadings)
}
}

View file

@ -188,7 +188,7 @@ class APSResultTest : TestBaseWithProfile() {
apsResult.rate(20.0).tempBasalRequested(true) apsResult.rate(20.0).tempBasalRequested(true)
Assert.assertEquals(20.0, safeGetDouble(apsResult.json(), "rate"), 0.0) Assert.assertEquals(20.0, safeGetDouble(apsResult.json(), "rate"), 0.0)
apsResult.rate(20.0).tempBasalRequested(false) apsResult.rate(20.0).tempBasalRequested(false)
Assert.assertEquals(false, apsResult.json().has("rate")) Assert.assertEquals(false, apsResult.json()?.has("rate"))
} }
@Before @Before

View file

@ -3,10 +3,9 @@ package info.nightscout.androidaps.plugins.general.automation.triggers
import com.google.common.base.Optional import com.google.common.base.Optional
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator import info.nightscout.androidaps.plugins.general.automation.elements.Comparator
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import org.json.JSONObject import org.json.JSONObject
@ -93,9 +92,16 @@ class TriggerBgTest : TriggerTestBase() {
Assert.assertEquals(Optional.of(R.drawable.ic_cp_bgcheck), TriggerBg(injector).icon()) Assert.assertEquals(Optional.of(R.drawable.ic_cp_bgcheck), TriggerBg(injector).icon())
} }
private fun generateOneCurrentRecordBgData(): List<BgReading> { private fun generateOneCurrentRecordBgData(): List<GlucoseValue> {
val list: MutableList<BgReading> = ArrayList() val list: MutableList<GlucoseValue> = ArrayList()
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":214,\"mills\":" + (now - 1) + ",\"direction\":\"Flat\"}")))) list.add(GlucoseValue(
raw = 0.0,
noise = 0.0,
value = 214.0,
timestamp = now - 1,
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN,
trendArrow = GlucoseValue.TrendArrow.FLAT
))
return list return list
} }
} }

View file

@ -3,11 +3,10 @@ package info.nightscout.androidaps.plugins.general.automation.triggers
import com.google.common.base.Optional import com.google.common.base.Optional
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator import info.nightscout.androidaps.plugins.general.automation.elements.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta.DeltaType import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta.DeltaType
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import org.json.JSONObject import org.json.JSONObject
@ -101,16 +100,16 @@ class TriggerDeltaTest : TriggerTestBase() {
Assert.assertTrue(t.units == Constants.MGDL) Assert.assertTrue(t.units == Constants.MGDL)
} }
private fun generateValidBgData(): List<BgReading> { private fun generateValidBgData(): List<GlucoseValue> {
val list: MutableList<BgReading> = ArrayList() val list: MutableList<GlucoseValue> = ArrayList()
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":214,\"mills\":1514766900000,\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 214.0, timestamp = 1514766900000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":216,\"mills\":1514766600000,\"direction\":\"Flat\"}")))) // +2 list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 216.0, timestamp = 1514766600000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":219,\"mills\":1514766300000,\"direction\":\"Flat\"}")))) // +3 list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 219.0, timestamp = 1514766300000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":223,\"mills\":1514766000000,\"direction\":\"Flat\"}")))) // +4 list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 223.0, timestamp = 1514766000000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":222,\"mills\":1514765700000,\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 222.0, timestamp = 1514765700000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":224,\"mills\":1514765400000,\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 224.0, timestamp = 1514765400000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":226,\"mills\":1514765100000,\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 226.0, timestamp = 1514765100000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":228,\"mills\":1514764800000,\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 228.0, timestamp = 1514764800000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
return list return list
} }
} }

View file

@ -4,9 +4,7 @@ import android.content.Context
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
import info.nightscout.androidaps.plugins.general.automation.elements.InputBg import info.nightscout.androidaps.plugins.general.automation.elements.InputBg
@ -83,9 +81,6 @@ open class TriggerTestBase : TestBaseWithProfile() {
if (it is StaticLabel) { if (it is StaticLabel) {
it.resourceHelper = resourceHelper it.resourceHelper = resourceHelper
} }
if (it is BgReading) {
it.dateUtil = dateUtil
}
} }
} }

View file

@ -10,7 +10,7 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.data.IobTotal import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
@ -39,9 +39,6 @@ import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers import org.mockito.ArgumentMatchers
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyString
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito import org.mockito.Mockito
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
@ -75,12 +72,6 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
it.aapsLogger = aapsLogger it.aapsLogger = aapsLogger
it.resourceHelper = resourceHelper it.resourceHelper = resourceHelper
} }
if (it is BgReading) {
it.aapsLogger = aapsLogger
it.defaultValueHelper = defaultValueHelper
it.resourceHelper = resourceHelper
it.profileFunction = profileFunction
}
if (it is AuthRequest) { if (it is AuthRequest) {
it.aapsLogger = aapsLogger it.aapsLogger = aapsLogger
it.smsCommunicatorPlugin = smsCommunicatorPlugin it.smsCommunicatorPlugin = smsCommunicatorPlugin
@ -98,9 +89,8 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
private var hasBeenRun = false private var hasBeenRun = false
@Before fun prepareTests() { @Before fun prepareTests() {
val reading = BgReading(injector) val reading = GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = 1514766900000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT)
reading.value = 100.0 val bgList: MutableList<GlucoseValue> = ArrayList()
val bgList: MutableList<BgReading> = ArrayList()
bgList.add(reading) bgList.add(reading)
`when`(iobCobCalculatorPlugin.dataLock).thenReturn(Unit) `when`(iobCobCalculatorPlugin.dataLock).thenReturn(Unit)
@ -176,7 +166,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
`when`(profileFunction.getUnits()).thenReturn(Constants.MGDL) `when`(profileFunction.getUnits()).thenReturn(Constants.MGDL)
`when`(otp.name()).thenReturn("User") `when`(otp.name()).thenReturn("User")
`when`(otp.checkOTP(anyString())).thenReturn(OneTimePasswordValidationResult.OK) `when`(otp.checkOTP(ArgumentMatchers.anyString())).thenReturn(OneTimePasswordValidationResult.OK)
`when`(resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)).thenReturn("Remote command is not allowed") `when`(resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)).thenReturn("Remote command is not allowed")
`when`(resourceHelper.gs(R.string.sms_wrongcode)).thenReturn("Wrong code. Command cancelled.") `when`(resourceHelper.gs(R.string.sms_wrongcode)).thenReturn("Wrong code. Command cancelled.")
@ -195,7 +185,7 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
`when`(resourceHelper.gs(R.string.smscommunicator_loopisdisabled)).thenReturn("Loop is disabled") `when`(resourceHelper.gs(R.string.smscommunicator_loopisdisabled)).thenReturn("Loop is disabled")
`when`(resourceHelper.gs(R.string.smscommunicator_loopisenabled)).thenReturn("Loop is enabled") `when`(resourceHelper.gs(R.string.smscommunicator_loopisenabled)).thenReturn("Loop is enabled")
`when`(resourceHelper.gs(R.string.wrongformat)).thenReturn("Wrong format") `when`(resourceHelper.gs(R.string.wrongformat)).thenReturn("Wrong format")
`when`(resourceHelper.gs(eq(R.string.wrongTbrDuration), any())).thenAnswer({ i: InvocationOnMock -> "TBR duration must be a multiple of " + i.getArguments()[1] + " minutes and greater than 0."}) `when`(resourceHelper.gs(ArgumentMatchers.eq(R.string.wrongTbrDuration), ArgumentMatchers.any())).thenAnswer({ i: InvocationOnMock -> "TBR duration must be a multiple of " + i.getArguments()[1] + " minutes and greater than 0." })
`when`(resourceHelper.gs(R.string.smscommunicator_loophasbeendisabled)).thenReturn("Loop has been disabled") `when`(resourceHelper.gs(R.string.smscommunicator_loophasbeendisabled)).thenReturn("Loop has been disabled")
`when`(resourceHelper.gs(R.string.smscommunicator_loophasbeenenabled)).thenReturn("Loop has been enabled") `when`(resourceHelper.gs(R.string.smscommunicator_loophasbeenenabled)).thenReturn("Loop has been enabled")
`when`(resourceHelper.gs(R.string.smscommunicator_tempbasalcanceled)).thenReturn("Temp basal canceled") `when`(resourceHelper.gs(R.string.smscommunicator_tempbasalcanceled)).thenReturn("Temp basal canceled")
@ -450,9 +440,9 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
passCode = smsCommunicatorPlugin.messageToConfirm?.confirmCode!! passCode = smsCommunicatorPlugin.messageToConfirm?.confirmCode!!
// ignore from other number // ignore from other number
smsCommunicatorPlugin.processSms(Sms("5678", passCode)) smsCommunicatorPlugin.processSms(Sms("5678", passCode))
`when`(otp.checkOTP(anyString())).thenReturn(OneTimePasswordValidationResult.ERROR_WRONG_OTP) `when`(otp.checkOTP(ArgumentMatchers.anyString())).thenReturn(OneTimePasswordValidationResult.ERROR_WRONG_OTP)
smsCommunicatorPlugin.processSms(Sms("1234", "XXXX")) smsCommunicatorPlugin.processSms(Sms("1234", "XXXX"))
`when`(otp.checkOTP(anyString())).thenReturn(OneTimePasswordValidationResult.OK) `when`(otp.checkOTP(ArgumentMatchers.anyString())).thenReturn(OneTimePasswordValidationResult.OK)
Assert.assertEquals("XXXX", smsCommunicatorPlugin.messages[3].text) Assert.assertEquals("XXXX", smsCommunicatorPlugin.messages[3].text)
Assert.assertEquals("Wrong code. Command cancelled.", smsCommunicatorPlugin.messages[4].text) Assert.assertEquals("Wrong code. Command cancelled.", smsCommunicatorPlugin.messages[4].text)
//then correct code should not work //then correct code should not work

View file

@ -3,12 +3,9 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.TestBase
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import org.json.JSONException
import org.json.JSONObject
import org.junit.Assert import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -36,9 +33,6 @@ class GlucoseStatusTest : TestBase() {
it.aapsLogger = aapsLogger it.aapsLogger = aapsLogger
it.iobCobCalculatorPlugin = iobCobCalculatorPlugin it.iobCobCalculatorPlugin = iobCobCalculatorPlugin
} }
if (it is BgReading) {
it.dateUtil = dateUtil
}
} }
} }
@ -127,78 +121,57 @@ class GlucoseStatusTest : TestBase() {
} }
// [{"mgdl":214,"mills":1521895773113,"device":"xDrip-DexcomG5","direction":"Flat","filtered":191040,"unfiltered":205024,"noise":1,"rssi":100},{"mgdl":219,"mills":1521896073352,"device":"xDrip-DexcomG5","direction":"Flat","filtered":200160,"unfiltered":209760,"noise":1,"rssi":100},{"mgdl":222,"mills":1521896372890,"device":"xDrip-DexcomG5","direction":"Flat","filtered":207360,"unfiltered":212512,"noise":1,"rssi":100},{"mgdl":220,"mills":1521896673062,"device":"xDrip-DexcomG5","direction":"Flat","filtered":211488,"unfiltered":210688,"noise":1,"rssi":100},{"mgdl":193,"mills":1521896972933,"device":"xDrip-DexcomG5","direction":"Flat","filtered":212384,"unfiltered":208960,"noise":1,"rssi":100},{"mgdl":181,"mills":1521897273336,"device":"xDrip-DexcomG5","direction":"SingleDown","filtered":210592,"unfiltered":204320,"noise":1,"rssi":100},{"mgdl":176,"mills":1521897572875,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":206720,"unfiltered":197440,"noise":1,"rssi":100},{"mgdl":168,"mills":1521897872929,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":201024,"unfiltered":187904,"noise":1,"rssi":100},{"mgdl":161,"mills":1521898172814,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":193376,"unfiltered":178144,"noise":1,"rssi":100},{"mgdl":148,"mills":1521898472879,"device":"xDrip-DexcomG5","direction":"SingleDown","filtered":183264,"unfiltered":161216,"noise":1,"rssi":100},{"mgdl":139,"mills":1521898772862,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":170784,"unfiltered":148928,"noise":1,"rssi":100},{"mgdl":132,"mills":1521899072896,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":157248,"unfiltered":139552,"noise":1,"rssi":100},{"mgdl":125,"mills":1521899372834,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":144416,"unfiltered":129616.00000000001,"noise":1,"rssi":100},{"mgdl":128,"mills":1521899973456,"device":"xDrip-DexcomG5","direction":"Flat","filtered":130240.00000000001,"unfiltered":133536,"noise":1,"rssi":100},{"mgdl":132,"mills":1521900573287,"device":"xDrip-DexcomG5","direction":"Flat","filtered":133504,"unfiltered":138720,"noise":1,"rssi":100},{"mgdl":127,"mills":1521900873711,"device":"xDrip-DexcomG5","direction":"Flat","filtered":136480,"unfiltered":132992,"noise":1,"rssi":100},{"mgdl":127,"mills":1521901180151,"device":"xDrip-DexcomG5","direction":"Flat","filtered":136896,"unfiltered":132128,"noise":1,"rssi":100},{"mgdl":125,"mills":1521901473582,"device":"xDrip-DexcomG5","direction":"Flat","filtered":134624,"unfiltered":129696,"noise":1,"rssi":100},{"mgdl":120,"mills":1521901773597,"device":"xDrip-DexcomG5","direction":"Flat","filtered":130704.00000000001,"unfiltered":123376,"noise":1,"rssi":100},{"mgdl":116,"mills":1521902075855,"device":"xDrip-DexcomG5","direction":"Flat","filtered":126272,"unfiltered":118448,"noise":1,"rssi":100}] // [{"mgdl":214,"mills":1521895773113,"device":"xDrip-DexcomG5","direction":"Flat","filtered":191040,"unfiltered":205024,"noise":1,"rssi":100},{"mgdl":219,"mills":1521896073352,"device":"xDrip-DexcomG5","direction":"Flat","filtered":200160,"unfiltered":209760,"noise":1,"rssi":100},{"mgdl":222,"mills":1521896372890,"device":"xDrip-DexcomG5","direction":"Flat","filtered":207360,"unfiltered":212512,"noise":1,"rssi":100},{"mgdl":220,"mills":1521896673062,"device":"xDrip-DexcomG5","direction":"Flat","filtered":211488,"unfiltered":210688,"noise":1,"rssi":100},{"mgdl":193,"mills":1521896972933,"device":"xDrip-DexcomG5","direction":"Flat","filtered":212384,"unfiltered":208960,"noise":1,"rssi":100},{"mgdl":181,"mills":1521897273336,"device":"xDrip-DexcomG5","direction":"SingleDown","filtered":210592,"unfiltered":204320,"noise":1,"rssi":100},{"mgdl":176,"mills":1521897572875,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":206720,"unfiltered":197440,"noise":1,"rssi":100},{"mgdl":168,"mills":1521897872929,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":201024,"unfiltered":187904,"noise":1,"rssi":100},{"mgdl":161,"mills":1521898172814,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":193376,"unfiltered":178144,"noise":1,"rssi":100},{"mgdl":148,"mills":1521898472879,"device":"xDrip-DexcomG5","direction":"SingleDown","filtered":183264,"unfiltered":161216,"noise":1,"rssi":100},{"mgdl":139,"mills":1521898772862,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":170784,"unfiltered":148928,"noise":1,"rssi":100},{"mgdl":132,"mills":1521899072896,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":157248,"unfiltered":139552,"noise":1,"rssi":100},{"mgdl":125,"mills":1521899372834,"device":"xDrip-DexcomG5","direction":"FortyFiveDown","filtered":144416,"unfiltered":129616.00000000001,"noise":1,"rssi":100},{"mgdl":128,"mills":1521899973456,"device":"xDrip-DexcomG5","direction":"Flat","filtered":130240.00000000001,"unfiltered":133536,"noise":1,"rssi":100},{"mgdl":132,"mills":1521900573287,"device":"xDrip-DexcomG5","direction":"Flat","filtered":133504,"unfiltered":138720,"noise":1,"rssi":100},{"mgdl":127,"mills":1521900873711,"device":"xDrip-DexcomG5","direction":"Flat","filtered":136480,"unfiltered":132992,"noise":1,"rssi":100},{"mgdl":127,"mills":1521901180151,"device":"xDrip-DexcomG5","direction":"Flat","filtered":136896,"unfiltered":132128,"noise":1,"rssi":100},{"mgdl":125,"mills":1521901473582,"device":"xDrip-DexcomG5","direction":"Flat","filtered":134624,"unfiltered":129696,"noise":1,"rssi":100},{"mgdl":120,"mills":1521901773597,"device":"xDrip-DexcomG5","direction":"Flat","filtered":130704.00000000001,"unfiltered":123376,"noise":1,"rssi":100},{"mgdl":116,"mills":1521902075855,"device":"xDrip-DexcomG5","direction":"Flat","filtered":126272,"unfiltered":118448,"noise":1,"rssi":100}]
private fun generateValidBgData(): List<BgReading> { private fun generateValidBgData(): List<GlucoseValue> {
val list: MutableList<BgReading> = ArrayList() val list: MutableList<GlucoseValue> = ArrayList()
try { list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 214.0, timestamp = 1514766900000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":214,\"mills\":1514766900000,\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 216.0, timestamp = 1514766600000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":216,\"mills\":1514766600000,\"direction\":\"Flat\"}")))) // +2 list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 219.0, timestamp = 1514766300000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":219,\"mills\":1514766300000,\"direction\":\"Flat\"}")))) // +3 list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 223.0, timestamp = 1514766000000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":223,\"mills\":1514766000000,\"direction\":\"Flat\"}")))) // +4 list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 222.0, timestamp = 1514765700000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":222,\"mills\":1514765700000,\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 224.0, timestamp = 1514765400000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":224,\"mills\":1514765400000,\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 226.0, timestamp = 1514765100000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":226,\"mills\":1514765100000,\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 228.0, timestamp = 1514764800000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":228,\"mills\":1514764800000,\"direction\":\"Flat\"}"))))
} catch (e: JSONException) {
throw RuntimeException(e)
}
return list return list
} }
private fun generateMostRecentBgData(): List<BgReading> { private fun generateMostRecentBgData(): List<GlucoseValue> {
val list: MutableList<BgReading> = ArrayList() val list: MutableList<GlucoseValue> = ArrayList()
try { list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 214.0, timestamp = 1514766900000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":214,\"mills\":1514766900000,\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 216.0, timestamp = 1514766800000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":216,\"mills\":1514766800000,\"direction\":\"Flat\"}")))) // +2 list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 216.0, timestamp = 1514766600000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":216,\"mills\":1514766600000,\"direction\":\"Flat\"}"))))
} catch (e: JSONException) {
throw RuntimeException(e)
}
return list return list
} }
private fun generateInsufficientBgData(): List<BgReading> { private fun generateInsufficientBgData(): List<GlucoseValue> {
return ArrayList() return ArrayList()
} }
private fun generateOldBgData(): List<BgReading> { private fun generateOldBgData(): List<GlucoseValue> {
val list: MutableList<BgReading> = ArrayList() val list: MutableList<GlucoseValue> = ArrayList()
try { list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 228.0, timestamp = 1514764800000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":228,\"mills\":1514764800000,\"direction\":\"Flat\"}"))))
} catch (e: JSONException) {
throw RuntimeException(e)
}
return list return list
} }
private fun generateOneCurrentRecordBgData(): List<BgReading> { private fun generateOneCurrentRecordBgData(): List<GlucoseValue> {
val list: MutableList<BgReading> = ArrayList() val list: MutableList<GlucoseValue> = ArrayList()
try { list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 214.0, timestamp = 1514766900000, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":214,\"mills\":1514766900000,\"direction\":\"Flat\"}"))))
} catch (e: JSONException) {
throw RuntimeException(e)
}
return list return list
} }
private fun generateLibreTestData(): List<BgReading> { private fun generateLibreTestData(): List<GlucoseValue> {
val list: MutableList<BgReading> = ArrayList() val list: MutableList<GlucoseValue> = ArrayList()
try {
val endTime = 1514766900000L val endTime = 1514766900000L
val latestReading = 100.0 val latestReading = 100.0
// Now // Now
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":$latestReading,\"mills\":$endTime,\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = latestReading, timestamp = endTime, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
// One minute ago // One minute ago
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":" + latestReading + ",\"mills\":" + (endTime - 1000 * 60 * 1) + ",\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = latestReading, timestamp = endTime - 1000 * 60 * 1, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
// Two minutes ago // Two minutes ago
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":" + latestReading + ",\"mills\":" + (endTime - 1000 * 60 * 2) + ",\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = latestReading, timestamp = endTime - 1000 * 60 * 2, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
// Three minutes and beyond at constant rate // Three minutes and beyond at constant rate
for (i in 3..49) { for (i in 3..49)
list.add(BgReading(injector, NSSgv(JSONObject("{\"mgdl\":" + (latestReading + i * 2) + ",\"mills\":" + (endTime - 1000 * 60 * i) + ",\"direction\":\"Flat\"}")))) list.add(GlucoseValue(raw = 0.0, noise = 0.0, value = latestReading + i * 2, timestamp = endTime - 1000 * 60 * i, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
}
} catch (e: JSONException) {
throw RuntimeException(e)
}
return list return list
} }
} }

View file

@ -3,10 +3,11 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.TestBase
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
@ -27,7 +28,7 @@ import org.powermock.modules.junit4.PowerMockRunner
import java.util.* import java.util.*
@RunWith(PowerMockRunner::class) @RunWith(PowerMockRunner::class)
@PrepareForTest(FabricPrivacy::class) @PrepareForTest(FabricPrivacy::class, AppRepository::class)
class IobCobCalculatorPluginTest : TestBase() { class IobCobCalculatorPluginTest : TestBase() {
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
@ -42,129 +43,123 @@ class IobCobCalculatorPluginTest : TestBase() {
@Mock lateinit var defaultValueHelper: DefaultValueHelper @Mock lateinit var defaultValueHelper: DefaultValueHelper
@Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var fabricPrivacy: FabricPrivacy
@Mock lateinit var dateUtil: DateUtil @Mock lateinit var dateUtil: DateUtil
@Mock lateinit var repository: AppRepository
lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
val injector = HasAndroidInjector { val injector = HasAndroidInjector {
AndroidInjector { AndroidInjector {
if (it is BgReading) {
it.aapsLogger = aapsLogger
it.defaultValueHelper = defaultValueHelper
it.resourceHelper = resourceHelper
it.profileFunction = profileFunction
it.dateUtil = dateUtil
}
} }
} }
@Before @Before
fun mock() { fun mock() {
iobCobCalculatorPlugin = IobCobCalculatorPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, resourceHelper, profileFunction, activePlugin, treatmentsPlugin, sensitivityOref1Plugin, sensitivityAAPSPlugin, sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil) iobCobCalculatorPlugin = IobCobCalculatorPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, resourceHelper, profileFunction, activePlugin, treatmentsPlugin, sensitivityOref1Plugin, sensitivityAAPSPlugin, sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil, repository)
} }
@Test @Test
fun isAbout5minDataTest() { fun isAbout5minDataTest() {
val bgReadingList: MutableList<BgReading> = ArrayList() val bgReadingList: MutableList<GlucoseValue> = ArrayList()
// Super data should not be touched // Super data should not be touched
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(15).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(10).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(5).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData)
// too much shifted data should return false // too much shifted data should return false
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(15).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(9).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(9).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(5).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData)
// too much shifted and missing data should return false // too much shifted and missing data should return false
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(9).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(9).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(5).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData)
// too much shifted and missing data should return false // too much shifted and missing data should return false
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(83).plus(T.secs(40)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(83).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(78).plus(T.secs(40)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(78).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(73).plus(T.secs(40)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(73).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(68).plus(T.secs(40)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(68).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(63).plus(T.secs(40)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(63).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(58).plus(T.secs(40)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(58).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(53).plus(T.secs(40)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(53).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(48).plus(T.secs(40)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(48).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(43).plus(T.secs(40)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(43).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(38).plus(T.secs(33)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(38).plus(T.secs(40)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(33).plus(T.secs(1)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(33).plus(T.secs(1)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(28).plus(T.secs(0)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(28).plus(T.secs(0)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(23).plus(T.secs(0)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(23).plus(T.secs(0)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(16).plus(T.secs(36)).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(16).plus(T.secs(36)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData)
// slightly shifted data should return true // slightly shifted data should return true
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(15).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(10).msecs() - T.secs(10).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).plus(T.secs(10)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(5).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData)
// slightly shifted and missing data should return true // slightly shifted and missing data should return true
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(10).msecs() - T.secs(10).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).plus(T.secs(10)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(5).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData)
} }
@Test @Test
fun createBucketedData5minTest() { fun createBucketedData5minTest() {
val bgReadingList: MutableList<BgReading> = ArrayList() val bgReadingList: MutableList<GlucoseValue> = ArrayList()
// Super data should not be touched // Super data should not be touched
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(15).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(10).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(5).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData)
iobCobCalculatorPlugin.createBucketedData() iobCobCalculatorPlugin.createBucketedData()
Assert.assertEquals(bgReadingList[0].date, iobCobCalculatorPlugin.bucketedData[0].timestamp) Assert.assertEquals(bgReadingList[0].timestamp, iobCobCalculatorPlugin.bucketedData[0].timestamp)
Assert.assertEquals(bgReadingList[3].date, iobCobCalculatorPlugin.bucketedData[3].timestamp) Assert.assertEquals(bgReadingList[3].timestamp, iobCobCalculatorPlugin.bucketedData[3].timestamp)
Assert.assertEquals(bgReadingList.size.toLong(), iobCobCalculatorPlugin.bucketedData.size.toLong()) Assert.assertEquals(bgReadingList.size.toLong(), iobCobCalculatorPlugin.bucketedData.size.toLong())
// Missing value should be replaced // Missing value should be replaced
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(10).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).plus(T.secs(10)).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(5).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData)
iobCobCalculatorPlugin.createBucketedData() iobCobCalculatorPlugin.createBucketedData()
Assert.assertEquals(bgReadingList[0].date, iobCobCalculatorPlugin.bucketedData[0].timestamp) Assert.assertEquals(bgReadingList[0].timestamp, iobCobCalculatorPlugin.bucketedData[0].timestamp)
Assert.assertEquals(bgReadingList[2].date, iobCobCalculatorPlugin.bucketedData[3].timestamp) Assert.assertEquals(bgReadingList[2].timestamp, iobCobCalculatorPlugin.bucketedData[3].timestamp)
Assert.assertEquals(bgReadingList.size + 1.toLong(), iobCobCalculatorPlugin.bucketedData.size.toLong()) Assert.assertEquals(bgReadingList.size + 1.toLong(), iobCobCalculatorPlugin.bucketedData.size.toLong())
// drift should be cleared // drift should be cleared
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(15).msecs() + T.secs(10).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs() + T.secs(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(10).msecs() + T.secs(10).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs() + T.secs(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(5).msecs() - T.secs(10).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs() + T.secs(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(0).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(0).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData)
iobCobCalculatorPlugin.createBucketedData() iobCobCalculatorPlugin.createBucketedData()
@ -176,8 +171,8 @@ class IobCobCalculatorPluginTest : TestBase() {
// bucketed data should return null if not enough bg data // bucketed data should return null if not enough bg data
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(30).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(30).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(5).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData)
iobCobCalculatorPlugin.createBucketedData() iobCobCalculatorPlugin.createBucketedData()
@ -185,9 +180,9 @@ class IobCobCalculatorPluginTest : TestBase() {
// data should be reconstructed // data should be reconstructed
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(50).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(50).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(45).msecs()).value(90.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 90.0, timestamp = T.mins(45).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(40.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 40.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData)
iobCobCalculatorPlugin.createBucketedData() iobCobCalculatorPlugin.createBucketedData()
@ -201,9 +196,9 @@ class IobCobCalculatorPluginTest : TestBase() {
// non 5min data should be reconstructed // non 5min data should be reconstructed
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(50).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(50).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(48).msecs()).value(96.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 96.0, timestamp = T.mins(48).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(40.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 40.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData)
iobCobCalculatorPlugin.createBucketedData() iobCobCalculatorPlugin.createBucketedData()
@ -222,122 +217,34 @@ class IobCobCalculatorPluginTest : TestBase() {
// real data gap test // real data gap test
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T13:34:55Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T13:34:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T13:14:55Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T13:14:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T13:09:55Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T13:09:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T13:04:55Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T13:04:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T12:59:55Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:59:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T12:54:55Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:54:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T12:49:55Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:49:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T12:44:55Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:44:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T12:39:55Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:39:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T12:34:55Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:34:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T12:29:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:29:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T12:24:55Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:24:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T12:19:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:19:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T12:14:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:14:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T12:09:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:09:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T12:04:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T12:04:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T11:59:55Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T11:59:55Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T11:54:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T11:49:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T04:29:57Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T11:44:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T04:24:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T11:39:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T04:19:57Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T11:34:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T04:14:57Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T11:29:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T04:10:03Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T11:24:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T04:04:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T11:19:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T03:59:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T11:14:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T03:54:56Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T11:09:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T03:50:03Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T11:04:56Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-09-05T03:44:57Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T10:59:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T10:54:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T10:49:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T10:44:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T10:39:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T10:34:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T10:29:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T10:24:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T10:19:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T10:14:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T10:09:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T10:04:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T09:59:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T09:54:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T09:49:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T09:44:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T09:39:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T09:35:05Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T09:30:17Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T09:24:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T09:19:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T09:14:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T09:09:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T09:04:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T08:59:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T08:54:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T08:49:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T08:44:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T08:40:02Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T08:34:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T08:29:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T08:24:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T08:19:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T08:14:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T08:09:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T08:04:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T07:59:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T07:54:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T07:49:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T07:44:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T07:39:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T07:34:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T07:30:03Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T07:25:17Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T07:19:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T07:14:58Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T07:09:58Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T07:04:58Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T06:59:58Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T06:54:58Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T06:49:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T06:44:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T06:39:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T06:34:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T06:29:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T06:24:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T06:19:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T06:14:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T06:10:03Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T06:04:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T05:59:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T05:54:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T05:49:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T05:44:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T05:39:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T05:34:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T05:29:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T05:24:57Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T05:19:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T05:14:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T05:09:57Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T05:04:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T04:59:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T04:54:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T04:50:03Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T04:44:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T04:39:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T04:34:57Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T04:29:57Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T04:24:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T04:19:57Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T04:14:57Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T04:10:03Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T04:04:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T03:59:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T03:54:56Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T03:50:03Z")).value(100.0))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-09-05T03:44:57Z")).value(100.0))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
iobCobCalculatorPlugin.referenceTime = null iobCobCalculatorPlugin.referenceTime = null
Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(true, iobCobCalculatorPlugin.isAbout5minData)
@ -347,34 +254,34 @@ class IobCobCalculatorPluginTest : TestBase() {
// 5min 4sec data // 5min 4sec data
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T06:33:40Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:33:40Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T06:28:36Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:28:36Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T06:23:32Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:23:32Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T06:18:28Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:18:28Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T06:13:24Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:13:24Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T06:08:19Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:08:19Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T06:03:16Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T06:03:16Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T05:58:11Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:58:11Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T05:53:07Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:53:07Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T05:48:03Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:48:03Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T05:42:58Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:42:58Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T05:37:54Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:37:54Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T05:32:51Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:32:51Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T05:27:46Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:27:46Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T05:22:42Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:22:42Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T05:17:38Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:17:38Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T05:12:33Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:12:33Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T05:07:29Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:07:29Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T05:02:26Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T05:02:26Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T04:57:21Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T04:57:21Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(DateUtil.fromISODateString("2018-10-05T04:52:17Z")).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = DateUtil.fromISODateString("2018-10-05T04:52:17Z").time, sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData) Assert.assertEquals(false, iobCobCalculatorPlugin.isAbout5minData)
} }
@Test @Test
fun bgReadingsTest() { fun bgReadingsTest() {
val bgReadingList: List<BgReading> = ArrayList() val bgReadingList: List<GlucoseValue> = ArrayList()
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(bgReadingList, iobCobCalculatorPlugin.bgReadings) Assert.assertEquals(bgReadingList, iobCobCalculatorPlugin.bgReadings)
} }
@ -386,47 +293,47 @@ class IobCobCalculatorPluginTest : TestBase() {
@Test @Test
fun findNewerTest() { fun findNewerTest() {
val bgReadingList: MutableList<BgReading> = ArrayList() val bgReadingList: MutableList<GlucoseValue> = ArrayList()
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(15).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(10).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(5).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(T.mins(10).msecs(), iobCobCalculatorPlugin.findNewer(T.mins(8).msecs())!!.date) Assert.assertEquals(T.mins(10).msecs(), iobCobCalculatorPlugin.findNewer(T.mins(8).msecs())!!.timestamp)
Assert.assertEquals(T.mins(5).msecs(), iobCobCalculatorPlugin.findNewer(T.mins(5).msecs())!!.date) Assert.assertEquals(T.mins(5).msecs(), iobCobCalculatorPlugin.findNewer(T.mins(5).msecs())!!.timestamp)
Assert.assertEquals(T.mins(10).msecs(), iobCobCalculatorPlugin.findNewer(T.mins(10).msecs())!!.date) Assert.assertEquals(T.mins(10).msecs(), iobCobCalculatorPlugin.findNewer(T.mins(10).msecs())!!.timestamp)
Assert.assertEquals(T.mins(20).msecs(), iobCobCalculatorPlugin.findNewer(T.mins(20).msecs())!!.date) Assert.assertEquals(T.mins(20).msecs(), iobCobCalculatorPlugin.findNewer(T.mins(20).msecs())!!.timestamp)
Assert.assertEquals(null, iobCobCalculatorPlugin.findNewer(T.mins(22).msecs())) Assert.assertEquals(null, iobCobCalculatorPlugin.findNewer(T.mins(22).msecs()))
} }
@Test @Test
fun findOlderTest() { fun findOlderTest() {
val bgReadingList: MutableList<BgReading> = ArrayList() val bgReadingList: MutableList<GlucoseValue> = ArrayList()
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(15).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(10).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(5).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
Assert.assertEquals(T.mins(5).msecs(), iobCobCalculatorPlugin.findOlder(T.mins(8).msecs())!!.date) Assert.assertEquals(T.mins(5).msecs(), iobCobCalculatorPlugin.findOlder(T.mins(8).msecs())!!.timestamp)
Assert.assertEquals(T.mins(5).msecs(), iobCobCalculatorPlugin.findOlder(T.mins(5).msecs())!!.date) Assert.assertEquals(T.mins(5).msecs(), iobCobCalculatorPlugin.findOlder(T.mins(5).msecs())!!.timestamp)
Assert.assertEquals(T.mins(10).msecs(), iobCobCalculatorPlugin.findOlder(T.mins(10).msecs())!!.date) Assert.assertEquals(T.mins(10).msecs(), iobCobCalculatorPlugin.findOlder(T.mins(10).msecs())!!.timestamp)
Assert.assertEquals(T.mins(20).msecs(), iobCobCalculatorPlugin.findOlder(T.mins(20).msecs())!!.date) Assert.assertEquals(T.mins(20).msecs(), iobCobCalculatorPlugin.findOlder(T.mins(20).msecs())!!.timestamp)
Assert.assertEquals(null, iobCobCalculatorPlugin.findOlder(T.mins(4).msecs())) Assert.assertEquals(null, iobCobCalculatorPlugin.findOlder(T.mins(4).msecs()))
} }
@Test @Test
fun findPreviousTimeFromBucketedDataTest() { fun findPreviousTimeFromBucketedDataTest() {
val bgReadingList: MutableList<BgReading> = ArrayList() val bgReadingList: MutableList<GlucoseValue> = ArrayList()
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
iobCobCalculatorPlugin.createBucketedData() iobCobCalculatorPlugin.createBucketedData()
Assert.assertEquals(null, iobCobCalculatorPlugin.findPreviousTimeFromBucketedData(1000)) Assert.assertEquals(null, iobCobCalculatorPlugin.findPreviousTimeFromBucketedData(1000))
// Super data should not be touched // Super data should not be touched
bgReadingList.clear() bgReadingList.clear()
bgReadingList.add(BgReading(injector).date(T.mins(20).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(20).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(15).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(15).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(10).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(10).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
bgReadingList.add(BgReading(injector).date(T.mins(5).msecs()).value(100.0)) bgReadingList.add(GlucoseValue(raw = 0.0, noise = 0.0, value = 100.0, timestamp = T.mins(5).msecs(), sourceSensor = GlucoseValue.SourceSensor.UNKNOWN, trendArrow = GlucoseValue.TrendArrow.FLAT))
iobCobCalculatorPlugin.bgReadings = bgReadingList iobCobCalculatorPlugin.bgReadings = bgReadingList
iobCobCalculatorPlugin.createBucketedData() iobCobCalculatorPlugin.createBucketedData()
Assert.assertEquals(null, iobCobCalculatorPlugin.findPreviousTimeFromBucketedData(T.mins(4).msecs())) Assert.assertEquals(null, iobCobCalculatorPlugin.findPreviousTimeFromBucketedData(T.mins(4).msecs()))

View file

@ -42,4 +42,8 @@ android {
} }
dependencies {
implementation project(':database')
}
apply from: 'core_dependencies.gradle' apply from: 'core_dependencies.gradle'

View file

@ -42,7 +42,9 @@ dependencies {
api 'com.google.firebase:firebase-database-ktx' api 'com.google.firebase:firebase-database-ktx'
//RxBus //RxBus
api "io.reactivex.rxjava2:rxandroid:${rxandroid_version}" api "io.reactivex.rxjava2:rxjava:$rxjava_version"
api "io.reactivex.rxjava2:rxkotlin:$rxkotlin_version"
api "io.reactivex.rxjava2:rxandroid:$rxandroid_version"
api "org.apache.commons:commons-lang3:$commonslang3_version" api "org.apache.commons:commons-lang3:$commonslang3_version"
//CryptoUtil //CryptoUtil

View file

@ -2,6 +2,7 @@ package info.nightscout.androidaps.core.di
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.data.GlucoseValueDataPoint
import info.nightscout.androidaps.data.Profile import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.PumpEnactResult import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.db.* import info.nightscout.androidaps.db.*
@ -19,7 +20,7 @@ abstract class CoreDataClassesModule {
@ContributesAndroidInjector abstract fun profileInjector(): Profile @ContributesAndroidInjector abstract fun profileInjector(): Profile
@ContributesAndroidInjector abstract fun profileStoreInjector(): ProfileStore @ContributesAndroidInjector abstract fun profileStoreInjector(): ProfileStore
@ContributesAndroidInjector abstract fun bgReadingInjector(): BgReading @ContributesAndroidInjector abstract fun glucoseValueDataPointInjector(): GlucoseValueDataPoint
@ContributesAndroidInjector abstract fun treatmentInjector(): Treatment @ContributesAndroidInjector abstract fun treatmentInjector(): Treatment
@ContributesAndroidInjector abstract fun profileSwitchInjector(): ProfileSwitch @ContributesAndroidInjector abstract fun profileSwitchInjector(): ProfileSwitch
@ContributesAndroidInjector abstract fun temporaryBasalInjector(): TemporaryBasal @ContributesAndroidInjector abstract fun temporaryBasalInjector(): TemporaryBasal

View file

@ -0,0 +1,78 @@
package info.nightscout.androidaps.data
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.database.entities.GlucoseValue
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.resources.ResourceHelper
import javax.inject.Inject
class GlucoseValueDataPoint @Inject constructor(
val injector: HasAndroidInjector,
val data: GlucoseValue
) : DataPointWithLabelInterface {
@Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var resourceHelper: ResourceHelper
init {
injector.androidInjector().inject(this)
}
fun valueToUnits(units: String): Double =
if (units == Constants.MGDL) data.value else data.value * Constants.MGDL_TO_MMOLL
override fun getX(): Double {
return data.timestamp.toDouble()
}
override fun getY(): Double {
return valueToUnits(profileFunction.getUnits())
}
override fun setY(y: Double) {}
override fun getLabel(): String? = null
override fun getDuration(): Long = 0
override fun getShape(): PointsWithLabelGraphSeries.Shape =
if (isPrediction) PointsWithLabelGraphSeries.Shape.PREDICTION
else PointsWithLabelGraphSeries.Shape.BG
override fun getSize(): Float = 1f
override fun getColor(): Int {
val units = profileFunction.getUnits()
val lowLine = defaultValueHelper.determineLowLine()
val highLine = defaultValueHelper.determineHighLine()
return when {
isPrediction -> predictionColor
valueToUnits(units) < lowLine -> resourceHelper.gc(R.color.low)
valueToUnits(units) > highLine -> resourceHelper.gc(R.color.high)
else -> resourceHelper.gc(R.color.inrange)
}
}
val predictionColor: Int
get() {
return when (data.sourceSensor) {
GlucoseValue.SourceSensor.IOB_PREDICTION -> resourceHelper.gc(R.color.iob)
GlucoseValue.SourceSensor.COB_PREDICTION -> resourceHelper.gc(R.color.cob)
GlucoseValue.SourceSensor.aCOB_PREDICTION -> -0x7f000001 and resourceHelper.gc(R.color.cob)
GlucoseValue.SourceSensor.UAM_PREDICTION -> resourceHelper.gc(R.color.uam)
GlucoseValue.SourceSensor.ZT_PREDICTION -> resourceHelper.gc(R.color.zt)
else -> R.color.white
}
}
private val isPrediction: Boolean
get() = data.sourceSensor == GlucoseValue.SourceSensor.IOB_PREDICTION ||
data.sourceSensor == GlucoseValue.SourceSensor.COB_PREDICTION ||
data.sourceSensor == GlucoseValue.SourceSensor.aCOB_PREDICTION ||
data.sourceSensor == GlucoseValue.SourceSensor.UAM_PREDICTION ||
data.sourceSensor == GlucoseValue.SourceSensor.ZT_PREDICTION
}

View file

@ -1,334 +0,0 @@
package info.nightscout.androidaps.db;
import androidx.annotation.NonNull;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.inject.Inject;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.core.R;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
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.NSSgv;
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.DecimalFormatter;
import info.nightscout.androidaps.utils.DefaultValueHelper;
import info.nightscout.androidaps.utils.T;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
@DatabaseTable(tableName = "BgReadings")
public class BgReading implements DataPointWithLabelInterface {
@Inject public AAPSLogger aapsLogger;
@Inject public DefaultValueHelper defaultValueHelper;
@Inject public ProfileFunction profileFunction;
@Inject public ResourceHelper resourceHelper;
@Inject public DateUtil dateUtil;
@DatabaseField(id = true)
public long date;
@DatabaseField
public boolean isValid = true;
@DatabaseField
public double value;
@DatabaseField
public String direction;
@DatabaseField
public double raw;
@DatabaseField
public int source = Source.NONE;
@DatabaseField
public String _id = null; // NS _id
public boolean isCOBPrediction = false; // true when drawing predictions as bg points (COB)
public boolean isaCOBPrediction = false; // true when drawing predictions as bg points (aCOB)
public boolean isIOBPrediction = false; // true when drawing predictions as bg points (IOB)
public boolean isUAMPrediction = false; // true when drawing predictions as bg points (UAM)
public boolean isZTPrediction = false; // true when drawing predictions as bg points (ZT)
public BgReading() {
StaticInjector.Companion.getInstance().androidInjector().inject(this);
}
public BgReading(HasAndroidInjector injector) {
injector.androidInjector().inject(this);
}
public BgReading(HasAndroidInjector injector, NSSgv sgv) {
injector.androidInjector().inject(this);
date = sgv.getMills();
value = sgv.getMgdl();
raw = sgv.getFiltered() != null ? sgv.getFiltered() : value;
direction = sgv.getDirection();
_id = sgv.getId();
}
public Double valueToUnits(String units) {
if (units.equals(Constants.MGDL))
return value;
else
return value * Constants.MGDL_TO_MMOLL;
}
public String valueToUnitsToString(String units) {
if (units.equals(Constants.MGDL)) return DecimalFormatter.to0Decimal(value);
else return DecimalFormatter.to1Decimal(value * Constants.MGDL_TO_MMOLL);
}
public String directionToSymbol(DatabaseHelperInterface databaseHelper) {
String symbol = "";
if (direction == null)
direction = calculateDirection(databaseHelper);
if (direction.compareTo("DoubleDown") == 0) {
symbol = "\u21ca";
} else if (direction.compareTo("SingleDown") == 0) {
symbol = "\u2193";
} else if (direction.compareTo("FortyFiveDown") == 0) {
symbol = "\u2198";
} else if (direction.compareTo("Flat") == 0) {
symbol = "\u2192";
} else if (direction.compareTo("FortyFiveUp") == 0) {
symbol = "\u2197";
} else if (direction.compareTo("SingleUp") == 0) {
symbol = "\u2191";
} else if (direction.compareTo("DoubleUp") == 0) {
symbol = "\u21c8";
} else if (isSlopeNameInvalid(direction)) {
symbol = "??";
}
return symbol;
}
public int directionToIcon(DatabaseHelperInterface databaseHelper) {
int symbol = 0;
if (direction == null)
direction = calculateDirection(databaseHelper);
if (direction.compareTo("DoubleDown") == 0) {
symbol = R.drawable.ic_doubledown;
} else if (direction.compareTo("SingleDown") == 0) {
symbol = R.drawable.ic_singledown;
} else if (direction.compareTo("FortyFiveDown") == 0) {
symbol = R.drawable.ic_fortyfivedown;;
} else if (direction.compareTo("Flat") == 0) {
symbol = R.drawable.ic_flat;;
} else if (direction.compareTo("FortyFiveUp") == 0) {
symbol = R.drawable.ic_fortyfiveup;
} else if (direction.compareTo("SingleUp") == 0) {
symbol = R.drawable.ic_singleup;
} else if (direction.compareTo("DoubleUp") == 0) {
symbol = R.drawable.ic_doubleup;
} else if (isSlopeNameInvalid(direction)) {
symbol = R.drawable.ic_invalid;
}
return symbol;
}
private static boolean isSlopeNameInvalid(String direction) {
return direction.compareTo("NOT_COMPUTABLE") == 0 ||
direction.compareTo("NOT COMPUTABLE") == 0 ||
direction.compareTo("OUT_OF_RANGE") == 0 ||
direction.compareTo("OUT OF RANGE") == 0 ||
direction.compareTo("NONE") == 0 ||
direction.compareTo("NotComputable") == 0;
}
@NonNull @Override
public String toString() {
return "BgReading{" +
"date=" + date +
", date=" + dateUtil.dateAndTimeString(date) +
", value=" + value +
", direction=" + direction +
", raw=" + raw +
'}';
}
public boolean isDataChanging(BgReading other) {
if (date != other.date) {
aapsLogger.debug(LTag.GLUCOSE, "Comparing different");
return false;
}
if (value != other.value)
return true;
return false;
}
public boolean isEqual(BgReading other) {
if (date != other.date) {
aapsLogger.debug(LTag.GLUCOSE, "Comparing different");
return false;
}
if (value != other.value)
return false;
if (raw != other.raw)
return false;
if (!Objects.equals(direction, other.direction))
return false;
if (!Objects.equals(_id, other._id))
return false;
return true;
}
public void copyFrom(BgReading other) {
if (date != other.date) {
aapsLogger.error(LTag.GLUCOSE, "Copying different");
return;
}
value = other.value;
raw = other.raw;
direction = other.direction;
_id = other._id;
}
public BgReading date(long date) {
this.date = date;
return this;
}
public BgReading date(Date date) {
this.date = date.getTime();
return this;
}
public BgReading value(double value) {
this.value = value;
return this;
}
// ------------------ DataPointWithLabelInterface ------------------
@Override
public double getX() {
return date;
}
@Override
public double getY() {
return valueToUnits(profileFunction.getUnits());
}
@Override
public void setY(double y) {
}
@Override
public String getLabel() {
return null;
}
@Override
public long getDuration() {
return 0;
}
@Override
public PointsWithLabelGraphSeries.Shape getShape() {
if (isPrediction())
return PointsWithLabelGraphSeries.Shape.PREDICTION;
else
return PointsWithLabelGraphSeries.Shape.BG;
}
@Override
public float getSize() {
return 1;
}
@Override
public int getColor() {
String units = profileFunction.getUnits();
Double lowLine = defaultValueHelper.determineLowLine();
Double highLine = defaultValueHelper.determineHighLine();
int color = resourceHelper.gc(R.color.inrange);
if (isPrediction())
return getPredectionColor();
else if (valueToUnits(units) < lowLine)
color = resourceHelper.gc(R.color.low);
else if (valueToUnits(units) > highLine)
color = resourceHelper.gc(R.color.high);
return color;
}
public int getPredectionColor() {
if (isIOBPrediction)
return resourceHelper.gc(R.color.iob);
if (isCOBPrediction)
return resourceHelper.gc(R.color.cob);
if (isaCOBPrediction)
return 0x80FFFFFF & resourceHelper.gc(R.color.cob);
if (isUAMPrediction)
return resourceHelper.gc(R.color.uam);
if (isZTPrediction)
return resourceHelper.gc(R.color.zt);
return R.color.white;
}
private boolean isPrediction() {
return isaCOBPrediction || isCOBPrediction || isIOBPrediction || isUAMPrediction || isZTPrediction;
}
// Copied from xDrip+
String calculateDirection(DatabaseHelperInterface databasehelper) {
// Rework to get bgreaings from internal DB and calculate on that base
List<BgReading> bgReadingsList = databasehelper.getAllBgreadingsDataFromTime(this.date - T.mins(10).msecs(), false);
if (bgReadingsList == null || bgReadingsList.size() < 2)
return "NONE";
BgReading current = bgReadingsList.get(1);
BgReading previous = bgReadingsList.get(0);
if (bgReadingsList.get(1).date < bgReadingsList.get(0).date) {
current = bgReadingsList.get(0);
previous = bgReadingsList.get(1);
}
double slope;
// Avoid division by 0
if (current.date == previous.date)
slope = 0;
else
slope = (previous.value - current.value) / (previous.date - current.date);
aapsLogger.error(LTag.GLUCOSE, "Slope is :" + slope + " delta " + (previous.value - current.value) + " date difference " + (current.date - previous.date));
double slope_by_minute = slope * 60000;
String arrow = "NONE";
if (slope_by_minute <= (-3.5)) {
arrow = "DoubleDown";
} else if (slope_by_minute <= (-2)) {
arrow = "SingleDown";
} else if (slope_by_minute <= (-1)) {
arrow = "FortyFiveDown";
} else if (slope_by_minute <= (1)) {
arrow = "Flat";
} else if (slope_by_minute <= (2)) {
arrow = "FortyFiveUp";
} else if (slope_by_minute <= (3.5)) {
arrow = "SingleUp";
} else if (slope_by_minute <= (40)) {
arrow = "DoubleUp";
}
aapsLogger.error(LTag.GLUCOSE, "Direction set to: " + arrow);
return arrow;
}
}

View file

@ -5,7 +5,6 @@ import info.nightscout.androidaps.db.*
interface DatabaseHelperInterface { interface DatabaseHelperInterface {
fun getAllBgreadingsDataFromTime(mills: Long, ascending: Boolean): List<BgReading>
fun createOrUpdate(careportalEvent: CareportalEvent) fun createOrUpdate(careportalEvent: CareportalEvent)
fun createOrUpdate(record: DanaRHistoryRecord) fun createOrUpdate(record: DanaRHistoryRecord)
fun createOrUpdate(record: OmnipodHistoryRecord) fun createOrUpdate(record: OmnipodHistoryRecord)

View file

@ -1,436 +0,0 @@
package info.nightscout.androidaps.plugins.aps.loop;
import android.text.Spanned;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.core.R;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.Constraint;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.HtmlHelper;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
/**
* Created by mike on 09.06.2016.
*/
public class APSResult {
@Inject HasAndroidInjector injector;
@Inject public AAPSLogger aapsLogger;
@Inject ConstraintChecker constraintChecker;
@Inject SP sp;
@Inject ActivePluginProvider activePlugin;
@Inject TreatmentsInterface treatmentsPlugin;
@Inject ProfileFunction profileFunction;
@Inject ResourceHelper resourceHelper;
@Inject
public APSResult(HasAndroidInjector injector) {
injector.androidInjector().inject(this);
}
public long date = 0;
public String reason;
public double rate;
public int percent;
public boolean usePercent = false;
public int duration;
public boolean tempBasalRequested = false;
public boolean bolusRequested = false;
public IobTotal iob;
public JSONObject json = new JSONObject();
public boolean hasPredictions = false;
public double smb = 0d; // super micro bolus in units
public long deliverAt = 0;
public double targetBG = 0d;
public int carbsReq = 0;
public int carbsReqWithin = 0;
public Constraint<Double> inputConstraints;
public Constraint<Double> rateConstraint;
public Constraint<Integer> percentConstraint;
public Constraint<Double> smbConstraint;
public APSResult rate(double rate) {
this.rate = rate;
return this;
}
public APSResult duration(int duration) {
this.duration = duration;
return this;
}
public APSResult percent(int percent) {
this.percent = percent;
return this;
}
public APSResult tempBasalRequested(boolean tempBasalRequested) {
this.tempBasalRequested = tempBasalRequested;
return this;
}
public APSResult usePercent(boolean usePercent) {
this.usePercent = usePercent;
return this;
}
public APSResult json(JSONObject json) {
this.json = json;
return this;
}
public String getCarbsRequiredText() {
return String.format(resourceHelper.gs(R.string.carbsreq), carbsReq, carbsReqWithin);
}
@Override
public String toString() {
final PumpInterface pump = activePlugin.getActivePump();
if (isChangeRequested()) {
String ret;
// rate
if (rate == 0 && duration == 0)
ret = resourceHelper.gs(R.string.canceltemp) + "\n";
else if (rate == -1)
ret = resourceHelper.gs(R.string.let_temp_basal_run) + "\n";
else if (usePercent)
ret = resourceHelper.gs(R.string.rate) + ": " + DecimalFormatter.to2Decimal(percent) + "% " +
"(" + DecimalFormatter.to2Decimal(percent * pump.getBaseBasalRate() / 100d) + " U/h)\n" +
resourceHelper.gs(R.string.duration) + ": " + DecimalFormatter.to2Decimal(duration) + " min\n";
else
ret = resourceHelper.gs(R.string.rate) + ": " + DecimalFormatter.to2Decimal(rate) + " U/h " +
"(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100) + "%) \n" +
resourceHelper.gs(R.string.duration) + ": " + DecimalFormatter.to2Decimal(duration) + " min\n";
// smb
if (smb != 0)
ret += ("SMB: " + DecimalFormatter.toPumpSupportedBolus(smb, activePlugin.getActivePump(), resourceHelper) + "\n");
if (isCarbsRequired()) {
ret += getCarbsRequiredText()+"\n";
}
// reason
ret += resourceHelper.gs(R.string.reason) + ": " + reason;
return ret;
}
if (isCarbsRequired()) {
return getCarbsRequiredText();
}
return resourceHelper.gs(R.string.nochangerequested);
}
public Spanned toSpanned() {
final PumpInterface pump = activePlugin.getActivePump();
if (isChangeRequested()) {
String ret;
// rate
if (rate == 0 && duration == 0)
ret = resourceHelper.gs(R.string.canceltemp) + "<br>";
else if (rate == -1)
ret = resourceHelper.gs(R.string.let_temp_basal_run) + "<br>";
else if (usePercent)
ret = "<b>" + resourceHelper.gs(R.string.rate) + "</b>: " + DecimalFormatter.to2Decimal(percent) + "% " +
"(" + DecimalFormatter.to2Decimal(percent * pump.getBaseBasalRate() / 100d) + " U/h)<br>" +
"<b>" + resourceHelper.gs(R.string.duration) + "</b>: " + DecimalFormatter.to2Decimal(duration) + " min<br>";
else
ret = "<b>" + resourceHelper.gs(R.string.rate) + "</b>: " + DecimalFormatter.to2Decimal(rate) + " U/h " +
"(" + DecimalFormatter.to2Decimal(rate / pump.getBaseBasalRate() * 100d) + "%) <br>" +
"<b>" + resourceHelper.gs(R.string.duration) + "</b>: " + DecimalFormatter.to2Decimal(duration) + " min<br>";
// smb
if (smb != 0)
ret += ("<b>" + "SMB" + "</b>: " + DecimalFormatter.toPumpSupportedBolus(smb, activePlugin.getActivePump(), resourceHelper) + "<br>");
if (isCarbsRequired()) {
ret += getCarbsRequiredText()+"<br>";
}
// reason
ret += "<b>" + resourceHelper.gs(R.string.reason) + "</b>: " + reason.replace("<", "&lt;").replace(">", "&gt;");
return HtmlHelper.INSTANCE.fromHtml(ret);
}
if (isCarbsRequired()) {
return HtmlHelper.INSTANCE.fromHtml(getCarbsRequiredText());
}
return HtmlHelper.INSTANCE.fromHtml(resourceHelper.gs(R.string.nochangerequested));
}
public APSResult newAndClone(HasAndroidInjector injector) {
APSResult newResult = new APSResult(injector);
doClone(newResult);
return newResult;
}
protected void doClone(APSResult newResult) {
newResult.date = date;
newResult.reason = reason != null ? reason : null;
newResult.rate = rate;
newResult.duration = duration;
newResult.tempBasalRequested = tempBasalRequested;
newResult.bolusRequested = bolusRequested;
newResult.iob = iob;
try {
newResult.json = new JSONObject(json.toString());
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
newResult.hasPredictions = hasPredictions;
newResult.smb = smb;
newResult.deliverAt = deliverAt;
newResult.rateConstraint = rateConstraint;
newResult.smbConstraint = smbConstraint;
newResult.percent = percent;
newResult.usePercent = usePercent;
newResult.carbsReq = carbsReq;
newResult.carbsReqWithin = carbsReqWithin;
newResult.targetBG = targetBG;
}
public JSONObject json() {
JSONObject json = new JSONObject();
try {
if (isChangeRequested()) {
json.put("rate", rate);
json.put("duration", duration);
json.put("reason", reason);
}
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
return json;
}
public List<BgReading> getPredictions() {
List<BgReading> array = new ArrayList<>();
try {
long startTime = date;
if (json != null && json.has("predBGs")) {
JSONObject predBGs = json.getJSONObject("predBGs");
if (predBGs.has("IOB")) {
JSONArray iob = predBGs.getJSONArray("IOB");
for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isIOBPrediction = true;
array.add(bg);
}
}
if (predBGs.has("aCOB")) {
JSONArray iob = predBGs.getJSONArray("aCOB");
for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isaCOBPrediction = true;
array.add(bg);
}
}
if (predBGs.has("COB")) {
JSONArray iob = predBGs.getJSONArray("COB");
for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isCOBPrediction = true;
array.add(bg);
}
}
if (predBGs.has("UAM")) {
JSONArray iob = predBGs.getJSONArray("UAM");
for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isUAMPrediction = true;
array.add(bg);
}
}
if (predBGs.has("ZT")) {
JSONArray iob = predBGs.getJSONArray("ZT");
for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading();
bg.value = iob.getInt(i);
bg.date = startTime + i * 5 * 60 * 1000L;
bg.isZTPrediction = true;
array.add(bg);
}
}
}
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
return array;
}
public long getLatestPredictionsTime() {
long latest = 0;
try {
long startTime = date;
if (json != null && json.has("predBGs")) {
JSONObject predBGs = json.getJSONObject("predBGs");
if (predBGs.has("IOB")) {
JSONArray iob = predBGs.getJSONArray("IOB");
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
}
if (predBGs.has("aCOB")) {
JSONArray iob = predBGs.getJSONArray("aCOB");
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
}
if (predBGs.has("COB")) {
JSONArray iob = predBGs.getJSONArray("COB");
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
}
if (predBGs.has("UAM")) {
JSONArray iob = predBGs.getJSONArray("UAM");
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
}
if (predBGs.has("ZT")) {
JSONArray iob = predBGs.getJSONArray("ZT");
latest = Math.max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L);
}
}
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
return latest;
}
public boolean isCarbsRequired() {
return carbsReq > 0;
}
public boolean isChangeRequested() {
Constraint<Boolean> closedLoopEnabled = constraintChecker.isClosedLoopAllowed();
// closed loop mode: handle change at driver level
if (closedLoopEnabled.value()) {
aapsLogger.debug(LTag.APS, "DEFAULT: Closed mode");
return tempBasalRequested || bolusRequested;
}
// open loop mode: try to limit request
if (!tempBasalRequested && !bolusRequested) {
aapsLogger.debug(LTag.APS, "FALSE: No request");
return false;
}
long now = System.currentTimeMillis();
TemporaryBasal activeTemp = treatmentsPlugin.getTempBasalFromHistory(now);
PumpInterface pump = activePlugin.getActivePump();
Profile profile = profileFunction.getProfile();
if (profile == null) {
aapsLogger.error("FALSE: No Profile");
return false;
}
if (usePercent) {
if (activeTemp == null && percent == 100) {
aapsLogger.debug(LTag.APS, "FALSE: No temp running, asking cancel temp");
return false;
}
if (activeTemp != null && Math.abs(percent - activeTemp.tempBasalConvertedToPercent(now, profile)) < pump.getPumpDescription().basalStep) {
aapsLogger.debug(LTag.APS, "FALSE: Temp equal");
return false;
}
// always report zerotemp
if (percent == 0) {
aapsLogger.debug(LTag.APS, "TRUE: Zero temp");
return true;
}
// always report hightemp
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT) {
double pumpLimit = pump.getPumpDescription().pumpType.getTbrSettings().getMaxDose();
if (percent == pumpLimit) {
aapsLogger.debug(LTag.APS, "TRUE: Pump limit");
return true;
}
}
// report change bigger than 30%
double percentMinChangeChange = sp.getDouble(R.string.key_loop_openmode_min_change, 30d);
percentMinChangeChange /= 100d;
double lowThreshold = 1 - percentMinChangeChange;
double highThreshold = 1 + percentMinChangeChange;
double change = percent / 100d;
if (activeTemp != null)
change = percent / (double) activeTemp.tempBasalConvertedToPercent(now, profile);
if (change < lowThreshold || change > highThreshold) {
aapsLogger.debug(LTag.APS, "TRUE: Outside allowed range " + (change * 100d) + "%");
return true;
} else {
aapsLogger.debug(LTag.APS, "TRUE: Inside allowed range " + (change * 100d) + "%");
return false;
}
} else {
if (activeTemp == null && rate == pump.getBaseBasalRate()) {
aapsLogger.debug(LTag.APS, "FALSE: No temp running, asking cancel temp");
return false;
}
if (activeTemp != null && Math.abs(rate - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.getPumpDescription().basalStep) {
aapsLogger.debug(LTag.APS, "FALSE: Temp equal");
return false;
}
// always report zerotemp
if (rate == 0) {
aapsLogger.debug(LTag.APS, "TRUE: Zero temp");
return true;
}
// always report hightemp
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.ABSOLUTE) {
double pumpLimit = pump.getPumpDescription().pumpType.getTbrSettings().getMaxDose();
if (rate == pumpLimit) {
aapsLogger.debug(LTag.APS, "TRUE: Pump limit");
return true;
}
}
// report change bigger than 30%
double percentMinChangeChange = sp.getDouble(R.string.key_loop_openmode_min_change, 30d);
percentMinChangeChange /= 100d;
double lowThreshold = 1 - percentMinChangeChange;
double highThreshold = 1 + percentMinChangeChange;
double change = rate / profile.getBasal();
if (activeTemp != null)
change = rate / activeTemp.tempBasalConvertedToAbsolute(now, profile);
if (change < lowThreshold || change > highThreshold) {
aapsLogger.debug(LTag.APS, "TRUE: Outside allowed range " + (change * 100d) + "%");
return true;
} else {
aapsLogger.debug(LTag.APS, "TRUE: Inside allowed range " + (change * 100d) + "%");
return false;
}
}
}
}

View file

@ -0,0 +1,399 @@
package info.nightscout.androidaps.plugins.aps.loop
import android.text.Spanned
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.data.GlucoseValueDataPoint
import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.PumpDescription
import info.nightscout.androidaps.interfaces.TreatmentsInterface
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.HtmlHelper.fromHtml
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject
import java.util.*
import javax.inject.Inject
import kotlin.math.abs
import kotlin.math.max
/**
* Created by mike on 09.06.2016.
*/
open class APSResult @Inject constructor(val injector: HasAndroidInjector) {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var sp: SP
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var treatmentsPlugin: TreatmentsInterface
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var resourceHelper: ResourceHelper
var date: Long = 0
var reason: String? = null
var rate = 0.0
var percent = 0
var usePercent = false
var duration = 0
var tempBasalRequested = false
var bolusRequested = false
var iob: IobTotal? = null
var json: JSONObject? = JSONObject()
var hasPredictions = false
var smb = 0.0 // super micro bolus in units
var deliverAt: Long = 0
var targetBG = 0.0
var carbsReq = 0
var carbsReqWithin = 0
var inputConstraints: Constraint<Double>? = null
var rateConstraint: Constraint<Double>? = null
var percentConstraint: Constraint<Int>? = null
var smbConstraint: Constraint<Double>? = null
init {
injector.androidInjector().inject(this)
}
fun rate(rate: Double): APSResult {
this.rate = rate
return this
}
fun duration(duration: Int): APSResult {
this.duration = duration
return this
}
fun percent(percent: Int): APSResult {
this.percent = percent
return this
}
fun tempBasalRequested(tempBasalRequested: Boolean): APSResult {
this.tempBasalRequested = tempBasalRequested
return this
}
fun usePercent(usePercent: Boolean): APSResult {
this.usePercent = usePercent
return this
}
fun json(json: JSONObject?): APSResult {
this.json = json
return this
}
val carbsRequiredText: String
get() = String.format(resourceHelper.gs(R.string.carbsreq), carbsReq, carbsReqWithin)
override fun toString(): String {
val pump = activePlugin.activePump
if (isChangeRequested) {
// rate
var ret: String = if (rate == 0.0 && duration == 0) "${resourceHelper.gs(R.string.canceltemp)}\n"
else if (rate == -1.0) "${resourceHelper.gs(R.string.let_temp_basal_run)}\n"
else if (usePercent) "${resourceHelper.gs(R.string.rate)}: ${DecimalFormatter.to2Decimal(percent.toDouble())}% (${DecimalFormatter.to2Decimal(percent * pump.baseBasalRate / 100.0)} U/h)\n" +
"${resourceHelper.gs(R.string.duration)}: ${DecimalFormatter.to2Decimal(duration.toDouble())} min\n"
else "${resourceHelper.gs(R.string.rate)}: ${DecimalFormatter.to2Decimal(rate)} U/h (${DecimalFormatter.to2Decimal(rate / pump.baseBasalRate * 100)}%)" +
"${resourceHelper.gs(R.string.duration)}: ${DecimalFormatter.to2Decimal(duration.toDouble())} min\n"
// smb
if (smb != 0.0) ret += "SMB: ${DecimalFormatter.toPumpSupportedBolus(smb, activePlugin.activePump, resourceHelper)}\n"
if (isCarbsRequired) {
ret += "$carbsRequiredText\n"
}
// reason
ret += resourceHelper.gs(R.string.reason) + ": " + reason
return ret
}
return if (isCarbsRequired) {
carbsRequiredText
} else resourceHelper.gs(R.string.nochangerequested)
}
fun toSpanned(): Spanned {
val pump = activePlugin.activePump
if (isChangeRequested) {
// rate
var ret: String = if (rate == 0.0 && duration == 0) resourceHelper.gs(R.string.canceltemp) + "<br>" else if (rate == -1.0) resourceHelper.gs(R.string.let_temp_basal_run) + "<br>" else if (usePercent) "<b>" + resourceHelper.gs(R.string.rate) + "</b>: " + DecimalFormatter.to2Decimal(percent.toDouble()) + "% " +
"(" + DecimalFormatter.to2Decimal(percent * pump.baseBasalRate / 100.0) + " U/h)<br>" +
"<b>" + resourceHelper.gs(R.string.duration) + "</b>: " + DecimalFormatter.to2Decimal(duration.toDouble()) + " min<br>" else "<b>" + resourceHelper.gs(R.string.rate) + "</b>: " + DecimalFormatter.to2Decimal(rate) + " U/h " +
"(" + DecimalFormatter.to2Decimal(rate / pump.baseBasalRate * 100.0) + "%) <br>" +
"<b>" + resourceHelper.gs(R.string.duration) + "</b>: " + DecimalFormatter.to2Decimal(duration.toDouble()) + " min<br>"
// smb
if (smb != 0.0) ret += "<b>" + "SMB" + "</b>: " + DecimalFormatter.toPumpSupportedBolus(smb, activePlugin.activePump, resourceHelper) + "<br>"
if (isCarbsRequired) {
ret += "$carbsRequiredText<br>"
}
// reason
ret += "<b>" + resourceHelper.gs(R.string.reason) + "</b>: " + reason!!.replace("<", "&lt;").replace(">", "&gt;")
return fromHtml(ret)
}
return if (isCarbsRequired) {
fromHtml(carbsRequiredText)
} else fromHtml(resourceHelper.gs(R.string.nochangerequested))
}
open fun newAndClone(injector: HasAndroidInjector): APSResult {
val newResult = APSResult(injector)
doClone(newResult)
return newResult
}
protected fun doClone(newResult: APSResult) {
newResult.date = date
newResult.reason = if (reason != null) reason else null
newResult.rate = rate
newResult.duration = duration
newResult.tempBasalRequested = tempBasalRequested
newResult.bolusRequested = bolusRequested
newResult.iob = iob
newResult.json = JSONObject(json.toString())
newResult.hasPredictions = hasPredictions
newResult.smb = smb
newResult.deliverAt = deliverAt
newResult.rateConstraint = rateConstraint
newResult.smbConstraint = smbConstraint
newResult.percent = percent
newResult.usePercent = usePercent
newResult.carbsReq = carbsReq
newResult.carbsReqWithin = carbsReqWithin
newResult.targetBG = targetBG
}
open fun json(): JSONObject? {
val json = JSONObject()
if (isChangeRequested) {
json.put("rate", rate)
json.put("duration", duration)
json.put("reason", reason)
}
return json
}
val predictions: MutableList<GlucoseValueDataPoint>
get() {
val array: MutableList<GlucoseValueDataPoint> = ArrayList()
val startTime = date
json?.let { json ->
if (json.has("predBGs")) {
val predBGs = json.getJSONObject("predBGs")
if (predBGs.has("IOB")) {
val iob = predBGs.getJSONArray("IOB")
for (i in 1 until iob.length()) {
val gv = GlucoseValue(
raw = 0.0,
noise = 0.0,
value = iob.getInt(i).toDouble(),
timestamp = startTime + i * 5 * 60 * 1000L,
sourceSensor = GlucoseValue.SourceSensor.IOB_PREDICTION,
trendArrow = GlucoseValue.TrendArrow.NONE
)
array.add(GlucoseValueDataPoint(injector, gv))
}
}
if (predBGs.has("aCOB")) {
val iob = predBGs.getJSONArray("aCOB")
for (i in 1 until iob.length()) {
val gv = GlucoseValue(
raw = 0.0,
noise = 0.0,
value = iob.getInt(i).toDouble(),
timestamp = startTime + i * 5 * 60 * 1000L,
sourceSensor = GlucoseValue.SourceSensor.aCOB_PREDICTION,
trendArrow = GlucoseValue.TrendArrow.NONE
)
array.add(GlucoseValueDataPoint(injector, gv))
}
}
if (predBGs.has("COB")) {
val iob = predBGs.getJSONArray("COB")
for (i in 1 until iob.length()) {
val gv = GlucoseValue(
raw = 0.0,
noise = 0.0,
value = iob.getInt(i).toDouble(),
timestamp = startTime + i * 5 * 60 * 1000L,
sourceSensor = GlucoseValue.SourceSensor.COB_PREDICTION,
trendArrow = GlucoseValue.TrendArrow.NONE
)
array.add(GlucoseValueDataPoint(injector, gv))
}
}
if (predBGs.has("UAM")) {
val iob = predBGs.getJSONArray("UAM")
for (i in 1 until iob.length()) {
val gv = GlucoseValue(
raw = 0.0,
noise = 0.0,
value = iob.getInt(i).toDouble(),
timestamp = startTime + i * 5 * 60 * 1000L,
sourceSensor = GlucoseValue.SourceSensor.UAM_PREDICTION,
trendArrow = GlucoseValue.TrendArrow.NONE
)
array.add(GlucoseValueDataPoint(injector, gv))
}
}
if (predBGs.has("ZT")) {
val iob = predBGs.getJSONArray("ZT")
for (i in 1 until iob.length()) {
val gv = GlucoseValue(
raw = 0.0,
noise = 0.0,
value = iob.getInt(i).toDouble(),
timestamp = startTime + i * 5 * 60 * 1000L,
sourceSensor = GlucoseValue.SourceSensor.ZT_PREDICTION,
trendArrow = GlucoseValue.TrendArrow.NONE
)
array.add(GlucoseValueDataPoint(injector, gv))
}
}
}
}
return array
}
val latestPredictionsTime: Long
get() {
var latest: Long = 0
try {
val startTime = date
if (json != null && json!!.has("predBGs")) {
val predBGs = json!!.getJSONObject("predBGs")
if (predBGs.has("IOB")) {
val iob = predBGs.getJSONArray("IOB")
latest = max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L)
}
if (predBGs.has("aCOB")) {
val iob = predBGs.getJSONArray("aCOB")
latest = max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L)
}
if (predBGs.has("COB")) {
val iob = predBGs.getJSONArray("COB")
latest = max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L)
}
if (predBGs.has("UAM")) {
val iob = predBGs.getJSONArray("UAM")
latest = max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L)
}
if (predBGs.has("ZT")) {
val iob = predBGs.getJSONArray("ZT")
latest = max(latest, startTime + (iob.length() - 1) * 5 * 60 * 1000L)
}
}
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)
}
return latest
}
val isCarbsRequired: Boolean
get() = carbsReq > 0
val isChangeRequested: Boolean
get() {
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
// closed loop mode: handle change at driver level
if (closedLoopEnabled.value()) {
aapsLogger.debug(LTag.APS, "DEFAULT: Closed mode")
return tempBasalRequested || bolusRequested
}
// open loop mode: try to limit request
if (!tempBasalRequested && !bolusRequested) {
aapsLogger.debug(LTag.APS, "FALSE: No request")
return false
}
val now = System.currentTimeMillis()
val activeTemp = treatmentsPlugin.getTempBasalFromHistory(now)
val pump = activePlugin.activePump
val profile = profileFunction.getProfile()
if (profile == null) {
aapsLogger.error("FALSE: No Profile")
return false
}
return if (usePercent) {
if (activeTemp == null && percent == 100) {
aapsLogger.debug(LTag.APS, "FALSE: No temp running, asking cancel temp")
return false
}
if (activeTemp != null && abs(percent - activeTemp.tempBasalConvertedToPercent(now, profile)) < pump.pumpDescription.basalStep) {
aapsLogger.debug(LTag.APS, "FALSE: Temp equal")
return false
}
// always report zerotemp
if (percent == 0) {
aapsLogger.debug(LTag.APS, "TRUE: Zero temp")
return true
}
// always report hightemp
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT) {
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings.maxDose
if (percent.toDouble() == pumpLimit) {
aapsLogger.debug(LTag.APS, "TRUE: Pump limit")
return true
}
}
// report change bigger than 30%
var percentMinChangeChange = sp.getDouble(R.string.key_loop_openmode_min_change, 30.0)
percentMinChangeChange /= 100.0
val lowThreshold = 1 - percentMinChangeChange
val highThreshold = 1 + percentMinChangeChange
var change = percent / 100.0
if (activeTemp != null) change = percent / activeTemp.tempBasalConvertedToPercent(now, profile).toDouble()
if (change < lowThreshold || change > highThreshold) {
aapsLogger.debug(LTag.APS, "TRUE: Outside allowed range " + change * 100.0 + "%")
true
} else {
aapsLogger.debug(LTag.APS, "TRUE: Inside allowed range " + change * 100.0 + "%")
false
}
} else {
if (activeTemp == null && rate == pump.baseBasalRate) {
aapsLogger.debug(LTag.APS, "FALSE: No temp running, asking cancel temp")
return false
}
if (activeTemp != null && abs(rate - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.pumpDescription.basalStep) {
aapsLogger.debug(LTag.APS, "FALSE: Temp equal")
return false
}
// always report zerotemp
if (rate == 0.0) {
aapsLogger.debug(LTag.APS, "TRUE: Zero temp")
return true
}
// always report hightemp
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings.maxDose
if (rate == pumpLimit) {
aapsLogger.debug(LTag.APS, "TRUE: Pump limit")
return true
}
}
// report change bigger than 30%
var percentMinChangeChange = sp.getDouble(R.string.key_loop_openmode_min_change, 30.0)
percentMinChangeChange /= 100.0
val lowThreshold = 1 - percentMinChangeChange
val highThreshold = 1 + percentMinChangeChange
var change = rate / profile.basal
if (activeTemp != null) change = rate / activeTemp.tempBasalConvertedToAbsolute(now, profile)
if (change < lowThreshold || change > highThreshold) {
aapsLogger.debug(LTag.APS, "TRUE: Outside allowed range " + change * 100.0 + "%")
true
} else {
aapsLogger.debug(LTag.APS, "TRUE: Inside allowed range " + change * 100.0 + "%")
false
}
}
}
}

View file

@ -1,22 +1,15 @@
package info.nightscout.androidaps.plugins.general.nsclient; package info.nightscout.androidaps.plugins.general.nsclient;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.os.Build; import android.os.Build;
import android.os.Bundle;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Locale;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -26,7 +19,7 @@ import info.nightscout.androidaps.core.R;
import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.DbRequest; import info.nightscout.androidaps.db.DbRequest;
import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ExtendedBolus;
@ -211,7 +204,7 @@ public class NSUpload {
apsResult.json().put("timestamp", DateUtil.toISOString(lastRun.getLastAPSRun())); apsResult.json().put("timestamp", DateUtil.toISOString(lastRun.getLastAPSRun()));
deviceStatus.suggested = apsResult.json(); deviceStatus.suggested = apsResult.json();
deviceStatus.iob = lastRun.getRequest().iob.json(); deviceStatus.iob = lastRun.getRequest().getIob().json();
deviceStatus.iob.put("time", DateUtil.toISOString(lastRun.getLastAPSRun())); deviceStatus.iob.put("time", DateUtil.toISOString(lastRun.getLastAPSRun()));
JSONObject requested = new JSONObject(); JSONObject requested = new JSONObject();
@ -221,8 +214,8 @@ public class NSUpload {
deviceStatus.enacted.put("rate", lastRun.getTbrSetByPump().json(profile).get("rate")); deviceStatus.enacted.put("rate", lastRun.getTbrSetByPump().json(profile).get("rate"));
deviceStatus.enacted.put("duration", lastRun.getTbrSetByPump().json(profile).get("duration")); deviceStatus.enacted.put("duration", lastRun.getTbrSetByPump().json(profile).get("duration"));
deviceStatus.enacted.put("recieved", true); deviceStatus.enacted.put("recieved", true);
requested.put("duration", lastRun.getRequest().duration); requested.put("duration", lastRun.getRequest().getDuration());
requested.put("rate", lastRun.getRequest().rate); requested.put("rate", lastRun.getRequest().getRate());
requested.put("temp", "absolute"); requested.put("temp", "absolute");
deviceStatus.enacted.put("requested", requested); deviceStatus.enacted.put("requested", requested);
} }
@ -231,7 +224,7 @@ public class NSUpload {
deviceStatus.enacted = lastRun.getRequest().json(); deviceStatus.enacted = lastRun.getRequest().json();
} }
deviceStatus.enacted.put("smb", lastRun.getTbrSetByPump().bolusDelivered); deviceStatus.enacted.put("smb", lastRun.getTbrSetByPump().bolusDelivered);
requested.put("smb", lastRun.getRequest().smb); requested.put("smb", lastRun.getRequest().getSmb());
deviceStatus.enacted.put("requested", requested); deviceStatus.enacted.put("requested", requested);
} }
} else { } else {
@ -402,14 +395,14 @@ public class NSUpload {
uploadQueue.add(new DbRequest("dbAdd", "treatments", data)); uploadQueue.add(new DbRequest("dbAdd", "treatments", data));
} }
public void uploadBg(BgReading reading, String source) { public void uploadBg(GlucoseValue reading, String source) {
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
try { try {
data.put("device", source); data.put("device", source);
data.put("date", reading.date); data.put("date", reading.getTimestamp());
data.put("dateString", DateUtil.toISOString(reading.date)); data.put("dateString", DateUtil.toISOString(reading.getTimestamp()));
data.put("sgv", reading.value); data.put("sgv", reading.getValue());
data.put("direction", reading.direction); data.put("direction", reading.getTrendArrow().getText());
data.put("type", "sgv"); data.put("type", "sgv");
} catch (JSONException e) { } catch (JSONException e) {
aapsLogger.error("Unhandled exception", e); aapsLogger.error("Unhandled exception", e);
@ -417,6 +410,24 @@ public class NSUpload {
uploadQueue.add(new DbRequest("dbAdd", "entries", data)); uploadQueue.add(new DbRequest("dbAdd", "entries", data));
} }
public void updateBg(GlucoseValue reading, String source) {
JSONObject data = new JSONObject();
try {
data.put("device", source);
data.put("date", reading.getTimestamp());
data.put("dateString", DateUtil.toISOString(reading.getTimestamp()));
data.put("sgv", reading.getValue());
data.put("direction", reading.getTrendArrow().getText());
data.put("type", "sgv");
if (reading.getInterfaceIDs() != null)
if (reading.getInterfaceIDs().getNightscoutId() != null) {
uploadQueue.add(new DbRequest("dbUpdate", "entries", reading.getInterfaceIDs().getNightscoutId(), data));
}
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
}
public void uploadAppStart() { public void uploadAppStart() {
if (sp.getBoolean(R.string.key_ns_logappstartedevent, true)) { if (sp.getBoolean(R.string.key_ns_logappstartedevent, true)) {
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
@ -461,46 +472,6 @@ public class NSUpload {
} }
public void sendToXdrip(BgReading bgReading) {
final String XDRIP_PLUS_NS_EMULATOR = "com.eveningoutpost.dexdrip.NS_EMULATOR";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
try {
final JSONArray entriesBody = new JSONArray();
JSONObject json = new JSONObject();
json.put("sgv", bgReading.value);
if (bgReading.direction == null) {
json.put("direction", "NONE");
} else {
json.put("direction", bgReading.direction);
}
json.put("device", "G5");
json.put("type", "sgv");
json.put("date", bgReading.date);
json.put("dateString", format.format(bgReading.date));
entriesBody.put(json);
final Bundle bundle = new Bundle();
bundle.putString("action", "add");
bundle.putString("collection", "entries");
bundle.putString("data", entriesBody.toString());
final Intent intent = new Intent(XDRIP_PLUS_NS_EMULATOR);
intent.putExtras(bundle).addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
List<ResolveInfo> receivers = context.getPackageManager().queryBroadcastReceivers(intent, 0);
if (receivers.size() < 1) {
aapsLogger.debug("No xDrip receivers found. ");
} else {
aapsLogger.debug(receivers.size() + " xDrip receivers");
}
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
}
public void createNSTreatment(JSONObject data, ProfileStore profileStore, ProfileFunction profileFunction, long eventTime) { public void createNSTreatment(JSONObject data, ProfileStore profileStore, ProfileFunction profileFunction, long eventTime) {
if (JsonHelper.safeGetString(data, "eventType", "").equals(CareportalEvent.PROFILESWITCH)) { if (JsonHelper.safeGetString(data, "eventType", "").equals(CareportalEvent.PROFILESWITCH)) {
ProfileSwitch profileSwitch = profileFunction.prepareProfileSwitch( ProfileSwitch profileSwitch = profileFunction.prepareProfileSwitch(

View file

@ -0,0 +1,18 @@
package info.nightscout.androidaps.utils.extensions
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.database.entities.GlucoseValue
fun GlucoseValue.TrendArrow.directionToIcon(): Int {
return when {
this == GlucoseValue.TrendArrow.DOUBLE_DOWN -> R.drawable.ic_doubledown
this == GlucoseValue.TrendArrow.SINGLE_DOWN -> R.drawable.ic_singledown
this == GlucoseValue.TrendArrow.FORTY_FIVE_DOWN -> R.drawable.ic_fortyfivedown
this == GlucoseValue.TrendArrow.FLAT -> R.drawable.ic_flat
this == GlucoseValue.TrendArrow.FORTY_FIVE_UP -> R.drawable.ic_fortyfiveup
this == GlucoseValue.TrendArrow.SINGLE_UP -> R.drawable.ic_singleup
this == GlucoseValue.TrendArrow.DOUBLE_UP -> R.drawable.ic_doubleup
this == GlucoseValue.TrendArrow.NONE -> R.drawable.ic_invalid
else -> R.drawable.ic_invalid
}
}

View file

@ -18,7 +18,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.extensions.plusAssign import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import java.text.DecimalFormat import java.text.DecimalFormat

View file

@ -60,12 +60,12 @@ class AppRepository @Inject internal constructor(
fun clearDatabases() = database.clearAllTables() fun clearDatabases() = database.clearAllTables()
//BG READINGS -- only valid records //BG READINGS -- only valid records
fun compatGetBgReadingsDataFromTime(timestamp: Long, ascending: Boolean) = fun compatGetBgReadingsDataFromTime(timestamp: Long, ascending: Boolean): Single<List<GlucoseValue>> =
database.glucoseValueDao.compatGetBgReadingsDataFromTime(timestamp) database.glucoseValueDao.compatGetBgReadingsDataFromTime(timestamp)
.map { if (!ascending) it.reversed() else it } .map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
fun compatGetBgReadingsDataFromTime(start: Long, end: Long, ascending: Boolean) = fun compatGetBgReadingsDataFromTime(start: Long, end: Long, ascending: Boolean): Single<List<GlucoseValue>> =
database.glucoseValueDao.compatGetBgReadingsDataFromTime(start, end) database.glucoseValueDao.compatGetBgReadingsDataFromTime(start, end)
.map { if (!ascending) it.reversed() else it } .map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
@ -74,23 +74,23 @@ class AppRepository @Inject internal constructor(
fun findBgReadingByNSIdSingle(nsId: String): Single<ValueWrapper<GlucoseValue>> = fun findBgReadingByNSIdSingle(nsId: String): Single<ValueWrapper<GlucoseValue>> =
database.glucoseValueDao.findByNSIdMaybe(nsId).toWrappedSingle() database.glucoseValueDao.findByNSIdMaybe(nsId).toWrappedSingle()
fun getModifiedBgReadingsDataFromId(lastId: Long) = fun getModifiedBgReadingsDataFromId(lastId: Long): Single<List<GlucoseValue>> =
database.glucoseValueDao.getModifiedFrom(lastId) database.glucoseValueDao.getModifiedFrom(lastId)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
fun getBgReadingsCorrespondingLastHistoryRecord(lastId: Long) = fun getBgReadingsCorrespondingLastHistoryRecord(lastId: Long): GlucoseValue? =
database.glucoseValueDao.getLastHistoryRecord(lastId) database.glucoseValueDao.getLastHistoryRecord(lastId)
@Suppress("unused") // debug purpose only @Suppress("unused") // debug purpose only
fun getAllBgReadingsStartingFrom(lastId: Long) = fun getAllBgReadingsStartingFrom(lastId: Long): Single<List<GlucoseValue>> =
database.glucoseValueDao.getAllStartingFrom(lastId) database.glucoseValueDao.getAllStartingFrom(lastId)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
// TEMP TARGETS // TEMP TARGETS
fun compatGetTemporaryTargetData() = fun compatGetTemporaryTargetData(): List<TemporaryTarget> =
database.temporaryTargetDao.compatGetTemporaryTargetData() database.temporaryTargetDao.compatGetTemporaryTargetData()
fun compatGetTemporaryTargetDataFromTime(timestamp: Long, ascending: Boolean) = fun compatGetTemporaryTargetDataFromTime(timestamp: Long, ascending: Boolean): Single<List<TemporaryTarget>> =
database.temporaryTargetDao.compatGetTemporaryTargetDataFromTime(timestamp) database.temporaryTargetDao.compatGetTemporaryTargetDataFromTime(timestamp)
.map { if (!ascending) it.reversed() else it } .map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
@ -98,16 +98,16 @@ class AppRepository @Inject internal constructor(
fun findTemporaryTargetByNSIdSingle(nsId: String): Single<ValueWrapper<TemporaryTarget>> = fun findTemporaryTargetByNSIdSingle(nsId: String): Single<ValueWrapper<TemporaryTarget>> =
database.temporaryTargetDao.findByNSIdMaybe(nsId).toWrappedSingle() database.temporaryTargetDao.findByNSIdMaybe(nsId).toWrappedSingle()
fun getModifiedTemporaryTargetsDataFromId(lastId: Long) = fun getModifiedTemporaryTargetsDataFromId(lastId: Long): Single<List<TemporaryTarget>> =
database.temporaryTargetDao.getModifiedFrom(lastId) database.temporaryTargetDao.getModifiedFrom(lastId)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
fun getTemporaryTargetsCorrespondingLastHistoryRecord(lastId: Long) = fun getTemporaryTargetsCorrespondingLastHistoryRecord(lastId: Long): TemporaryTarget? =
database.temporaryTargetDao.getLastHistoryRecord(lastId) database.temporaryTargetDao.getLastHistoryRecord(lastId)
} }
@Suppress("USELESS_CAST")
inline fun <reified T> Maybe<T>.toWrappedSingle(): Single<ValueWrapper<T>> = inline fun <reified T : Any> Maybe<T>.toWrappedSingle(): Single<ValueWrapper<T>> =
this.map { ValueWrapper.Existing(it) as ValueWrapper<T> } this.map { ValueWrapper.Existing(it) as ValueWrapper<T> }
.switchIfEmpty(Maybe.just(ValueWrapper.Absent())) .switchIfEmpty(Maybe.just(ValueWrapper.Absent()))
.toSingle() .toSingle()

View file

@ -90,11 +90,18 @@ data class GlucoseValue(
@SerializedName("MM600Series") MM_600_SERIES("MM600Series"), @SerializedName("MM600Series") MM_600_SERIES("MM600Series"),
@SerializedName("Eversense") EVERSENSE("Eversense"), @SerializedName("Eversense") EVERSENSE("Eversense"),
@SerializedName("Random") RANDOM("Random"), @SerializedName("Random") RANDOM("Random"),
@SerializedName("Unknown") UNKNOWN("Unknown") @SerializedName("Unknown") UNKNOWN("Unknown"),
@SerializedName("IOBPrediction") IOB_PREDICTION("IOBPrediction"),
@SerializedName("aCOBPrediction") aCOB_PREDICTION("aCOBPrediction"),
@SerializedName("COBPrediction") COB_PREDICTION("COBPrediction"),
@SerializedName("UAMPrediction") UAM_PREDICTION("UAMPrediction"),
@SerializedName("ZTPrediction") ZT_PREDICTION("ZTPrediction")
; ;
companion object { companion object {
fun fromString(source : String?) = values().firstOrNull {it.text == source} ?: UNKNOWN
fun fromString(source: String?) = values().firstOrNull { it.text == source } ?: UNKNOWN
} }
} }
} }

View file

@ -9,11 +9,14 @@ import info.nightscout.androidaps.database.entities.TherapyEvent
class CgmSourceTransaction( class CgmSourceTransaction(
private val glucoseValues: List<TransactionGlucoseValue>, private val glucoseValues: List<TransactionGlucoseValue>,
private val calibrations: List<Calibration>, private val calibrations: List<Calibration>,
private val sensorInsertionTime: Long? private val sensorInsertionTime: Long?,
) : Transaction<List<GlucoseValue>>() { private val syncer: Boolean = false // caller is not native source ie. NS
// syncer is allowed create records
// update synchronization ID
) : Transaction<CgmSourceTransaction.TransactionResult>() {
override fun run(): List<GlucoseValue> { override fun run(): TransactionResult {
val insertedGlucoseValues = mutableListOf<GlucoseValue>() val result = TransactionResult()
glucoseValues.forEach { glucoseValues.forEach {
val current = database.glucoseValueDao.findByTimestampAndSensor(it.timestamp, it.sourceSensor) val current = database.glucoseValueDao.findByTimestampAndSensor(it.timestamp, it.sourceSensor)
val glucoseValue = GlucoseValue( val glucoseValue = GlucoseValue(
@ -25,15 +28,26 @@ class CgmSourceTransaction(
sourceSensor = it.sourceSensor sourceSensor = it.sourceSensor
) )
glucoseValue.interfaceIDs.nightscoutId = it.nightscoutId glucoseValue.interfaceIDs.nightscoutId = it.nightscoutId
// if nsId is not provided in new record, copy from current if exists
if (glucoseValue.interfaceIDs.nightscoutId == null)
current?.let { existing -> glucoseValue.interfaceIDs.nightscoutId = existing.interfaceIDs.nightscoutId }
when { when {
// new record, create new
current == null -> { current == null -> {
database.glucoseValueDao.insertNewEntry(glucoseValue) database.glucoseValueDao.insertNewEntry(glucoseValue)
insertedGlucoseValues.add(glucoseValue) result.inserted.add(glucoseValue)
} }
// different record, update
!current.contentEqualsTo(glucoseValue) -> { !current.contentEqualsTo(glucoseValue) && !syncer -> {
glucoseValue.id = current.id glucoseValue.id = current.id
database.glucoseValueDao.updateExistingEntry(glucoseValue) database.glucoseValueDao.updateExistingEntry(glucoseValue)
result.updated.add(glucoseValue)
}
// update NS id if didn't exist and now provided
current.interfaceIDs.nightscoutId == null && it.nightscoutId != null && syncer -> {
glucoseValue.id = current.id
database.glucoseValueDao.updateExistingEntry(glucoseValue)
result.updated.add(glucoseValue)
} }
} }
} }
@ -54,7 +68,7 @@ class CgmSourceTransaction(
)) ))
} }
} }
return insertedGlucoseValues return result
} }
data class TransactionGlucoseValue( data class TransactionGlucoseValue(
@ -71,4 +85,16 @@ class CgmSourceTransaction(
val timestamp: Long, val timestamp: Long,
val value: Double val value: Double
) )
class TransactionResult {
val inserted = mutableListOf<GlucoseValue>()
val updated = mutableListOf<GlucoseValue>()
fun all(): MutableList<GlucoseValue> =
mutableListOf<GlucoseValue>().also { result ->
result.addAll(inserted)
result.addAll(updated)
}
}
} }