migrate BG code

This commit is contained in:
Milos Kozak 2021-02-06 00:30:27 +01:00
parent cfe23cef96
commit 7763a96d6a
49 changed files with 978 additions and 962 deletions

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);
@ -120,7 +137,7 @@ public class MainApp extends DaggerApplication {
filter.addAction(Intents.ACTION_NEW_TREATMENT); filter.addAction(Intents.ACTION_NEW_TREATMENT);
filter.addAction(Intents.ACTION_CHANGED_TREATMENT); filter.addAction(Intents.ACTION_CHANGED_TREATMENT);
filter.addAction(Intents.ACTION_REMOVED_TREATMENT); filter.addAction(Intents.ACTION_REMOVED_TREATMENT);
filter.addAction(Intents.ACTION_NEW_SGV); //filter.addAction(Intents.ACTION_NEW_SGV);
filter.addAction(Intents.ACTION_NEW_PROFILE); filter.addAction(Intents.ACTION_NEW_PROFILE);
filter.addAction(Intents.ACTION_NEW_MBG); filter.addAction(Intents.ACTION_NEW_MBG);
filter.addAction(Intents.ACTION_NEW_CAL); filter.addAction(Intents.ACTION_NEW_CAL);

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);
@ -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();
@ -384,136 +373,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() { public List<BgReading> getAllBgReadings() {
try { try {
return getDaoBgReadings().queryForAll(); return getDaoBgReadings().queryForAll();
@ -2010,7 +1869,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 +1916,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() {

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

@ -13,6 +13,7 @@ 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
@ -38,6 +39,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 +49,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
@ -332,7 +335,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), BgReading(injector).value(Profile.toMgdl(bg, profileFunction.getUnits())).valueToUnitsToString(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)
); );
} }

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,8 +8,11 @@ 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.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
@ -20,11 +23,12 @@ import javax.inject.Inject
class MaintenanceFragment : DaggerFragment() { class MaintenanceFragment : DaggerFragment() {
@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 repository: AppRepository
private var _binding: MaintenanceFragmentBinding? = null private var _binding: MaintenanceFragmentBinding? = null
@ -49,6 +53,8 @@ class MaintenanceFragment : DaggerFragment() {
// additional service interface and plugin registry // additional service interface and plugin registry
foodPlugin.service?.resetFood() foodPlugin.service?.resetFood()
treatmentsPlugin.service.resetTreatments() treatmentsPlugin.service.resetTreatments()
Thread { repository.clearDatabases() } .start()
rxBus.send(EventNewBG(null))
}) })
} }
} }

View file

@ -16,6 +16,7 @@ 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.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 +57,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)
@ -163,13 +165,13 @@ class OpenHumansUploader @Inject constructor(
fun enqueueBGReading(bgReading: BgReading?) = bgReading?.let { fun enqueueBGReading(bgReading: BgReading?) = bgReading?.let {
insertQueueItem("BgReadings") { insertQueueItem("BgReadings") {
put("date", bgReading.date) put("date", bgReading.data.dateCreated)
put("isValid", bgReading.isValid) put("isValid", bgReading.data.isValid)
put("value", bgReading.value) put("value", bgReading.data.value)
put("direction", bgReading.direction) put("direction", bgReading.data.trendArrow)
put("raw", bgReading.raw) put("raw", bgReading.data.raw)
put("source", bgReading.source) put("source", bgReading.data.sourceSensor)
put("nsId", bgReading._id) put("nsId", bgReading.data.interfaceIDs.nightscoutId)
} }
} }

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

@ -27,6 +27,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.utils.DecimalFormatter import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.convertToBGReadings
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -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
@ -62,7 +63,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<BgReading>?) {
var maxBgValue = Double.MIN_VALUE var maxBgValue = Double.MIN_VALUE
bgReadingsArray = iobCobCalculatorPlugin.bgReadings bgReadingsArray = iobCobCalculatorPlugin.bgReadings?.convertToBGReadings(injector)
if (bgReadingsArray?.isEmpty() != false) { if (bgReadingsArray?.isEmpty() != false) {
aapsLogger.debug("No BG data.") aapsLogger.debug("No BG data.")
maxY = 10.0 maxY = 10.0
@ -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.data.timestamp < fromTime || bg.data.timestamp > toTime) continue
if (bg.value > maxBgValue) maxBgValue = bg.value if (bg.data.value > maxBgValue) maxBgValue = bg.data.value
bgListArray.add(bg) bgListArray.add(bg)
} }
if (predictions != null) { if (predictions != null) {
predictions.sortWith(Comparator { o1: BgReading, o2: BgReading -> o1.x.compareTo(o2.x) }) predictions.sortWith(Comparator { o1: BgReading, o2: BgReading -> 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)
@ -282,10 +283,10 @@ 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.data.timestamp > date) continue
return Profile.fromMgdlToUnits(reading.value, units) return Profile.fromMgdlToUnits(reading.data.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].data.value, units) else Profile.fromMgdlToUnits(100.0, units)
} ?: return Profile.fromMgdlToUnits(100.0, units) } ?: return 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,8 +1,10 @@
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
@ -16,6 +18,7 @@ import info.nightscout.androidaps.plugins.general.tidepool.utils.GsonInstance
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.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.convertToBGReadings
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -24,12 +27,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 +107,11 @@ 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 .convertToBGReadings(injector)
return if (bgReadingList.isNotEmpty())
bgReadingList[0].data.timestamp
else -1 else -1
} }
@ -131,7 +138,9 @@ 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()
.convertToBGReadings(injector)
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

@ -5,7 +5,7 @@ import info.nightscout.androidaps.db.BgReading
import java.util.* import java.util.*
class SensorGlucoseElement(bgReading: BgReading) class SensorGlucoseElement(bgReading: BgReading)
: BaseElement(bgReading.date, UUID.nameUUIDFromBytes(("AAPS-cgm" + bgReading.date).toByteArray()).toString()) { : BaseElement(bgReading.data.timestamp, UUID.nameUUIDFromBytes(("AAPS-cgm" + bgReading.data.timestamp).toByteArray()).toString()) {
@Expose @Expose
internal var units: String = "mg/dL" internal var units: String = "mg/dL"
@ -14,7 +14,7 @@ class SensorGlucoseElement(bgReading: BgReading)
init { init {
this.type = "cbg" this.type = "cbg"
value = bgReading.value.toInt() value = bgReading.data.value.toInt()
} }
companion object { companion object {

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.IobTotal; import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
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);
@ -541,8 +543,8 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
if (!predArray.isEmpty()) { if (!predArray.isEmpty()) {
final String units = profileFunction.getUnits(); final String units = profileFunction.getUnits();
for (BgReading bg : predArray) { for (BgReading bg : predArray) {
if (bg.value < 40) continue; if (bg.getValue() < 40) continue;
predictions.add(predictionMap(bg.date, bg.value, bg.getPredectionColor())); predictions.add(predictionMap(bg.getDate(), bg.getValue(), bg.getPredictionColor()));
} }
} }
} }

View file

@ -8,6 +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.database.entities.GlucoseValue;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
@ -71,7 +72,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 +85,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 +113,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 +132,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 +153,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,6 +10,7 @@ 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;
@ -21,6 +22,8 @@ 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.database.AppRepository;
import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.db.Treatment;
@ -72,6 +75,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 +84,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 +112,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 +136,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 +175,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 +234,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 +279,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 +294,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 +338,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 +370,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.getTimestamp() - older.getTimestamp();
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 +407,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 +440,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 +921,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 +938,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

@ -5,32 +5,28 @@ 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.utils.*
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.FabricPrivacy
import info.nightscout.androidaps.utils.ListDiffCallback
import info.nightscout.androidaps.utils.ListUpdateCallbackHelper
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 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 +37,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 +57,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
@ -93,83 +93,41 @@ class BGSourceFragment : DaggerFragment() {
binding.recyclerview.adapter = null // avoid leaks binding.recyclerview.adapter = null // avoid leaks
} }
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,36 @@ 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.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source
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 +50,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 +64,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 +84,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 +96,52 @@ 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) {
val jsonObject = JSONObject()
jsonObject.put("enteredBy", "AndroidAPS-Dexcom$sensorType")
jsonObject.put("created_at", DateUtil.toISOString(sensorInsertionTime))
jsonObject.put("eventType", CareportalEvent.SENSORCHANGE)
val careportalEvent = CareportalEvent(injector)
careportalEvent.date = sensorInsertionTime
careportalEvent.source = Source.USER
careportalEvent.eventType = CareportalEvent.SENSORCHANGE
careportalEvent.json = jsonObject.toString()
MainApp.getDbHelper().createOrUpdate(careportalEvent)
nsUpload.uploadCareportalEntryToNS(jsonObject)
}
} }
dexcomPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, calibrations, sensorStartTime)).subscribe({ savedValues ->
savedValues.forEach {
broadcastToXDrip(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false))
nsUpload.uploadBg(BgReading(injector, it), sourceSensor.text)
} }
}, {
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 +157,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,6 +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.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.db.CareportalEvent import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
@ -18,8 +21,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 +50,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 +89,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 +101,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 +109,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.forEach {
} broadcastToXDrip(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false))
nsUpload.uploadBg(BgReading(injector, 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,8 +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.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
@ -13,7 +15,12 @@ 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 +39,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 +67,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.forEach {
broadcastToXDrip(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false))
nsUpload.uploadBg(BgReading(injector, 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,8 +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.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
@ -13,7 +15,14 @@ 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 +42,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 +56,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 +77,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.forEach {
broadcastToXDrip(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false))
nsUpload.uploadBg(BgReading(injector, 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,53 @@ 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
init { init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this) (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
} }
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),
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(PluginType.BGSOURCE) && !sp.getBoolean(R.string.key_ns_autobackfill, true)) 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)).subscribe({ savedValues ->
savedValues.forEach {
broadcastToXDrip(it)
nsClientSourcePlugin.detectSource(it)
} }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Eversense 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,8 +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.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
@ -16,8 +18,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 +43,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 +72,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.forEach {
broadcastToXDrip(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false))
nsUpload.uploadBg(BgReading(injector, 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,8 +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.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
@ -16,10 +18,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 +39,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 +69,8 @@ class RandomBgPlugin @Inject constructor(
} }
} }
private val disposable = CompositeDisposable()
override fun advancedFilteringSupported(): Boolean { override fun advancedFilteringSupported(): Boolean {
return true return true
} }
@ -68,6 +78,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 +99,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.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(BgReading(injector, 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,8 +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.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.interfaces.BgSourceInterface import info.nightscout.androidaps.interfaces.BgSourceInterface
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
@ -14,8 +16,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 +40,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 +67,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.forEach {
broadcastToXDrip(it)
if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false))
nsUpload.uploadBg(BgReading(injector, 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.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,18 @@
package info.nightscout.androidaps.utils
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.db.BgReading
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)
fun GlucoseValue.convertToBGReading(injector: HasAndroidInjector): BgReading = BgReading(injector, this)
fun List<GlucoseValue>.convertToBGReadings(injector: HasAndroidInjector): List<BgReading> = map { it.convertToBGReading(injector) }

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

@ -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

@ -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

@ -0,0 +1,171 @@
package info.nightscout.androidaps.db
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries
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
import javax.inject.Inject
class BgReading : DataPointWithLabelInterface {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var repository: AppRepository
var data: GlucoseValue
// Compatibility functions
fun setDate(timeStamp: Long) {
data.timestamp = timeStamp
}
fun getDate(): Long = data.timestamp
fun getValue(): Double = data.value
fun setValue(value: Double) {
data.value = value
}
var isCOBPrediction = false // true when drawing predictions as bg points (COB)
var isaCOBPrediction = false // true when drawing predictions as bg points (aCOB)
var isIOBPrediction = false // true when drawing predictions as bg points (IOB)
var isUAMPrediction = false // true when drawing predictions as bg points (UAM)
var isZTPrediction = false // true when drawing predictions as bg points (ZT)
@Deprecated("Create only with data")
constructor(injector: HasAndroidInjector) {
injector.androidInjector().inject(this)
data = GlucoseValue(
timestamp = 0,
utcOffset = 0,
raw = null,
value = 0.0,
trendArrow = GlucoseValue.TrendArrow.NONE,
noise = null,
sourceSensor = GlucoseValue.SourceSensor.UNKNOWN
)
}
constructor(injector: HasAndroidInjector, glucoseValue: GlucoseValue) {
injector.androidInjector().inject(this)
data = glucoseValue
}
fun valueToUnits(units: String): Double =
if (units == Constants.MGDL) data.value else data.value * Constants.MGDL_TO_MMOLL
fun valueToUnitsToString(units: String): String =
if (units == Constants.MGDL) DecimalFormatter.to0Decimal(data.value)
else DecimalFormatter.to1Decimal(data.value * Constants.MGDL_TO_MMOLL)
fun directionToSymbol(): String =
if (data.trendArrow == GlucoseValue.TrendArrow.NONE) calculateDirection().symbol
else data.trendArrow.symbol
fun date(date: Long): BgReading {
data.timestamp = date
return this
}
fun value(value: Double): BgReading {
data.value = value
return this
}
// ------------------ DataPointWithLabelInterface ------------------
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 {
isIOBPrediction -> resourceHelper.gc(R.color.iob)
isCOBPrediction -> resourceHelper.gc(R.color.cob)
isaCOBPrediction -> -0x7f000001 and resourceHelper.gc(R.color.cob)
isUAMPrediction -> resourceHelper.gc(R.color.uam)
isZTPrediction -> resourceHelper.gc(R.color.zt)
else -> R.color.white
}
}
private val isPrediction: Boolean
get() = isaCOBPrediction || isCOBPrediction || isIOBPrediction || isUAMPrediction || isZTPrediction
// Copied from xDrip+
fun calculateDirection(): GlucoseValue.TrendArrow {
// Rework to get bgreaings from internal DB and calculate on that base
val bgReadingsList = repository.compatGetBgReadingsDataFromTime(data.timestamp - T.mins(10).msecs(), false)
.blockingGet()
if (bgReadingsList == null || bgReadingsList.size < 2) return GlucoseValue.TrendArrow.NONE
var current = bgReadingsList[1]
var previous = bgReadingsList[0]
if (bgReadingsList[1].timestamp < bgReadingsList[0].timestamp) {
current = bgReadingsList[0]
previous = bgReadingsList[1]
}
val slope: Double
// Avoid division by 0
slope = if (current.timestamp == previous.timestamp) 0.0 else (previous.value - current.value) / (previous.timestamp - current.timestamp)
aapsLogger.error(LTag.GLUCOSE, "Slope is :" + slope + " delta " + (previous.value - current.value) + " date difference " + (current.timestamp - previous.timestamp))
val slope_by_minute = slope * 60000
var arrow = GlucoseValue.TrendArrow.NONE
if (slope_by_minute <= -3.5) {
arrow = GlucoseValue.TrendArrow.DOUBLE_DOWN
} else if (slope_by_minute <= -2) {
arrow = GlucoseValue.TrendArrow.SINGLE_DOWN
} else if (slope_by_minute <= -1) {
arrow = GlucoseValue.TrendArrow.FORTY_FIVE_DOWN
} else if (slope_by_minute <= 1) {
arrow = GlucoseValue.TrendArrow.FLAT
} else if (slope_by_minute <= 2) {
arrow = GlucoseValue.TrendArrow.FORTY_FIVE_UP
} else if (slope_by_minute <= 3.5) {
arrow = GlucoseValue.TrendArrow.SINGLE_UP
} else if (slope_by_minute <= 40) {
arrow = GlucoseValue.TrendArrow.DOUBLE_UP
}
aapsLogger.error(LTag.GLUCOSE, "Direction set to: $arrow")
return arrow
}
private fun isSlopeNameInvalid(direction: String?): Boolean {
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
}
}

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

@ -2,6 +2,8 @@ package info.nightscout.androidaps.plugins.aps.loop;
import android.text.Spanned; import android.text.Spanned;
import androidx.annotation.NonNull;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -107,7 +109,7 @@ public class APSResult {
return String.format(resourceHelper.gs(R.string.carbsreq), carbsReq, carbsReqWithin); return String.format(resourceHelper.gs(R.string.carbsreq), carbsReq, carbsReqWithin);
} }
@Override @NonNull @Override
public String toString() { public String toString() {
final PumpInterface pump = activePlugin.getActivePump(); final PumpInterface pump = activePlugin.getActivePump();
if (isChangeRequested()) { if (isChangeRequested()) {
@ -131,7 +133,7 @@ public class APSResult {
ret += ("SMB: " + DecimalFormatter.toPumpSupportedBolus(smb, activePlugin.getActivePump(), resourceHelper) + "\n"); ret += ("SMB: " + DecimalFormatter.toPumpSupportedBolus(smb, activePlugin.getActivePump(), resourceHelper) + "\n");
if (isCarbsRequired()) { if (isCarbsRequired()) {
ret += getCarbsRequiredText()+"\n"; ret += getCarbsRequiredText() + "\n";
} }
// reason // reason
@ -169,7 +171,7 @@ public class APSResult {
ret += ("<b>" + "SMB" + "</b>: " + DecimalFormatter.toPumpSupportedBolus(smb, activePlugin.getActivePump(), resourceHelper) + "<br>"); ret += ("<b>" + "SMB" + "</b>: " + DecimalFormatter.toPumpSupportedBolus(smb, activePlugin.getActivePump(), resourceHelper) + "<br>");
if (isCarbsRequired()) { if (isCarbsRequired()) {
ret += getCarbsRequiredText()+"<br>"; ret += getCarbsRequiredText() + "<br>";
} }
// reason // reason
@ -239,50 +241,50 @@ public class APSResult {
if (predBGs.has("IOB")) { if (predBGs.has("IOB")) {
JSONArray iob = predBGs.getJSONArray("IOB"); JSONArray iob = predBGs.getJSONArray("IOB");
for (int i = 1; i < iob.length(); i++) { for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading(); BgReading bg = new BgReading(injector);
bg.value = iob.getInt(i); bg.setValue(iob.getInt(i));
bg.date = startTime + i * 5 * 60 * 1000L; bg.setDate(startTime + i * 5 * 60 * 1000L);
bg.isIOBPrediction = true; bg.setIOBPrediction(true);
array.add(bg); array.add(bg);
} }
} }
if (predBGs.has("aCOB")) { if (predBGs.has("aCOB")) {
JSONArray iob = predBGs.getJSONArray("aCOB"); JSONArray iob = predBGs.getJSONArray("aCOB");
for (int i = 1; i < iob.length(); i++) { for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading(); BgReading bg = new BgReading(injector);
bg.value = iob.getInt(i); bg.setValue(iob.getInt(i));
bg.date = startTime + i * 5 * 60 * 1000L; bg.setDate(startTime + i * 5 * 60 * 1000L);
bg.isaCOBPrediction = true; bg.setIsaCOBPrediction(true);
array.add(bg); array.add(bg);
} }
} }
if (predBGs.has("COB")) { if (predBGs.has("COB")) {
JSONArray iob = predBGs.getJSONArray("COB"); JSONArray iob = predBGs.getJSONArray("COB");
for (int i = 1; i < iob.length(); i++) { for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading(); BgReading bg = new BgReading(injector);
bg.value = iob.getInt(i); bg.setValue(iob.getInt(i));
bg.date = startTime + i * 5 * 60 * 1000L; bg.setDate(startTime + i * 5 * 60 * 1000L);
bg.isCOBPrediction = true; bg.setCOBPrediction(true);
array.add(bg); array.add(bg);
} }
} }
if (predBGs.has("UAM")) { if (predBGs.has("UAM")) {
JSONArray iob = predBGs.getJSONArray("UAM"); JSONArray iob = predBGs.getJSONArray("UAM");
for (int i = 1; i < iob.length(); i++) { for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading(); BgReading bg = new BgReading(injector);
bg.value = iob.getInt(i); bg.setValue(iob.getInt(i));
bg.date = startTime + i * 5 * 60 * 1000L; bg.setDate(startTime + i * 5 * 60 * 1000L);
bg.isUAMPrediction = true; bg.setUAMPrediction(true);
array.add(bg); array.add(bg);
} }
} }
if (predBGs.has("ZT")) { if (predBGs.has("ZT")) {
JSONArray iob = predBGs.getJSONArray("ZT"); JSONArray iob = predBGs.getJSONArray("ZT");
for (int i = 1; i < iob.length(); i++) { for (int i = 1; i < iob.length(); i++) {
BgReading bg = new BgReading(); BgReading bg = new BgReading(injector);
bg.value = iob.getInt(i); bg.setValue(iob.getInt(i));
bg.date = startTime + i * 5 * 60 * 1000L; bg.setDate(startTime + i * 5 * 60 * 1000L);
bg.isZTPrediction = true; bg.setZTPrediction(true);
array.add(bg); array.add(bg);
} }
} }

View file

@ -406,10 +406,10 @@ public class NSUpload {
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.getDate());
data.put("dateString", DateUtil.toISOString(reading.date)); data.put("dateString", DateUtil.toISOString(reading.getDate()));
data.put("sgv", reading.value); data.put("sgv", reading.getValue());
data.put("direction", reading.direction); data.put("direction", reading.getData().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);
@ -461,46 +461,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

@ -106,8 +106,8 @@ class AppRepository @Inject internal constructor(
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()