{
- @Inject AAPSLogger aapsLogger;
- @Inject RxBusWrapper rxBus;
- @Inject FabricPrivacy fabricPrivacy;
- @Inject AapsSchedulers aapsSchedulers;
-
- private final CompositeDisposable disposable = new CompositeDisposable();
-
- private static final ScheduledExecutorService foodEventWorker = Executors.newSingleThreadScheduledExecutor();
- private static ScheduledFuture> scheduledFoodEventPost = null;
-
- public FoodService(HasAndroidInjector injector) {
- injector.androidInjector().inject(this);
- onCreate();
- dbInitialize();
- disposable.add(rxBus
- .toObservable(EventNsFood.class)
- .observeOn(aapsSchedulers.getIo())
- .subscribe(event -> {
- int mode = event.getMode();
- JSONArray array = event.getFoods();
- if (mode == EventNsFood.Companion.getADD() || mode == EventNsFood.Companion.getUPDATE())
- this.createFoodFromJsonIfNotExists(array);
- else
- this.deleteNS(array);
- }, fabricPrivacy::logException)
- );
- }
-
- /**
- * This method is a simple re-implementation of the database create and up/downgrade functionality
- * in SQLiteOpenHelper#getDatabaseLocked method.
- *
- * It is implemented to be able to late initialize separate plugins of the application.
- */
- protected void dbInitialize() {
- DatabaseHelper helper = OpenHelperManager.getHelper(this, DatabaseHelper.class);
- int newVersion = helper.getNewVersion();
- int oldVersion = helper.getOldVersion();
-
- if (oldVersion > newVersion) {
- onDowngrade(this.getConnectionSource(), oldVersion, newVersion);
- } else {
- onUpgrade(this.getConnectionSource(), oldVersion, newVersion);
- }
- }
-
- public Dao getDao() {
- try {
- return DaoManager.createDao(this.getConnectionSource(), Food.class);
- } catch (SQLException e) {
- aapsLogger.error("Cannot create Dao for Food.class");
- }
-
- return null;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- try {
- aapsLogger.info(LTag.DATAFOOD, "onCreate");
- TableUtils.createTableIfNotExists(this.getConnectionSource(), Food.class);
- } catch (SQLException e) {
- aapsLogger.error("Can't create database", e);
- throw new RuntimeException(e);
- }
- }
-
- public void onUpgrade(ConnectionSource connectionSource, int oldVersion, int newVersion) {
- aapsLogger.info(LTag.DATAFOOD, "onUpgrade");
-// this.resetFood();
- }
-
- public void onDowngrade(ConnectionSource connectionSource, int oldVersion, int newVersion) {
- // this method is not supported right now
- }
-
- public void resetFood() {
- try {
- TableUtils.dropTable(this.getConnectionSource(), Food.class, true);
- TableUtils.createTableIfNotExists(this.getConnectionSource(), Food.class);
- } catch (SQLException e) {
- aapsLogger.error("Unhandled exception", e);
- }
- scheduleFoodChange();
- }
-
-
- /**
- * A place to centrally register events to be posted, if any data changed.
- * This should be implemented in an abstract service-class.
- *
- * We do need to make sure, that ICallback is extended to be able to handle multiple
- * events, or handle a list of events.
- *
- * on some methods the earliestDataChange event is handled separatly, in that it is checked if it is
- * set to null by another event already (eg. scheduleExtendedBolusChange).
- *
- * @param event
- * @param eventWorker
- * @param callback
- */
- private void scheduleEvent(final Event event, ScheduledExecutorService eventWorker,
- final ICallback callback) {
-
- class PostRunnable implements Runnable {
- public void run() {
- aapsLogger.debug(LTag.DATAFOOD, "Firing EventFoodChange");
- rxBus.send(event);
- callback.setPost(null);
- }
- }
- // prepare task for execution in 1 sec
- // cancel waiting task to prevent sending multiple posts
- if (callback.getPost() != null)
- callback.getPost().cancel(false);
- Runnable task = new PostRunnable();
- final int sec = 1;
- callback.setPost(eventWorker.schedule(task, sec, TimeUnit.SECONDS));
- }
-
- /**
- * Schedule a foodChange Event.
- */
- public void scheduleFoodChange() {
- this.scheduleEvent(new EventFoodDatabaseChanged(), foodEventWorker, new ICallback() {
- @Override
- public void setPost(ScheduledFuture> post) {
- scheduledFoodEventPost = post;
- }
-
- @Override
- public ScheduledFuture> getPost() {
- return scheduledFoodEventPost;
- }
- });
- }
-
- public List getFoodData() {
- try {
- return this.getDao().queryForAll();
- } catch (SQLException e) {
- aapsLogger.error("Unhandled exception", e);
- }
-
- return new ArrayList<>();
- }
-
- /*
- {
- "_id": "551ee3ad368e06e80856e6a9",
- "type": "food",
- "category": "Zakladni",
- "subcategory": "Napoje",
- "name": "Mleko",
- "portion": 250,
- "carbs": 12,
- "gi": 1,
- "created_at": "2015-04-14T06:59:16.500Z",
- "unit": "ml"
- }
- */
- public void createFoodFromJsonIfNotExists(JSONObject json) {
- try {
- Food food = Food.createFromJson(json);
- this.createFoodFromJsonIfNotExists(food);
- } catch (JSONException e) {
- aapsLogger.error("Unhandled exception", e);
- }
- }
-
- public void createFoodFromJsonIfNotExists(JSONArray array) {
- try {
- for (int n = 0; n < array.length(); n++) {
- JSONObject json = array.getJSONObject(n);
- Food food = Food.createFromJson(json);
- this.createFoodFromJsonIfNotExists(food);
- }
- } catch (JSONException e) {
- aapsLogger.error("Unhandled exception", e);
- }
- }
-
- public void createFoodFromJsonIfNotExists(Food food) {
- this.createOrUpdateByNS(food);
- }
-
- public void deleteNS(JSONObject json) {
- try {
- String _id = json.getString("_id");
- this.deleteByNSId(_id);
- } catch (JSONException | SQLException e) {
- aapsLogger.error("Unhandled exception", e);
- }
- }
-
- public void deleteNS(JSONArray array) {
- try {
- for (int n = 0; n < array.length(); n++) {
- JSONObject json = array.getJSONObject(n);
- this.deleteNS(json);
- }
- } catch (JSONException e) {
- aapsLogger.error("Unhandled exception", e);
- }
- }
-
- /**
- * deletes an entry by its NS Id.
- *
- * Basically a convenience method for findByNSId and delete.
- *
- * @param _id
- */
- public void deleteByNSId(String _id) throws SQLException {
- Food stored = this.findByNSId(_id);
- if (stored != null) {
- aapsLogger.debug(LTag.DATAFOOD, "Removing Food record from database: " + stored.toString());
- this.delete(stored);
- }
- }
-
- /**
- * deletes the food and sends the foodChange Event
- *
- * should be moved ot a Service
- *
- * @param food
- */
- public void delete(Food food) {
- try {
- this.getDao().delete(food);
- this.scheduleFoodChange();
- } catch (SQLException e) {
- aapsLogger.error("Unhandled exception", e);
- }
- }
-
- /**
- * Create of update a food record by the NS (Nightscout) Id.
- *
- * @param food
- * @return
- */
- public boolean createOrUpdateByNS(Food food) {
- // find by NS _id
- if (food._id != null && !food._id.equals("")) {
- Food old = this.findByNSId(food._id);
-
- if (old != null) {
- if (!old.isEqual(food)) {
- this.delete(old); // need to delete/create because date may change too
- old.copyFrom(food);
- this.create(old);
- return true;
- } else {
- return false;
- }
- } else {
- this.createOrUpdate(food);
- return true;
- }
- }
-
- return false;
- }
-
- public void createOrUpdate(Food food) {
- try {
- this.getDao().createOrUpdate(food);
- aapsLogger.debug(LTag.DATAFOOD, "Created or Updated: " + food.toString());
- } catch (SQLException e) {
- aapsLogger.error("Unable to createOrUpdate Food", e);
- }
- this.scheduleFoodChange();
- }
-
- public void create(Food food) {
- try {
- this.getDao().create(food);
- aapsLogger.debug(LTag.DATAFOOD, "New record: " + food.toString());
- } catch (SQLException e) {
- aapsLogger.error("Unable to create Food", e);
- }
- this.scheduleFoodChange();
- }
-
- /**
- * finds food by its NS Id.
- *
- * @param _id
- * @return
- */
- @Nullable
- public Food findByNSId(String _id) {
- try {
- List list = this.getDao().queryForEq("_id", _id);
-
- if (list.size() == 1) { // really? if there are more then one result, then we do not return anything...
- return list.get(0);
- }
- } catch (SQLException e) {
- aapsLogger.error("Unhandled exception", e);
- }
- return null;
- }
-
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefsImpl.kt
similarity index 91%
rename from app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt
rename to app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefsImpl.kt
index 98fc711d25..bf83f2c5bc 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefs.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/ImportExportPrefsImpl.kt
@@ -15,9 +15,12 @@ import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.DaggerAppCompatActivityWithResult
import info.nightscout.androidaps.activities.PreferencesActivity
+import info.nightscout.androidaps.database.entities.UserEntry
+import info.nightscout.androidaps.database.entities.UserEntry.Action
+import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.events.EventAppExit
-import info.nightscout.androidaps.interfaces.ConfigInterface
-import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
+import info.nightscout.androidaps.interfaces.Config
+import info.nightscout.androidaps.interfaces.ImportExportPrefs
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger
@@ -34,10 +37,10 @@ import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.protection.PasswordCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
+import io.reactivex.Single
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
-import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.system.exitProcess
@@ -47,20 +50,21 @@ import kotlin.system.exitProcess
*/
@Singleton
-class ImportExportPrefs @Inject constructor(
+class ImportExportPrefsImpl @Inject constructor(
private var log: AAPSLogger,
private val resourceHelper: ResourceHelper,
private val sp: SP,
private val buildHelper: BuildHelper,
private val rxBus: RxBusWrapper,
private val passwordCheck: PasswordCheck,
- private val config: ConfigInterface,
+ private val config: Config,
private val androidPermission: AndroidPermission,
private val classicPrefsFormat: ClassicPrefsFormat,
private val encryptedPrefsFormat: EncryptedPrefsFormat,
private val prefFileList: PrefFileListProvider,
- private val uel: UserEntryLogger
-) : ImportExportPrefsInterface {
+ private val uel: UserEntryLogger,
+ private val dateUtil: DateUtil
+) : ImportExportPrefs {
override fun prefsFileExists(): Boolean {
return prefFileList.listPreferenceFiles().size > 0
@@ -91,7 +95,7 @@ class ImportExportPrefs @Inject constructor(
val metadata: MutableMap = mutableMapOf()
metadata[PrefsMetadataKey.DEVICE_NAME] = PrefMetadata(detectUserName(context), PrefsStatus.OK)
- metadata[PrefsMetadataKey.CREATED_AT] = PrefMetadata(DateUtil.toISOString(Date()), PrefsStatus.OK)
+ metadata[PrefsMetadataKey.CREATED_AT] = PrefMetadata(dateUtil.toISOString(dateUtil.now()), PrefsStatus.OK)
metadata[PrefsMetadataKey.AAPS_VERSION] = PrefMetadata(BuildConfig.VERSION_NAME, PrefsStatus.OK)
metadata[PrefsMetadataKey.AAPS_FLAVOUR] = PrefMetadata(BuildConfig.FLAVOR, PrefsStatus.OK)
metadata[PrefsMetadataKey.DEVICE_MODEL] = PrefMetadata(config.currentDeviceModelString, PrefsStatus.OK)
@@ -105,6 +109,7 @@ class ImportExportPrefs @Inject constructor(
return metadata
}
+ @Suppress("SpellCheckingInspection")
private fun detectUserName(context: Context): String {
// based on https://medium.com/@pribble88/how-to-get-an-android-device-nickname-4b4700b3068c
val n1 = Settings.System.getString(context.contentResolver, "bluetooth_name")
@@ -343,8 +348,8 @@ class ImportExportPrefs @Inject constructor(
private fun restartAppAfterImport(context: Context) {
sp.putBoolean(R.string.key_setupwizard_processed, true)
- OKDialog.show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp), Runnable {
- uel.log("IMPORT")
+ OKDialog.show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp)) {
+ uel.log(Action.IMPORT_SETTINGS, Sources.Maintenance)
log.debug(LTag.CORE, "Exiting")
rxBus.send(EventAppExit())
if (context is AppCompatActivity) {
@@ -352,6 +357,23 @@ class ImportExportPrefs @Inject constructor(
}
System.runFinalization()
exitProcess(0)
- })
+ }
+ }
+
+ override fun exportUserEntriesCsv(activity: FragmentActivity, singleEntries: Single>) {
+ val entries = singleEntries.blockingGet()
+ prefFileList.ensureExportDirExists()
+ val newFile = prefFileList.newExportXmlFile()
+
+ try {
+ classicPrefsFormat.saveCsv(newFile, entries)
+ ToastUtils.okToast(activity, resourceHelper.gs(R.string.ue_exported))
+ } catch (e: FileNotFoundException) {
+ ToastUtils.errorToast(activity, resourceHelper.gs(R.string.filenotfound) + " " + newFile)
+ log.error(LTag.CORE, "Unhandled exception", e)
+ } catch (e: IOException) {
+ ToastUtils.errorToast(activity, e.message)
+ log.error(LTag.CORE, "Unhandled exception", e)
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt
index 7f44689ebc..4337808106 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenanceFragment.kt
@@ -6,18 +6,21 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import dagger.android.support.DaggerFragment
-import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
+import info.nightscout.androidaps.database.entities.UserEntry.Action
+import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding
import info.nightscout.androidaps.events.EventNewBG
-import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
+import info.nightscout.androidaps.interfaces.DataSyncSelector
+import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
+import info.nightscout.androidaps.interfaces.ImportExportPrefs
+import info.nightscout.androidaps.interfaces.PumpSync
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
-import info.nightscout.androidaps.plugins.general.food.FoodPlugin
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
@@ -32,12 +35,13 @@ class MaintenanceFragment : DaggerFragment() {
@Inject lateinit var maintenancePlugin: MaintenancePlugin
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper
- @Inject lateinit var treatmentsPlugin: TreatmentsPlugin
- @Inject lateinit var foodPlugin: FoodPlugin
- @Inject lateinit var importExportPrefs: ImportExportPrefsInterface
+ @Inject lateinit var importExportPrefs: ImportExportPrefs
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var repository: AppRepository
+ @Inject lateinit var databaseHelper: DatabaseHelperInterface
@Inject lateinit var uel: UserEntryLogger
+ @Inject lateinit var dataSyncSelector: DataSyncSelector
+ @Inject lateinit var pumpSync: PumpSync
private val compositeDisposable = CompositeDisposable()
@@ -56,47 +60,56 @@ class MaintenanceFragment : DaggerFragment() {
super.onViewCreated(view, savedInstanceState)
binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() }
binding.logDelete.setOnClickListener {
- uel.log("DELETE LOGS")
+ uel.log(Action.DELETE_LOGS, Sources.Maintenance)
maintenancePlugin.deleteLogs()
}
binding.navResetdb.setOnClickListener {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable {
- uel.log("RESET DATABASES")
compositeDisposable.add(
fromAction {
- MainApp.getDbHelper().resetDatabases()
- // should be handled by Plugin-Interface and
- // additional service interface and plugin registry
- foodPlugin.service?.resetFood()
- treatmentsPlugin.service.resetTreatments()
+ databaseHelper.resetDatabases()
repository.clearDatabases()
+ dataSyncSelector.resetToNextFullSync()
+ pumpSync.connectNewPump()
}
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.main)
.subscribeBy(
onError = { aapsLogger.error("Error clearing databases", it) },
- onComplete = { rxBus.send(EventNewBG(null)) }
+ onComplete = {
+ rxBus.send(EventNewBG(null))
+ rxBus.send(EventNewHistoryData(0, true))
+ }
)
)
+ uel.log(Action.RESET_DATABASES, Sources.Maintenance)
})
}
}
binding.navExport.setOnClickListener {
- uel.log("EXPORT SETTINGS")
+ uel.log(Action.EXPORT_SETTINGS, Sources.Maintenance)
// start activity for checking permissions...
importExportPrefs.verifyStoragePermissions(this) {
importExportPrefs.exportSharedPreferences(this)
}
}
binding.navImport.setOnClickListener {
- uel.log("IMPORT SETTINGS")
+ uel.log(Action.IMPORT_SETTINGS, Sources.Maintenance)
// start activity for checking permissions...
importExportPrefs.verifyStoragePermissions(this) {
importExportPrefs.importSharedPreferences(this)
}
}
binding.navLogsettings.setOnClickListener { startActivity(Intent(activity, LogSettingActivity::class.java)) }
+ binding.exportCsv.setOnClickListener {
+ activity?.let { activity ->
+ OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.ue_export_to_csv) + "?") {
+ uel.log(Action.EXPORT_CSV, Sources.Maintenance)
+ importExportPrefs.exportUserEntriesCsv(activity, repository.getAllUserEntries())
+ }
+ }
+ }
}
@Synchronized
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePlugin.kt
index e50b19b0ec..20bdfa269a 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/MaintenancePlugin.kt
@@ -8,7 +8,7 @@ import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.BuildConfig
-import info.nightscout.androidaps.Config
+import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription
@@ -173,7 +173,7 @@ class MaintenancePlugin @Inject constructor(
builder.append("Build: " + BuildConfig.BUILDVERSION + System.lineSeparator())
builder.append("Remote: " + BuildConfig.REMOTE + System.lineSeparator())
builder.append("Flavor: " + BuildConfig.FLAVOR + BuildConfig.BUILD_TYPE + System.lineSeparator())
- builder.append(resourceHelper.gs(R.string.configbuilder_nightscoutversion_label) + " " + nsSettingsStatus.nightscoutVersionName + System.lineSeparator())
+ builder.append(resourceHelper.gs(R.string.configbuilder_nightscoutversion_label) + " " + nsSettingsStatus.getVersion() + System.lineSeparator())
if (buildHelper.isEngineeringMode()) builder.append(resourceHelper.gs(R.string.engineering_mode_enabled))
return sendMail(attachmentUri, recipient, subject, builder.toString())
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt
new file mode 100644
index 0000000000..99b9febf03
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt
@@ -0,0 +1,448 @@
+package info.nightscout.androidaps.plugins.general.nsclient
+
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.database.AppRepository
+import info.nightscout.androidaps.database.entities.DeviceStatus
+import info.nightscout.androidaps.database.entities.*
+import info.nightscout.androidaps.interfaces.ActivePlugin
+import info.nightscout.androidaps.interfaces.DataSyncSelector
+import info.nightscout.androidaps.interfaces.ProfileFunction
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.extensions.toJson
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import javax.inject.Inject
+
+class DataSyncSelectorImplementation @Inject constructor(
+ private val sp: SP,
+ private val aapsLogger: AAPSLogger,
+ private val dateUtil: DateUtil,
+ private val profileFunction: ProfileFunction,
+ private val nsClientPlugin: NSClientPlugin,
+ private val activePlugin: ActivePlugin,
+ private val appRepository: AppRepository
+) : DataSyncSelector {
+
+ override fun resetToNextFullSync() {
+ sp.remove(R.string.key_ns_temporary_target_last_synced_id)
+ sp.remove(R.string.key_ns_glucose_value_last_synced_id)
+ sp.remove(R.string.key_ns_food_last_synced_id)
+ sp.remove(R.string.key_ns_bolus_last_synced_id)
+ sp.remove(R.string.key_ns_carbs_last_synced_id)
+ sp.remove(R.string.key_ns_bolus_calculator_result_last_synced_id)
+ sp.remove(R.string.key_ns_device_status_last_synced_id)
+ sp.remove(R.string.key_ns_temporary_basal_last_synced_id)
+ sp.remove(R.string.key_ns_extended_bolus_last_synced_id)
+ sp.remove(R.string.key_ns_therapy_event_last_synced_id)
+ sp.remove(R.string.key_ns_profile_switch_last_synced_id)
+ }
+
+ override fun confirmLastBolusIdIfGreater(lastSynced: Long) {
+ if (lastSynced > sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)) {
+ aapsLogger.debug(LTag.NSCLIENT, "Setting Bolus data sync from $lastSynced")
+ sp.putLong(R.string.key_ns_bolus_last_synced_id, lastSynced)
+ }
+ }
+
+ // Prepared for v3 (returns all modified after)
+ override fun changedBoluses(): List {
+ val startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
+ return appRepository.getModifiedBolusesDataFromId(startId)
+ .blockingGet()
+ .filter { it.type != Bolus.Type.PRIMING }
+ .also {
+ aapsLogger.debug(LTag.NSCLIENT, "Loading Bolus data for sync from $startId. Records ${it.size}")
+ }
+ }
+
+ override fun processChangedBolusesCompat(): Boolean {
+ val startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
+ appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus ->
+ aapsLogger.info(LTag.DATABASE, "Loading Bolus data Start: $startId ID: ${bolus.first.id} HistoryID: ${bolus.second} ")
+ when {
+ // removed and not uploaded yet = ignore
+ !bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId == null -> Any()
+ // removed and already uploaded = send for removal
+ !bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbRemove("treatments", bolus.first.interfaceIDs.nightscoutId, DataSyncSelector.PairBolus(bolus.first, bolus.second))
+ // existing without nsId = create new
+ bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId == null ->
+ nsClientPlugin.nsClientService?.dbAdd("treatments", bolus.first.toJson(dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second))
+ // existing with nsId = update
+ bolus.first.isValid && bolus.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbUpdate("treatments", bolus.first.interfaceIDs.nightscoutId, bolus.first.toJson(dateUtil), DataSyncSelector.PairBolus(bolus.first, bolus.second))
+ }
+ return true
+ }
+ return false
+ }
+
+ override fun confirmLastCarbsIdIfGreater(lastSynced: Long) {
+ if (lastSynced > sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)) {
+ aapsLogger.debug(LTag.NSCLIENT, "Setting Carbs data sync from $lastSynced")
+ sp.putLong(R.string.key_ns_carbs_last_synced_id, lastSynced)
+ }
+ }
+
+ // Prepared for v3 (returns all modified after)
+ override fun changedCarbs(): List {
+ val startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
+ return appRepository.getModifiedCarbsDataFromId(startId).blockingGet().also {
+ aapsLogger.debug(LTag.NSCLIENT, "Loading Carbs data for sync from $startId. Records ${it.size}")
+ }
+ }
+
+ override fun processChangedCarbsCompat(): Boolean {
+ val startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
+ appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb ->
+ aapsLogger.info(LTag.DATABASE, "Loading Carbs data Start: $startId ID: ${carb.first.id} HistoryID: ${carb.second} ")
+ when {
+ // removed and not uploaded yet = ignore
+ !carb.first.isValid && carb.first.interfaceIDs.nightscoutId == null -> Any()
+ // removed and already uploaded = send for removal
+ !carb.first.isValid && carb.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbRemove("treatments", carb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairCarbs(carb.first, carb.second))
+ // existing without nsId = create new
+ carb.first.isValid && carb.first.interfaceIDs.nightscoutId == null ->
+ nsClientPlugin.nsClientService?.dbAdd("treatments", carb.first.toJson(dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second))
+ // existing with nsId = update
+ carb.first.isValid && carb.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbUpdate("treatments", carb.first.interfaceIDs.nightscoutId, carb.first.toJson(dateUtil), DataSyncSelector.PairCarbs(carb.first, carb.second))
+ }
+ return true
+ }
+ return false
+ }
+
+ override fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long) {
+ if (lastSynced > sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)) {
+ aapsLogger.debug(LTag.NSCLIENT, "Setting BolusCalculatorResult data sync from $lastSynced")
+ sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, lastSynced)
+ }
+ }
+
+ // Prepared for v3 (returns all modified after)
+ override fun changedBolusCalculatorResults(): List {
+ val startId = sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
+ return appRepository.getModifiedBolusCalculatorResultsDataFromId(startId).blockingGet().also {
+ aapsLogger.debug(LTag.NSCLIENT, "Loading BolusCalculatorResult data for sync from $startId. Records ${it.size}")
+ }
+ }
+
+ override fun processChangedBolusCalculatorResultsCompat(): Boolean {
+ val startId = sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
+ appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult ->
+ aapsLogger.info(LTag.DATABASE, "Loading BolusCalculatorResult data Start: $startId ID: ${bolusCalculatorResult.first.id} HistoryID: ${bolusCalculatorResult.second} ")
+ when {
+ // removed and not uploaded yet = ignore
+ !bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId == null -> Any()
+ // removed and already uploaded = send for removal
+ !bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbRemove("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second))
+ // existing without nsId = create new
+ bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
+ nsClientPlugin.nsClientService?.dbAdd("treatments", bolusCalculatorResult.first.toJson(dateUtil), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second))
+ // existing with nsId = update
+ bolusCalculatorResult.first.isValid && bolusCalculatorResult.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbUpdate("treatments", bolusCalculatorResult.first.interfaceIDs.nightscoutId, bolusCalculatorResult.first.toJson(dateUtil), DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second))
+ }
+ return true
+ }
+ return false
+ }
+
+ override fun confirmLastTempTargetsIdIfGreater(lastSynced: Long) {
+ if (lastSynced > sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)) {
+ aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryTarget data sync from $lastSynced")
+ sp.putLong(R.string.key_ns_temporary_target_last_synced_id, lastSynced)
+ }
+ }
+
+ // Prepared for v3 (returns all modified after)
+ override fun changedTempTargets(): List {
+ val startId = sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
+ return appRepository.getModifiedTemporaryTargetsDataFromId(startId).blockingGet().also {
+ aapsLogger.debug(LTag.NSCLIENT, "Loading TemporaryTarget data for sync from $startId. Records ${it.size}")
+ }
+ }
+
+ override fun processChangedTempTargetsCompat(): Boolean {
+ val startId = sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
+ appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt ->
+ aapsLogger.info(LTag.DATABASE, "Loading TemporaryTarget data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ")
+ when {
+ // removed and not uploaded yet = ignore
+ !tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any()
+ // removed and already uploaded = send for removal
+ !tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbRemove("treatments", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTemporaryTarget(tt.first, tt.second))
+ // existing without nsId = create new
+ tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null ->
+ nsClientPlugin.nsClientService?.dbAdd("treatments", tt.first.toJson(profileFunction.getUnits(), dateUtil), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second))
+ // existing with nsId = update
+ tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbUpdate("treatments", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(profileFunction.getUnits(), dateUtil), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second))
+ }
+ return true
+ }
+ return false
+ }
+
+ override fun confirmLastFoodIdIfGreater(lastSynced: Long) {
+ if (lastSynced > sp.getLong(R.string.key_ns_food_last_synced_id, 0)) {
+ aapsLogger.debug(LTag.NSCLIENT, "Setting Food data sync from $lastSynced")
+ sp.putLong(R.string.key_ns_food_last_synced_id, lastSynced)
+ }
+ }
+
+ // Prepared for v3 (returns all modified after)
+ override fun changedFoods(): List {
+ val startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0)
+ return appRepository.getModifiedFoodDataFromId(startId).blockingGet().also {
+ aapsLogger.debug(LTag.NSCLIENT, "Loading Food data for sync from $startId. Records ${it.size}")
+ }
+ }
+
+ override fun processChangedFoodsCompat(): Boolean {
+ val startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0)
+ appRepository.getNextSyncElementFood(startId).blockingGet()?.let { tt ->
+ aapsLogger.info(LTag.DATABASE, "Loading Food data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ")
+ when {
+ // removed and not uploaded yet = ignore
+ !tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any()
+ // removed and already uploaded = send for removal
+ !tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbRemove("food", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairFood(tt.first, tt.second))
+ // existing without nsId = create new
+ tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null ->
+ nsClientPlugin.nsClientService?.dbAdd("food", tt.first.toJson(), DataSyncSelector.PairFood(tt.first, tt.second))
+ // existing with nsId = update
+ tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbUpdate("food", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(), DataSyncSelector.PairFood(tt.first, tt.second))
+ }
+ return true
+ }
+ return false
+ }
+
+ override fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) {
+ if (lastSynced > sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)) {
+ aapsLogger.debug(LTag.NSCLIENT, "Setting GlucoseValue data sync from $lastSynced")
+ sp.putLong(R.string.key_ns_glucose_value_last_synced_id, lastSynced)
+ }
+ }
+
+ // Prepared for v3 (returns all modified after)
+ override fun changedGlucoseValues(): List {
+ val startId = sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)
+ return appRepository.getModifiedBgReadingsDataFromId(startId).blockingGet().also {
+ aapsLogger.debug(LTag.NSCLIENT, "Loading GlucoseValue data for sync from $startId . Records ${it.size}")
+ }
+ }
+
+ override fun processChangedGlucoseValuesCompat(): Boolean {
+ val startId = sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)
+ appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv ->
+ aapsLogger.info(LTag.DATABASE, "Loading GlucoseValue data Start: $startId ID: ${gv.first.id} HistoryID: ${gv.second} ")
+ if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) {
+ when {
+ // removed and not uploaded yet = ignore
+ !gv.first.isValid && gv.first.interfaceIDs.nightscoutId == null -> Any()
+ // removed and already uploaded = send for removal
+ !gv.first.isValid && gv.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbRemove("entries", gv.first.interfaceIDs.nightscoutId, DataSyncSelector.PairGlucoseValue(gv.first, gv.second))
+ // existing without nsId = create new
+ gv.first.isValid && gv.first.interfaceIDs.nightscoutId == null ->
+ nsClientPlugin.nsClientService?.dbAdd("entries", gv.first.toJson(dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second))
+ // existing with nsId = update
+ gv.first.isValid && gv.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbUpdate("entries", gv.first.interfaceIDs.nightscoutId, gv.first.toJson(dateUtil), DataSyncSelector.PairGlucoseValue(gv.first, gv.second))
+ }
+ return true
+ }
+ }
+ return false
+ }
+
+ override fun confirmLastTherapyEventIdIfGreater(lastSynced: Long) {
+ if (lastSynced > sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)) {
+ aapsLogger.debug(LTag.NSCLIENT, "Setting TherapyEvents data sync from $lastSynced")
+ sp.putLong(R.string.key_ns_therapy_event_last_synced_id, lastSynced)
+ }
+ }
+
+ // Prepared for v3 (returns all modified after)
+ override fun changedTherapyEvents(): List {
+ val startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
+ return appRepository.getModifiedTherapyEventDataFromId(startId).blockingGet().also {
+ aapsLogger.debug(LTag.NSCLIENT, "Loading TherapyEvents data for sync from $startId. Records ${it.size}")
+ }
+ }
+
+ override fun processChangedTherapyEventsCompat(): Boolean {
+ val startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
+ appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { tt ->
+ aapsLogger.info(LTag.DATABASE, "Loading TherapyEvents data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ")
+ when {
+ // removed and not uploaded yet = ignore
+ !tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any()
+ // removed and already uploaded = send for removal
+ !tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbRemove("treatments", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTherapyEvent(tt.first, tt.second))
+ // existing without nsId = create new
+ tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null ->
+ nsClientPlugin.nsClientService?.dbAdd("treatments", tt.first.toJson(), DataSyncSelector.PairTherapyEvent(tt.first, tt.second))
+ // existing with nsId = update
+ tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbUpdate("treatments", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(), DataSyncSelector.PairTherapyEvent(tt.first, tt.second))
+ }
+ return true
+ }
+ return false
+ }
+
+ override fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) {
+ if (lastSynced > sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)) {
+ aapsLogger.debug(LTag.NSCLIENT, "Setting DeviceStatus data sync from $lastSynced")
+ sp.putLong(R.string.key_ns_device_status_last_synced_id, lastSynced)
+ }
+ }
+
+ override fun changedDeviceStatuses(): List {
+ val startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
+ return appRepository.getModifiedDeviceStatusDataFromId(startId).blockingGet().also {
+ aapsLogger.debug(LTag.NSCLIENT, "Loading DeviceStatus data for sync from $startId. Records ${it.size}")
+ }
+ }
+
+ override fun processChangedDeviceStatusesCompat(): Boolean {
+ val startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
+ appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
+ aapsLogger.info(LTag.DATABASE, "Loading DeviceStatus data Start: $startId ID: ${deviceStatus.id}")
+ when {
+ // without nsId = create new
+ deviceStatus.interfaceIDs.nightscoutId == null ->
+ nsClientPlugin.nsClientService?.dbAdd("devicestatus", deviceStatus.toJson(dateUtil), deviceStatus)
+ // with nsId = ignore
+ deviceStatus.interfaceIDs.nightscoutId != null -> Any()
+ }
+ return true
+ }
+ return false
+ }
+
+ override fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long) {
+ if (lastSynced > sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)) {
+ aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryBasal data sync from $lastSynced")
+ sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, lastSynced)
+ }
+ }
+
+ // Prepared for v3 (returns all modified after)
+ override fun changedTemporaryBasals(): List {
+ val startId = sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
+ return appRepository.getModifiedTemporaryBasalDataFromId(startId).blockingGet().also {
+ aapsLogger.debug(LTag.NSCLIENT, "Loading TemporaryBasal data for sync from $startId. Records ${it.size}")
+ }
+ }
+
+ override fun processChangedTemporaryBasalsCompat(): Boolean {
+ val startId = sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
+ appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb ->
+ aapsLogger.info(LTag.DATABASE, "Loading TemporaryBasal data Start: $startId ID: ${tb.first.id} HistoryID: ${tb.second} ")
+ profileFunction.getProfile(tb.first.timestamp)?.let { profile ->
+ when {
+ // removed and not uploaded yet = ignore
+ !tb.first.isValid && tb.first.interfaceIDs.nightscoutId == null -> Any()
+ // removed and already uploaded = send for removal
+ !tb.first.isValid && tb.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbRemove("treatments", tb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTemporaryBasal(tb.first, tb.second))
+ // existing without nsId = create new
+ tb.first.isValid && tb.first.interfaceIDs.nightscoutId == null ->
+ nsClientPlugin.nsClientService?.dbAdd("treatments", tb.first.toJson(profile, dateUtil), DataSyncSelector.PairTemporaryBasal(tb.first, tb.second))
+ // existing with nsId = update
+ tb.first.isValid && tb.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbUpdate("treatments", tb.first.interfaceIDs.nightscoutId, tb.first.toJson(profile, dateUtil), DataSyncSelector.PairTemporaryBasal(tb.first, tb.second))
+ }
+ return true
+ }
+ }
+ return false
+ }
+
+ override fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long) {
+ if (lastSynced > sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)) {
+ aapsLogger.debug(LTag.NSCLIENT, "Setting ExtendedBolus data sync from $lastSynced")
+ sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, lastSynced)
+ }
+ }
+
+ // Prepared for v3 (returns all modified after)
+ override fun changedExtendedBoluses(): List {
+ val startId = sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
+ return appRepository.getModifiedExtendedBolusDataFromId(startId).blockingGet().also {
+ aapsLogger.debug(LTag.NSCLIENT, "Loading ExtendedBolus data for sync from $startId. Records ${it.size}")
+ }
+ }
+
+ override fun processChangedExtendedBolusesCompat(): Boolean {
+ val startId = sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
+ appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb ->
+ aapsLogger.info(LTag.DATABASE, "Loading ExtendedBolus data Start: $startId ID: ${eb.first.id} HistoryID: ${eb.second} ")
+ profileFunction.getProfile(eb.first.timestamp)?.let { profile ->
+ when {
+ // removed and not uploaded yet = ignore
+ !eb.first.isValid && eb.first.interfaceIDs.nightscoutId == null -> Any()
+ // removed and already uploaded = send for removal
+ !eb.first.isValid && eb.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbRemove("treatments", eb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairExtendedBolus(eb.first, eb.second))
+ // existing without nsId = create new
+ eb.first.isValid && eb.first.interfaceIDs.nightscoutId == null ->
+ nsClientPlugin.nsClientService?.dbAdd("treatments", eb.first.toJson(profile, dateUtil), DataSyncSelector.PairExtendedBolus(eb.first, eb.second))
+ // existing with nsId = update
+ eb.first.isValid && eb.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbUpdate("treatments", eb.first.interfaceIDs.nightscoutId, eb.first.toJson(profile, dateUtil), DataSyncSelector.PairExtendedBolus(eb.first, eb.second))
+ }
+ return true
+ }
+ }
+ return false
+ }
+
+ override fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long) {
+ if (lastSynced > sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)) {
+ aapsLogger.debug(LTag.NSCLIENT, "Setting ProfileSwitch data sync from $lastSynced")
+ sp.putLong(R.string.key_ns_profile_switch_last_synced_id, lastSynced)
+ }
+ }
+
+ override fun changedProfileSwitch(): List {
+ val startId = sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
+ return appRepository.getModifiedProfileSwitchDataFromId(startId).blockingGet().also {
+ aapsLogger.debug(LTag.NSCLIENT, "Loading ProfileSwitch data for sync from $startId. Records ${it.size}")
+ }
+ }
+
+ override fun processChangedProfileSwitchesCompat(): Boolean {
+ val startId = sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
+ appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { eb ->
+ aapsLogger.info(LTag.DATABASE, "Loading ProfileSwitch data Start: $startId ID: ${eb.first.id} HistoryID: ${eb.second} ")
+ when {
+ // removed and not uploaded yet = ignore
+ !eb.first.isValid && eb.first.interfaceIDs.nightscoutId == null -> Any()
+ // removed and already uploaded = send for removal
+ !eb.first.isValid && eb.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbRemove("treatments", eb.first.interfaceIDs.nightscoutId, DataSyncSelector.PairProfileSwitch(eb.first, eb.second))
+ // existing without nsId = create new
+ eb.first.isValid && eb.first.interfaceIDs.nightscoutId == null ->
+ nsClientPlugin.nsClientService?.dbAdd("treatments", eb.first.toJson(dateUtil), DataSyncSelector.PairProfileSwitch(eb.first, eb.second))
+ // existing with nsId = update
+ eb.first.isValid && eb.first.interfaceIDs.nightscoutId != null ->
+ nsClientPlugin.nsClientService?.dbUpdate("treatments", eb.first.interfaceIDs.nightscoutId, eb.first.toJson(dateUtil), DataSyncSelector.PairProfileSwitch(eb.first, eb.second))
+ }
+ return true
+ }
+ return false
+ }
+}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddAckWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddAckWorker.kt
new file mode 100644
index 0000000000..39c20b00e3
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddAckWorker.kt
@@ -0,0 +1,256 @@
+package info.nightscout.androidaps.plugins.general.nsclient
+
+import android.content.Context
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import androidx.work.workDataOf
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.database.AppRepository
+import info.nightscout.androidaps.database.entities.DeviceStatus
+import info.nightscout.androidaps.database.transactions.*
+import info.nightscout.androidaps.interfaces.DataSyncSelector
+import info.nightscout.androidaps.interfaces.DataSyncSelector.*
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAddAck
+import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog
+import info.nightscout.androidaps.receivers.DataWorker
+import info.nightscout.androidaps.utils.rx.AapsSchedulers
+import javax.inject.Inject
+
+class NSClientAddAckWorker(
+ context: Context,
+ params: WorkerParameters
+) : Worker(context, params) {
+
+ @Inject lateinit var dataWorker: DataWorker
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var repository: AppRepository
+ @Inject lateinit var rxBus: RxBusWrapper
+ @Inject lateinit var dataSyncSelector: DataSyncSelector
+ @Inject lateinit var aapsSchedulers: AapsSchedulers
+
+ override fun doWork(): Result {
+ var ret = Result.success()
+
+ val ack = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as NSAddAck?
+ ?: return Result.failure(workDataOf("Error" to "missing input data"))
+
+ when (ack.originalObject) {
+ is PairTemporaryTarget -> {
+ val pair = ack.originalObject
+ pair.value.interfaceIDs.nightscoutId = ack.id
+ repository.runTransactionForResult(UpdateNsIdTemporaryTargetTransaction(pair.value))
+ .doOnError { error ->
+ aapsLogger.error(LTag.DATABASE, "Updated ns id of TemporaryTarget failed", error)
+ ret = Result.failure((workDataOf("Error" to error.toString())))
+ }
+ .doOnSuccess {
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ aapsLogger.debug(LTag.DATABASE, "Updated ns id of TemporaryTarget " + pair.value)
+ dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.updateRecordId)
+ }
+ .blockingGet()
+ rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryTarget " + pair.value.interfaceIDs.nightscoutId))
+ // Send new if waiting
+ dataSyncSelector.processChangedTempTargetsCompat()
+ }
+
+ is PairGlucoseValue -> {
+ val pair = ack.originalObject
+ pair.value.interfaceIDs.nightscoutId = ack.id
+ repository.runTransactionForResult(UpdateNsIdGlucoseValueTransaction(pair.value))
+ .doOnError { error ->
+ aapsLogger.error(LTag.DATABASE, "Updated ns id of GlucoseValue failed", error)
+ ret = Result.failure((workDataOf("Error" to error.toString())))
+ }
+ .doOnSuccess {
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ aapsLogger.debug(LTag.DATABASE, "Updated ns id of GlucoseValue " + pair.value)
+ dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.updateRecordId)
+ }
+ .blockingGet()
+ rxBus.send(EventNSClientNewLog("DBADD", "Acked GlucoseValue " + pair.value.interfaceIDs.nightscoutId))
+ // Send new if waiting
+ dataSyncSelector.processChangedGlucoseValuesCompat()
+ }
+
+ is PairFood -> {
+ val pair = ack.originalObject
+ pair.value.interfaceIDs.nightscoutId = ack.id
+ repository.runTransactionForResult(UpdateNsIdFoodTransaction(pair.value))
+ .doOnError { error ->
+ aapsLogger.error(LTag.DATABASE, "Updated ns id of Food failed", error)
+ ret = Result.failure((workDataOf("Error" to error.toString())))
+ }
+ .doOnSuccess {
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ aapsLogger.debug(LTag.DATABASE, "Updated ns id of Food " + pair.value)
+ dataSyncSelector.confirmLastFoodIdIfGreater(pair.updateRecordId)
+ }
+ .blockingGet()
+ rxBus.send(EventNSClientNewLog("DBADD", "Acked Food " + pair.value.interfaceIDs.nightscoutId))
+ // Send new if waiting
+ dataSyncSelector.processChangedFoodsCompat()
+ }
+
+ is PairTherapyEvent -> {
+ val pair = ack.originalObject
+ pair.value.interfaceIDs.nightscoutId = ack.id
+ repository.runTransactionForResult(UpdateNsIdTherapyEventTransaction(pair.value))
+ .doOnError { error ->
+ aapsLogger.error(LTag.DATABASE, "Updated ns id of TherapyEvent failed", error)
+ ret = Result.failure((workDataOf("Error" to error.toString())))
+ }
+ .doOnSuccess {
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ aapsLogger.debug(LTag.DATABASE, "Updated ns id of TherapyEvent " + pair.value)
+ dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.updateRecordId)
+ }
+ .blockingGet()
+ rxBus.send(EventNSClientNewLog("DBADD", "Acked TherapyEvent " + pair.value.interfaceIDs.nightscoutId))
+ // Send new if waiting
+ dataSyncSelector.processChangedTherapyEventsCompat()
+ }
+
+ is PairBolus -> {
+ val pair = ack.originalObject
+ pair.value.interfaceIDs.nightscoutId = ack.id
+ repository.runTransactionForResult(UpdateNsIdBolusTransaction(pair.value))
+ .doOnError { error ->
+ aapsLogger.error(LTag.DATABASE, "Updated ns id of Bolus failed", error)
+ ret = Result.failure((workDataOf("Error" to error.toString())))
+ }
+ .doOnSuccess {
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ aapsLogger.debug(LTag.DATABASE, "Updated ns id of Bolus " + pair.value)
+ dataSyncSelector.confirmLastBolusIdIfGreater(pair.updateRecordId)
+ }
+ .blockingGet()
+ rxBus.send(EventNSClientNewLog("DBADD", "Acked Bolus " + pair.value.interfaceIDs.nightscoutId))
+ // Send new if waiting
+ dataSyncSelector.processChangedBolusesCompat()
+ }
+
+ is PairCarbs -> {
+ val pair = ack.originalObject
+ pair.value.interfaceIDs.nightscoutId = ack.id
+ repository.runTransactionForResult(UpdateNsIdCarbsTransaction(pair.value))
+ .doOnError { error ->
+ aapsLogger.error(LTag.DATABASE, "Updated ns id of Carbs failed", error)
+ ret = Result.failure((workDataOf("Error" to error.toString())))
+ }
+ .doOnSuccess {
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ aapsLogger.debug(LTag.DATABASE, "Updated ns id of Carbs " + pair.value)
+ dataSyncSelector.confirmLastCarbsIdIfGreater(pair.updateRecordId)
+ }
+ .blockingGet()
+ rxBus.send(EventNSClientNewLog("DBADD", "Acked Carbs" + pair.value.interfaceIDs.nightscoutId))
+ // Send new if waiting
+ dataSyncSelector.processChangedCarbsCompat()
+ }
+
+ is PairBolusCalculatorResult -> {
+ val pair = ack.originalObject
+ pair.value.interfaceIDs.nightscoutId = ack.id
+ repository.runTransactionForResult(UpdateNsIdBolusCalculatorResultTransaction(pair.value))
+ .doOnError { error ->
+ aapsLogger.error(LTag.DATABASE, "Updated ns id of BolusCalculatorResult failed", error)
+ ret = Result.failure((workDataOf("Error" to error.toString())))
+ }
+ .doOnSuccess {
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ aapsLogger.debug(LTag.DATABASE, "Updated ns id of BolusCalculatorResult " + pair.value)
+ dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.updateRecordId)
+ }
+ .blockingGet()
+ rxBus.send(EventNSClientNewLog("DBADD", "Acked BolusCalculatorResult" + pair.value.interfaceIDs.nightscoutId))
+ // Send new if waiting
+ dataSyncSelector.processChangedBolusCalculatorResultsCompat()
+ }
+
+ is PairTemporaryBasal -> {
+ val pair = ack.originalObject
+ pair.value.interfaceIDs.nightscoutId = ack.id
+ repository.runTransactionForResult(UpdateNsIdTemporaryBasalTransaction(pair.value))
+ .doOnError { error ->
+ aapsLogger.error(LTag.DATABASE, "Updated ns id of TemporaryBasal failed", error)
+ ret = Result.failure((workDataOf("Error" to error.toString())))
+ }
+ .doOnSuccess {
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ aapsLogger.debug(LTag.DATABASE, "Updated ns id of TemporaryBasal " + pair.value)
+ dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.updateRecordId)
+ }
+ .blockingGet()
+ rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryBasal" + pair.value.interfaceIDs.nightscoutId))
+ // Send new if waiting
+ dataSyncSelector.processChangedTemporaryBasalsCompat()
+ }
+
+ is PairExtendedBolus -> {
+ val pair = ack.originalObject
+ pair.value.interfaceIDs.nightscoutId = ack.id
+ repository.runTransactionForResult(UpdateNsIdExtendedBolusTransaction(pair.value))
+ .doOnError { error ->
+ aapsLogger.error(LTag.DATABASE, "Updated ns id of ExtendedBolus failed", error)
+ ret = Result.failure((workDataOf("Error" to error.toString())))
+ }
+ .doOnSuccess {
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ aapsLogger.debug(LTag.DATABASE, "Updated ns id of ExtendedBolus " + pair.value)
+ dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.updateRecordId)
+ }
+ .blockingGet()
+ rxBus.send(EventNSClientNewLog("DBADD", "Acked ExtendedBolus" + pair.value.interfaceIDs.nightscoutId))
+ // Send new if waiting
+ dataSyncSelector.processChangedTemporaryBasalsCompat()
+ }
+
+ is PairProfileSwitch -> {
+ val pair = ack.originalObject
+ pair.value.interfaceIDs.nightscoutId = ack.id
+ repository.runTransactionForResult(UpdateNsIdProfileSwitchTransaction(pair.value))
+ .doOnError { error ->
+ aapsLogger.error(LTag.DATABASE, "Updated ns id of ProfileSwitch failed", error)
+ ret = Result.failure((workDataOf("Error" to error.toString())))
+ }
+ .doOnSuccess {
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ aapsLogger.debug(LTag.DATABASE, "Updated ns id of ProfileSwitch " + pair.value)
+ dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.updateRecordId)
+ }
+ .blockingGet()
+ rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileSwitch" + pair.value.interfaceIDs.nightscoutId))
+ // Send new if waiting
+ dataSyncSelector.processChangedTemporaryBasalsCompat()
+ }
+
+ is DeviceStatus -> {
+ val deviceStatus = ack.originalObject
+ deviceStatus.interfaceIDs.nightscoutId = ack.id
+ repository.runTransactionForResult(UpdateNsIdDeviceStatusTransaction(deviceStatus))
+ .doOnError { error ->
+ aapsLogger.error(LTag.DATABASE, "Updated ns id of DeviceStatus failed", error)
+ ret = Result.failure((workDataOf("Error" to error.toString())))
+ }
+ .doOnSuccess {
+ ret = Result.success(workDataOf("ProcessedData" to deviceStatus.toString()))
+ aapsLogger.debug(LTag.DATABASE, "Updated ns id of DeviceStatus $deviceStatus")
+ dataSyncSelector.confirmLastDeviceStatusIdIfGreater(deviceStatus.id)
+ }
+ .blockingGet()
+ rxBus.send(EventNSClientNewLog("DBADD", "Acked DeviceStatus" + deviceStatus.interfaceIDs.nightscoutId))
+ // Send new if waiting
+ dataSyncSelector.processChangedDeviceStatusesCompat()
+ }
+ }
+ return ret
+ }
+
+ init {
+ (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddUpdateWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddUpdateWorker.kt
new file mode 100644
index 0000000000..83b19b2a16
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddUpdateWorker.kt
@@ -0,0 +1,353 @@
+package info.nightscout.androidaps.plugins.general.nsclient
+
+import android.content.Context
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import androidx.work.workDataOf
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.Constants
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.database.AppRepository
+import info.nightscout.androidaps.database.entities.TherapyEvent
+import info.nightscout.androidaps.database.entities.UserEntry.Action
+import info.nightscout.androidaps.database.entities.UserEntry.Sources
+import info.nightscout.androidaps.database.entities.ValueWithUnit
+import info.nightscout.androidaps.database.transactions.*
+import info.nightscout.androidaps.extensions.*
+import info.nightscout.androidaps.interfaces.Config
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.logging.UserEntryLogger
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
+import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
+import info.nightscout.androidaps.receivers.DataWorker
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.JsonHelper
+import info.nightscout.androidaps.utils.JsonHelper.safeGetLong
+import info.nightscout.androidaps.utils.buildHelper.BuildHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+
+class NSClientAddUpdateWorker(
+ context: Context,
+ params: WorkerParameters
+) : Worker(context, params) {
+
+ @Inject lateinit var nsClientPlugin: NSClientPlugin
+ @Inject lateinit var dataWorker: DataWorker
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var buildHelper: BuildHelper
+ @Inject lateinit var sp: SP
+ @Inject lateinit var dateUtil: DateUtil
+ @Inject lateinit var config: Config
+ @Inject lateinit var repository: AppRepository
+ @Inject lateinit var rxBus: RxBusWrapper
+ @Inject lateinit var uel: UserEntryLogger
+
+ override fun doWork(): Result {
+ val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT
+ if (!acceptNSData) return Result.success()
+
+ val treatments = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
+ ?: return Result.failure(workDataOf("Error" to "missing input data"))
+
+ var ret = Result.success()
+ var latestDateInReceivedData = 0L
+
+ for (i in 0 until treatments.length()) {
+ var json = treatments.getJSONObject(i)
+ // new DB model
+ val insulin = JsonHelper.safeGetDouble(json, "insulin")
+ val carbs = JsonHelper.safeGetDouble(json, "carbs")
+ val eventType = JsonHelper.safeGetString(json, "eventType")
+ if (eventType == null) {
+ aapsLogger.debug(LTag.NSCLIENT, "Wrong treatment. Ignoring : $json")
+ continue
+ }
+
+ //Find latest date in treatment
+ val mills = safeGetLong(json, "mills")
+ if (mills != 0L && mills < dateUtil.now())
+ if (mills > latestDateInReceivedData) latestDateInReceivedData = mills
+
+ if (insulin > 0) {
+ bolusFromJson(json)?.let { bolus ->
+ repository.runTransactionForResult(SyncNsBolusTransaction(bolus, invalidateByNsOnly = false))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.inserted.forEach {
+ uel.log(Action.BOLUS, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.Insulin(it.amount)
+ )
+ aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it")
+ }
+ result.invalidated.forEach {
+ uel.log(Action.BOLUS_REMOVED, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.Insulin(it.amount)
+ )
+ aapsLogger.debug(LTag.DATABASE, "Invalidated bolus $it")
+ }
+ result.updatedNsId.forEach {
+ aapsLogger.debug(LTag.DATABASE, "Updated nsId bolus $it")
+ }
+ }
+ } ?: aapsLogger.error("Error parsing bolus json $json")
+ }
+ if (carbs > 0) {
+ carbsFromJson(json)?.let { carb ->
+ repository.runTransactionForResult(SyncNsCarbsTransaction(carb, invalidateByNsOnly = false))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.inserted.forEach {
+ uel.log(Action.CARBS, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.Gram(it.amount.toInt())
+ )
+ aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it")
+ }
+ result.invalidated.forEach {
+ uel.log(Action.CARBS_REMOVED, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.Gram(it.amount.toInt())
+ )
+ aapsLogger.debug(LTag.DATABASE, "Invalidated carbs $it")
+ }
+ result.updatedNsId.forEach {
+ aapsLogger.debug(LTag.DATABASE, "Updated nsId carbs $it")
+ }
+ }
+ } ?: aapsLogger.error("Error parsing bolus json $json")
+ }
+ // Convert back emulated TBR -> EB
+ if (eventType == TherapyEvent.Type.TEMPORARY_BASAL.text && json.has("extendedEmulated")) {
+ val ebJson = json.getJSONObject("extendedEmulated")
+ ebJson.put("_id", json.getString("_id"))
+ ebJson.put("isValid", json.getBoolean("isValid"))
+ json = ebJson
+ }
+ when {
+ insulin > 0 || carbs > 0 -> Any()
+ eventType == TherapyEvent.Type.TEMPORARY_TARGET.text ->
+ temporaryTargetFromJson(json)?.let { temporaryTarget ->
+ repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget, invalidateByNsOnly = false))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.inserted.forEach { tt ->
+ uel.log(Action.TT, Sources.NSClient,
+ ValueWithUnit.TherapyEventTTReason(tt.reason),
+ ValueWithUnit.fromGlucoseUnit(tt.lowTarget, Constants.MGDL),
+ ValueWithUnit.fromGlucoseUnit(tt.highTarget, Constants.MGDL).takeIf { tt.lowTarget != tt.highTarget },
+ ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
+ )
+ aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryTarget $tt")
+ }
+ result.invalidated.forEach { tt ->
+ uel.log(Action.TT_REMOVED, Sources.NSClient,
+ ValueWithUnit.TherapyEventTTReason(tt.reason),
+ ValueWithUnit.Mgdl(tt.lowTarget),
+ ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
+ ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
+ )
+ aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryTarget $tt")
+ }
+ result.ended.forEach { tt ->
+ uel.log(Action.CANCEL_TT, Sources.NSClient,
+ ValueWithUnit.TherapyEventTTReason(tt.reason),
+ ValueWithUnit.Mgdl(tt.lowTarget),
+ ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
+ ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
+ )
+ aapsLogger.debug(LTag.DATABASE, "Updated TemporaryTarget $tt")
+ }
+ result.updatedNsId.forEach {
+ aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryTarget $it")
+ }
+ }
+ } ?: aapsLogger.error("Error parsing TT json $json")
+ eventType == TherapyEvent.Type.CANNULA_CHANGE.text ||
+ eventType == TherapyEvent.Type.INSULIN_CHANGE.text ||
+ eventType == TherapyEvent.Type.SENSOR_CHANGE.text ||
+ eventType == TherapyEvent.Type.FINGER_STICK_BG_VALUE.text ||
+ eventType == TherapyEvent.Type.NONE.text ||
+ eventType == TherapyEvent.Type.ANNOUNCEMENT.text ||
+ eventType == TherapyEvent.Type.QUESTION.text ||
+ eventType == TherapyEvent.Type.EXERCISE.text ||
+ eventType == TherapyEvent.Type.APS_OFFLINE.text ||
+ eventType == TherapyEvent.Type.PUMP_BATTERY_CHANGE.text ->
+ therapyEventFromJson(json)?.let { therapyEvent ->
+ repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent, invalidateByNsOnly = false))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ val action = when (eventType) {
+ TherapyEvent.Type.CANNULA_CHANGE.text -> Action.SITE_CHANGE
+ TherapyEvent.Type.INSULIN_CHANGE.text -> Action.RESERVOIR_CHANGE
+ else -> Action.CAREPORTAL
+ }
+ result.inserted.forEach {
+ uel.log(action, Sources.NSClient,
+ it.note ?: "",
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.TherapyEventType(it.type)
+ )
+ aapsLogger.debug(LTag.DATABASE, "Inserted TherapyEvent $it")
+ }
+ result.invalidated.forEach {
+ uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient,
+ it.note ?: "",
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.TherapyEventType(it.type)
+ )
+ aapsLogger.debug(LTag.DATABASE, "Invalidated TherapyEvent $it")
+ }
+ result.updatedNsId.forEach {
+ aapsLogger.debug(LTag.DATABASE, "Updated nsId TherapyEvent $it")
+ }
+ }
+ } ?: aapsLogger.error("Error parsing TherapyEvent json $json")
+ eventType == TherapyEvent.Type.COMBO_BOLUS.text ->
+ extendedBolusFromJson(json)?.let { extendedBolus ->
+ repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBolus, invalidateByNsOnly = false))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while saving extended bolus", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.inserted.forEach {
+ uel.log(Action.EXTENDED_BOLUS, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.Insulin(it.amount),
+ ValueWithUnit.UnitPerHour(it.rate),
+ ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
+ )
+ aapsLogger.debug(LTag.DATABASE, "Inserted ExtendedBolus $it")
+ }
+ result.invalidated.forEach {
+ uel.log(Action.EXTENDED_BOLUS_REMOVED, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.Insulin(it.amount),
+ ValueWithUnit.UnitPerHour(it.rate),
+ ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
+ )
+ aapsLogger.debug(LTag.DATABASE, "Invalidated ExtendedBolus $it")
+ }
+ result.ended.forEach {
+ uel.log(Action.CANCEL_EXTENDED_BOLUS, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.Insulin(it.amount),
+ ValueWithUnit.UnitPerHour(it.rate),
+ ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
+ )
+ aapsLogger.debug(LTag.DATABASE, "Updated ExtendedBolus $it")
+ }
+ result.updatedNsId.forEach {
+ aapsLogger.debug(LTag.DATABASE, "Updated nsId ExtendedBolus $it")
+ }
+ }
+ } ?: aapsLogger.error("Error parsing ExtendedBolus json $json")
+ eventType == TherapyEvent.Type.TEMPORARY_BASAL.text ->
+ temporaryBasalFromJson(json)?.let { temporaryBasal ->
+ repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasal, invalidateByNsOnly = false))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while saving temporary basal", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.inserted.forEach {
+ uel.log(Action.TEMP_BASAL, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.UnitPerHour(it.rate),
+ ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
+ )
+ aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it")
+ }
+ result.invalidated.forEach {
+ uel.log(Action.TEMP_BASAL_REMOVED, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.UnitPerHour(it.rate),
+ ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
+ )
+ aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryBasal $it")
+ }
+ result.ended.forEach {
+ uel.log(Action.CANCEL_TEMP_BASAL, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.UnitPerHour(it.rate),
+ ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
+ )
+ aapsLogger.debug(LTag.DATABASE, "Ended TemporaryBasal $it")
+ }
+ result.updatedNsId.forEach {
+ aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryBasal $it")
+ }
+ }
+ } ?: aapsLogger.error("Error parsing TemporaryBasal json $json")
+ eventType == TherapyEvent.Type.PROFILE_SWITCH.text ->
+ profileSwitchFromJson(json, dateUtil)?.let { profileSwitch ->
+ repository.runTransactionForResult(SyncNsProfileSwitchTransaction(profileSwitch, invalidateByNsOnly = false))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while saving ProfileSwitch", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.inserted.forEach {
+ uel.log(Action.PROFILE_SWITCH, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp))
+ aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it")
+ }
+ result.invalidated.forEach {
+ uel.log(Action.PROFILE_SWITCH_REMOVED, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp))
+ aapsLogger.debug(LTag.DATABASE, "Invalidated ProfileSwitch $it")
+ }
+ result.updatedNsId.forEach {
+ aapsLogger.debug(LTag.DATABASE, "Updated nsId ProfileSwitch $it")
+ }
+ }
+ } ?: aapsLogger.error("Error parsing TemporaryBasal json $json")
+ }
+ if (eventType == TherapyEvent.Type.ANNOUNCEMENT.text) {
+ val date = safeGetLong(json, "mills")
+ val now = System.currentTimeMillis()
+ val enteredBy = JsonHelper.safeGetString(json, "enteredBy", "")
+ val notes = JsonHelper.safeGetString(json, "notes", "")
+ if (date > now - 15 * 60 * 1000L && notes.isNotEmpty()
+ && enteredBy != sp.getString("careportal_enteredby", "AndroidAPS")) {
+ val defaultVal = config.NSCLIENT
+ if (sp.getBoolean(R.string.key_ns_announcements, defaultVal)) {
+ val announcement = Notification(Notification.NS_ANNOUNCEMENT, notes, Notification.ANNOUNCEMENT, 60)
+ rxBus.send(EventNewNotification(announcement))
+ }
+ }
+ }
+ }
+ nsClientPlugin.updateLatestDateReceivedIfNewer(latestDateInReceivedData)
+ return ret
+ }
+
+ init {
+ (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java
deleted file mode 100644
index 58bacbbf4c..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java
+++ /dev/null
@@ -1,168 +0,0 @@
-package info.nightscout.androidaps.plugins.general.nsclient;
-
-
-import android.graphics.Paint;
-import android.os.Bundle;
-import android.text.Spanned;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-import javax.inject.Inject;
-
-import dagger.android.support.DaggerFragment;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.logging.UserEntryLogger;
-import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
-import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog;
-import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart;
-import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI;
-import info.nightscout.androidaps.utils.FabricPrivacy;
-import info.nightscout.androidaps.utils.HtmlHelper;
-import info.nightscout.androidaps.utils.alertDialogs.OKDialog;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-import info.nightscout.androidaps.utils.rx.AapsSchedulers;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-import io.reactivex.disposables.CompositeDisposable;
-
-public class NSClientFragment extends DaggerFragment implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
- @Inject NSClientPlugin nsClientPlugin;
- @Inject SP sp;
- @Inject ResourceHelper resourceHelper;
- @Inject RxBusWrapper rxBus;
- @Inject UploadQueue uploadQueue;
- @Inject FabricPrivacy fabricPrivacy;
- @Inject AapsSchedulers aapsSchedulers;
- @Inject UserEntryLogger uel;
-
- private final CompositeDisposable disposable = new CompositeDisposable();
-
- private TextView logTextView;
- private TextView queueTextView;
- private TextView urlTextView;
- private TextView statusTextView;
- private TextView clearlog;
- private TextView restart;
- private TextView delivernow;
- private TextView clearqueue;
- private TextView showqueue;
- private ScrollView logScrollview;
- private CheckBox autoscrollCheckbox;
- private CheckBox pausedCheckbox;
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.nsclientinternal_fragment, container, false);
-
- logScrollview = view.findViewById(R.id.nsclientinternal_logscrollview);
- autoscrollCheckbox = view.findViewById(R.id.nsclientinternal_autoscroll);
- autoscrollCheckbox.setChecked(nsClientPlugin.autoscroll);
- autoscrollCheckbox.setOnCheckedChangeListener(this);
- pausedCheckbox = view.findViewById(R.id.nsclientinternal_paused);
- pausedCheckbox.setChecked(nsClientPlugin.paused);
- pausedCheckbox.setOnCheckedChangeListener(this);
- logTextView = view.findViewById(R.id.nsclientinternal_log);
- queueTextView = view.findViewById(R.id.nsclientinternal_queue);
- urlTextView = view.findViewById(R.id.nsclientinternal_url);
- statusTextView = view.findViewById(R.id.nsclientinternal_status);
-
- clearlog = view.findViewById(R.id.nsclientinternal_clearlog);
- clearlog.setOnClickListener(this);
- clearlog.setPaintFlags(clearlog.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
- restart = view.findViewById(R.id.nsclientinternal_restart);
- restart.setOnClickListener(this);
- restart.setPaintFlags(restart.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
- delivernow = view.findViewById(R.id.nsclientinternal_delivernow);
- delivernow.setOnClickListener(this);
- delivernow.setPaintFlags(delivernow.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
- clearqueue = view.findViewById(R.id.nsclientinternal_clearqueue);
- clearqueue.setOnClickListener(this);
- clearqueue.setPaintFlags(clearqueue.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
- showqueue = view.findViewById(R.id.nsclientinternal_showqueue);
- showqueue.setOnClickListener(this);
- showqueue.setPaintFlags(showqueue.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
-
- return view;
- }
-
- @Override
- public synchronized void onResume() {
- super.onResume();
- disposable.add(rxBus
- .toObservable(EventNSClientUpdateGUI.class)
- .observeOn(aapsSchedulers.getMain())
- .subscribe(event -> updateGui(), fabricPrivacy::logException)
- );
- updateGui();
- }
-
- @Override
- public synchronized void onPause() {
- super.onPause();
- disposable.clear();
- }
-
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.nsclientinternal_restart:
- rxBus.send(new EventNSClientRestart());
- fabricPrivacy.logCustom("NSClientRestart");
- break;
- case R.id.nsclientinternal_delivernow:
- nsClientPlugin.resend("GUI");
- fabricPrivacy.logCustom("NSClientDeliverNow");
- break;
- case R.id.nsclientinternal_clearlog:
- nsClientPlugin.clearLog();
- break;
- case R.id.nsclientinternal_clearqueue:
- OKDialog.showConfirmation(getContext(), resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), () -> {
- uel.log("NS QUEUE CLEARED", "", 0.0, 0.0, 0, 0);
- uploadQueue.clearQueue();
- updateGui();
- fabricPrivacy.logCustom("NSClientClearQueue");
- });
- break;
- case R.id.nsclientinternal_showqueue:
- rxBus.send(new EventNSClientNewLog("QUEUE", uploadQueue.textList()));
- break;
- }
- }
-
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- switch (buttonView.getId()) {
- case R.id.nsclientinternal_paused:
- uel.log("NS PAUSED", "", 0.0, 0.0, isChecked ? 1 : 0, 0);
- nsClientPlugin.pause(isChecked);
- updateGui();
- fabricPrivacy.logCustom("NSClientPause");
- break;
- case R.id.nsclientinternal_autoscroll:
- sp.putBoolean(R.string.key_nsclientinternal_autoscroll, isChecked);
- nsClientPlugin.autoscroll = isChecked;
- updateGui();
- break;
- }
- }
-
- protected void updateGui() {
- nsClientPlugin.updateLog();
- pausedCheckbox.setChecked(sp.getBoolean(R.string.key_nsclientinternal_paused, false));
- logTextView.setText(nsClientPlugin.textLog);
- if (nsClientPlugin.autoscroll) {
- logScrollview.fullScroll(ScrollView.FOCUS_DOWN);
- }
- urlTextView.setText(nsClientPlugin.url());
- Spanned queuetext = HtmlHelper.INSTANCE.fromHtml(resourceHelper.gs(R.string.queue) + " " + uploadQueue.size() + "");
- queueTextView.setText(queuetext);
- statusTextView.setText(nsClientPlugin.status);
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt
new file mode 100644
index 0000000000..d2e77a4f95
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt
@@ -0,0 +1,122 @@
+package info.nightscout.androidaps.plugins.general.nsclient
+
+import android.graphics.Paint
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ScrollView
+import dagger.android.support.DaggerFragment
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.database.entities.UserEntry.Action
+import info.nightscout.androidaps.database.entities.UserEntry.Sources
+import info.nightscout.androidaps.databinding.NsClientFragmentBinding
+import info.nightscout.androidaps.interfaces.DataSyncSelector
+import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface
+import info.nightscout.androidaps.logging.UserEntryLogger
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog
+import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
+import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
+import info.nightscout.androidaps.utils.FabricPrivacy
+import info.nightscout.androidaps.utils.HtmlHelper.fromHtml
+import info.nightscout.androidaps.utils.alertDialogs.OKDialog
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.rx.AapsSchedulers
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import io.reactivex.disposables.CompositeDisposable
+import javax.inject.Inject
+
+class NSClientFragment : DaggerFragment() {
+
+ @Inject lateinit var nsClientPlugin: NSClientPlugin
+ @Inject lateinit var sp: SP
+ @Inject lateinit var resourceHelper: ResourceHelper
+ @Inject lateinit var rxBus: RxBusWrapper
+ @Inject lateinit var uploadQueue: UploadQueueAdminInterface
+ @Inject lateinit var fabricPrivacy: FabricPrivacy
+ @Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var dataSyncSelector: DataSyncSelector
+ @Inject lateinit var uel: UserEntryLogger
+
+ private val disposable = CompositeDisposable()
+
+ private var _binding: NsClientFragmentBinding? = null
+
+ // This property is only valid between onCreateView and
+ // onDestroyView.
+ private val binding get() = _binding!!
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
+ NsClientFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ binding.autoscroll.isChecked = nsClientPlugin.autoscroll
+ binding.autoscroll.setOnCheckedChangeListener { _, isChecked ->
+ sp.putBoolean(R.string.key_nsclientinternal_autoscroll, isChecked)
+ nsClientPlugin.autoscroll = isChecked
+ updateGui()
+ }
+
+ binding.paused.isChecked = nsClientPlugin.paused
+ binding.paused.setOnCheckedChangeListener { _, isChecked ->
+ uel.log(if (isChecked) Action.NS_PAUSED else Action.NS_RESUME, Sources.NSClient)
+ nsClientPlugin.pause(isChecked)
+ updateGui()
+ }
+ binding.clearLog.setOnClickListener { nsClientPlugin.clearLog() }
+ binding.clearLog.paintFlags = binding.clearLog.paintFlags or Paint.UNDERLINE_TEXT_FLAG
+ binding.restart.setOnClickListener { rxBus.send(EventNSClientRestart()) }
+ binding.restart.paintFlags = binding.restart.paintFlags or Paint.UNDERLINE_TEXT_FLAG
+ binding.deliverNow.setOnClickListener { nsClientPlugin.resend("GUI") }
+ binding.deliverNow.paintFlags = binding.deliverNow.paintFlags or Paint.UNDERLINE_TEXT_FLAG
+ binding.clearQueue.setOnClickListener {
+ context?.let { context ->
+ OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), Runnable {
+ uel.log(Action.NS_QUEUE_CLEARED, Sources.NSClient)
+ uploadQueue.clearQueue()
+ updateGui()
+ })
+ }
+ }
+ binding.clearQueue.paintFlags = binding.clearQueue.paintFlags or Paint.UNDERLINE_TEXT_FLAG
+ binding.showQueue.setOnClickListener { rxBus.send(EventNSClientNewLog("QUEUE", uploadQueue.textList())) }
+ binding.showQueue.paintFlags = binding.showQueue.paintFlags or Paint.UNDERLINE_TEXT_FLAG
+ binding.fullSync.setOnClickListener {
+ context?.let { context ->
+ OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.full_sync), Runnable {
+ dataSyncSelector.resetToNextFullSync()
+ })
+ }
+ }
+ binding.fullSync.paintFlags = binding.fullSync.paintFlags or Paint.UNDERLINE_TEXT_FLAG
+ }
+
+ @Synchronized override fun onResume() {
+ super.onResume()
+ disposable.add(rxBus
+ .toObservable(EventNSClientUpdateGUI::class.java)
+ .observeOn(aapsSchedulers.main)
+ .subscribe({ updateGui() }, fabricPrivacy::logException)
+ )
+ updateGui()
+ }
+
+ @Synchronized override fun onPause() {
+ super.onPause()
+ disposable.clear()
+ }
+
+ private fun updateGui() {
+ if (_binding == null) return
+ nsClientPlugin.updateLog()
+ binding.paused.isChecked = sp.getBoolean(R.string.key_nsclientinternal_paused, false)
+ binding.log.text = nsClientPlugin.textLog
+ if (nsClientPlugin.autoscroll) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN)
+ binding.url.text = nsClientPlugin.url()
+ binding.queue.text = fromHtml(resourceHelper.gs(R.string.queue) + " " + uploadQueue.size() + "")
+ binding.status.text = nsClientPlugin.status
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt
new file mode 100644
index 0000000000..a769f2ec38
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt
@@ -0,0 +1,60 @@
+package info.nightscout.androidaps.plugins.general.nsclient
+
+import android.content.Context
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import androidx.work.workDataOf
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.database.AppRepository
+import info.nightscout.androidaps.database.transactions.SyncNsTherapyEventTransaction
+import info.nightscout.androidaps.interfaces.Config
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg
+import info.nightscout.androidaps.receivers.DataWorker
+import info.nightscout.androidaps.utils.buildHelper.BuildHelper
+import info.nightscout.androidaps.extensions.therapyEventFromNsMbg
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import javax.inject.Inject
+
+class NSClientMbgWorker(
+ context: Context,
+ params: WorkerParameters
+) : Worker(context, params) {
+
+ @Inject lateinit var repository: AppRepository
+ @Inject lateinit var dataWorker: DataWorker
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var sp: SP
+ @Inject lateinit var buildHelper: BuildHelper
+ @Inject lateinit var config: Config
+
+ override fun doWork(): Result {
+ var ret = Result.success()
+
+ val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT
+ if (!acceptNSData) return ret
+
+ val mbgArray = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
+ ?: return Result.failure(workDataOf("Error" to "missing input data"))
+ for (i in 0 until mbgArray.length()) {
+ val nsMbg = NSMbg(mbgArray.getJSONObject(i))
+ if (!nsMbg.isValid()) continue
+ repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEventFromNsMbg(nsMbg), false))
+ .doOnError {
+ aapsLogger.error("Error while saving therapy event", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also {
+ aapsLogger.debug(LTag.DATABASE, "Saved therapy event $it")
+ }
+ }
+ return ret
+ }
+
+ init {
+ (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java
index de1b919ed1..ae28f50b36 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientPlugin.java
@@ -4,20 +4,16 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.text.Spanned;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreference;
-import org.jetbrains.annotations.NotNull;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
import java.util.ArrayList;
import java.util.List;
@@ -25,17 +21,13 @@ import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.interfaces.Config;
import info.nightscout.androidaps.Constants;
-import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventChargingState;
import info.nightscout.androidaps.events.EventNetworkChange;
-import info.nightscout.androidaps.events.EventNsTreatment;
import info.nightscout.androidaps.events.EventPreferenceChange;
-import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
@@ -44,18 +36,13 @@ import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.general.nsclient.data.AlarmAck;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm;
-import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientResend;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI;
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService;
-import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
-import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
-import info.nightscout.androidaps.services.Intents;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.HtmlHelper;
-import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.ToastUtils;
import info.nightscout.androidaps.utils.buildHelper.BuildHelper;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
@@ -74,10 +61,9 @@ public class NSClientPlugin extends PluginBase {
private final AapsSchedulers aapsSchedulers;
private final FabricPrivacy fabricPrivacy;
private final SP sp;
+ private final NsClientReceiverDelegate nsClientReceiverDelegate;
private final Config config;
private final BuildHelper buildHelper;
- private final ActivePluginProvider activePlugin;
- private final NSUpload nsUpload;
public Handler handler;
@@ -89,9 +75,8 @@ public class NSClientPlugin extends PluginBase {
public String status = "";
- public NSClientService nsClientService = null;
+ public @Nullable NSClientService nsClientService = null;
- private final NsClientReceiverDelegate nsClientReceiverDelegate;
@Inject
public NSClientPlugin(
@@ -105,9 +90,7 @@ public class NSClientPlugin extends PluginBase {
SP sp,
NsClientReceiverDelegate nsClientReceiverDelegate,
Config config,
- BuildHelper buildHelper,
- ActivePluginProvider activePlugin,
- NSUpload nsUpload
+ BuildHelper buildHelper
) {
super(new PluginDescription()
.mainType(PluginType.GENERAL)
@@ -130,8 +113,6 @@ public class NSClientPlugin extends PluginBase {
this.nsClientReceiverDelegate = nsClientReceiverDelegate;
this.config = config;
this.buildHelper = buildHelper;
- this.activePlugin = activePlugin;
- this.nsUpload = nsUpload;
if (config.getNSCLIENT()) {
getPluginDescription().alwaysEnabled(true).visibleByDefault(true);
@@ -170,12 +151,12 @@ public class NSClientPlugin extends PluginBase {
disposable.add(rxBus
.toObservable(EventNetworkChange.class)
.observeOn(aapsSchedulers.getIo())
- .subscribe(event -> nsClientReceiverDelegate.onStatusEvent(event), fabricPrivacy::logException)
+ .subscribe(nsClientReceiverDelegate::onStatusEvent, fabricPrivacy::logException)
);
disposable.add(rxBus
.toObservable(EventPreferenceChange.class)
.observeOn(aapsSchedulers.getIo())
- .subscribe(event -> nsClientReceiverDelegate.onStatusEvent(event), fabricPrivacy::logException)
+ .subscribe(nsClientReceiverDelegate::onStatusEvent, fabricPrivacy::logException)
);
disposable.add(rxBus
.toObservable(EventAppExit.class)
@@ -197,7 +178,7 @@ public class NSClientPlugin extends PluginBase {
disposable.add(rxBus
.toObservable(EventChargingState.class)
.observeOn(aapsSchedulers.getIo())
- .subscribe(event -> nsClientReceiverDelegate.onStatusEvent(event), fabricPrivacy::logException)
+ .subscribe(nsClientReceiverDelegate::onStatusEvent, fabricPrivacy::logException)
);
disposable.add(rxBus
.toObservable(EventNSClientResend.class)
@@ -214,7 +195,7 @@ public class NSClientPlugin extends PluginBase {
}
@Override
- public void preprocessPreferences(@NotNull PreferenceFragmentCompat preferenceFragment) {
+ public void preprocessPreferences(@NonNull PreferenceFragmentCompat preferenceFragment) {
super.preprocessPreferences(preferenceFragment);
if (config.getNSCLIENT()) {
@@ -236,7 +217,7 @@ public class NSClientPlugin extends PluginBase {
SwitchPreference key_ns_sync_use_absolute = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_sync_use_absolute));
if (key_ns_sync_use_absolute != null) key_ns_sync_use_absolute.setVisible(false);
} else {
- // APS or pumpcontrol mode
+ // APS or pumpControl mode
SwitchPreference key_ns_upload_only = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_ns_upload_only));
if (key_ns_upload_only != null)
key_ns_upload_only.setVisible(buildHelper.isEngineeringMode());
@@ -332,143 +313,8 @@ public class NSClientPlugin extends PluginBase {
nsClientService.sendAlarmAck(ack);
}
- // Parsing input data
-
- public void handleNewDataFromNSClient(String action, Bundle bundle) {
- boolean acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.getNSCLIENT();
- if (!acceptNSData) return;
- aapsLogger.debug(LTag.DATASERVICE, "Got intent: " + action);
-
- if (action.equals(Intents.ACTION_NEW_TREATMENT) || action.equals(Intents.ACTION_CHANGED_TREATMENT)) {
- try {
- if (bundle.containsKey("treatment")) {
- JSONObject json = new JSONObject(bundle.getString("treatment"));
- handleTreatmentFromNS(json, action);
- }
- if (bundle.containsKey("treatments")) {
- String trstring = bundle.getString("treatments");
- JSONArray jsonArray = new JSONArray(trstring);
- for (int i = 0; i < jsonArray.length(); i++) {
- JSONObject json = jsonArray.getJSONObject(i);
- handleTreatmentFromNS(json, action);
- }
- }
- } catch (JSONException e) {
- aapsLogger.error(LTag.DATASERVICE, "Unhandled exception", e);
- }
- }
-
- if (action.equals(Intents.ACTION_REMOVED_TREATMENT)) {
- try {
- if (bundle.containsKey("treatment")) {
- String trstring = bundle.getString("treatment");
- JSONObject json = new JSONObject(trstring);
- handleRemovedTreatmentFromNS(json);
- }
-
- if (bundle.containsKey("treatments")) {
- String trstring = bundle.getString("treatments");
- JSONArray jsonArray = new JSONArray(trstring);
- for (int i = 0; i < jsonArray.length(); i++) {
- JSONObject json = jsonArray.getJSONObject(i);
- handleRemovedTreatmentFromNS(json);
- }
- }
- } catch (JSONException e) {
- aapsLogger.error(LTag.DATASERVICE, "Unhandled exception", e);
- }
- }
-
- if (action.equals(Intents.ACTION_NEW_MBG)) {
- try {
- if (bundle.containsKey("mbg")) {
- String mbgstring = bundle.getString("mbg");
- JSONObject mbgJson = new JSONObject(mbgstring);
- storeMbg(mbgJson);
- }
-
- if (bundle.containsKey("mbgs")) {
- String sgvstring = bundle.getString("mbgs");
- JSONArray jsonArray = new JSONArray(sgvstring);
- for (int i = 0; i < jsonArray.length(); i++) {
- JSONObject mbgJson = jsonArray.getJSONObject(i);
- storeMbg(mbgJson);
- }
- }
- } catch (Exception e) {
- aapsLogger.error(LTag.DATASERVICE, "Unhandled exception", e);
- }
- }
- }
-
- private void handleRemovedTreatmentFromNS(JSONObject json) {
- // new DB model
- EventNsTreatment evtTreatment = new EventNsTreatment(EventNsTreatment.Companion.getREMOVE(), json);
- rxBus.send(evtTreatment);
- // old DB model
- String _id = JsonHelper.safeGetString(json, "_id");
- MainApp.getDbHelper().deleteTempTargetById(_id);
- MainApp.getDbHelper().deleteTempBasalById(_id);
- MainApp.getDbHelper().deleteExtendedBolusById(_id);
- MainApp.getDbHelper().deleteCareportalEventById(_id);
- MainApp.getDbHelper().deleteProfileSwitchById(_id);
- }
-
- private void handleTreatmentFromNS(JSONObject json, String action) {
- // new DB model
- int mode = Intents.ACTION_NEW_TREATMENT.equals(action) ? EventNsTreatment.Companion.getADD() : EventNsTreatment.Companion.getUPDATE();
- double insulin = JsonHelper.safeGetDouble(json, "insulin");
- double carbs = JsonHelper.safeGetDouble(json, "carbs");
- String eventType = JsonHelper.safeGetString(json, "eventType");
- if (eventType == null) {
- aapsLogger.debug(LTag.DATASERVICE, "Wrong treatment. Ignoring : " + json.toString());
- return;
- }
- if (insulin > 0 || carbs > 0) {
- EventNsTreatment evtTreatment = new EventNsTreatment(mode, json);
- rxBus.send(evtTreatment);
- } else if (eventType.equals(CareportalEvent.TEMPORARYTARGET)) {
- MainApp.getDbHelper().createTemptargetFromJsonIfNotExists(json);
- } else if (eventType.equals(CareportalEvent.TEMPBASAL)) {
- MainApp.getDbHelper().createTempBasalFromJsonIfNotExists(json);
- } else if (eventType.equals(CareportalEvent.COMBOBOLUS)) {
- MainApp.getDbHelper().createExtendedBolusFromJsonIfNotExists(json);
- } else if (eventType.equals(CareportalEvent.PROFILESWITCH)) {
- MainApp.getDbHelper().createProfileSwitchFromJsonIfNotExists(activePlugin, nsUpload, json);
- } else if (eventType.equals(CareportalEvent.SITECHANGE) ||
- eventType.equals(CareportalEvent.INSULINCHANGE) ||
- eventType.equals(CareportalEvent.SENSORCHANGE) ||
- eventType.equals(CareportalEvent.BGCHECK) ||
- eventType.equals(CareportalEvent.NOTE) ||
- eventType.equals(CareportalEvent.NONE) ||
- eventType.equals(CareportalEvent.ANNOUNCEMENT) ||
- eventType.equals(CareportalEvent.QUESTION) ||
- eventType.equals(CareportalEvent.EXERCISE) ||
- eventType.equals(CareportalEvent.OPENAPSOFFLINE) ||
- eventType.equals(CareportalEvent.PUMPBATTERYCHANGE)) {
- MainApp.getDbHelper().createCareportalEventFromJsonIfNotExists(json);
- }
-
- if (eventType.equals(CareportalEvent.ANNOUNCEMENT)) {
- long date = JsonHelper.safeGetLong(json, "mills");
- long now = System.currentTimeMillis();
- String enteredBy = JsonHelper.safeGetString(json, "enteredBy", "");
- String notes = JsonHelper.safeGetString(json, "notes", "");
- if (date > now - 15 * 60 * 1000L && !notes.isEmpty()
- && !enteredBy.equals(sp.getString("careportal_enteredby", "AndroidAPS"))) {
- boolean defaultVal = config.getNSCLIENT();
- if (sp.getBoolean(R.string.key_ns_announcements, defaultVal)) {
- Notification announcement = new Notification(Notification.NSANNOUNCEMENT, notes, Notification.ANNOUNCEMENT, 60);
- rxBus.send(new EventNewNotification(announcement));
- }
- }
- }
- }
-
- private void storeMbg(JSONObject mbgJson) {
- NSMbg nsMbg = new NSMbg(mbgJson);
- CareportalEvent careportalEvent = new CareportalEvent(nsMbg);
- MainApp.getDbHelper().createOrUpdate(careportalEvent);
- aapsLogger.debug(LTag.DATASERVICE, "Adding/Updating new MBG: " + careportalEvent.toString());
+ public void updateLatestDateReceivedIfNewer(long latestReceived) {
+ if (nsClientService != null && latestReceived > nsClientService.latestDateInReceivedData)
+ nsClientService.latestDateInReceivedData = latestReceived;
}
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientRemoveWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientRemoveWorker.kt
new file mode 100644
index 0000000000..a2423de9ce
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientRemoveWorker.kt
@@ -0,0 +1,181 @@
+package info.nightscout.androidaps.plugins.general.nsclient
+
+import android.content.Context
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import androidx.work.workDataOf
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.database.AppRepository
+import info.nightscout.androidaps.database.entities.UserEntry.Action
+import info.nightscout.androidaps.database.entities.UserEntry.Sources
+import info.nightscout.androidaps.database.entities.ValueWithUnit
+import info.nightscout.androidaps.database.transactions.*
+import info.nightscout.androidaps.extensions.*
+import info.nightscout.androidaps.interfaces.Config
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.logging.UserEntryLogger
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.receivers.DataWorker
+import info.nightscout.androidaps.utils.JsonHelper
+import info.nightscout.androidaps.utils.buildHelper.BuildHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+
+// This will not be needed fpr NS v3
+// Now NS provides on _id of removed records
+
+class NSClientRemoveWorker(
+ context: Context,
+ params: WorkerParameters) : Worker(context, params) {
+
+ @Inject lateinit var nsClientPlugin: NSClientPlugin
+ @Inject lateinit var dataWorker: DataWorker
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var buildHelper: BuildHelper
+ @Inject lateinit var sp: SP
+ @Inject lateinit var config: Config
+ @Inject lateinit var repository: AppRepository
+ @Inject lateinit var rxBus: RxBusWrapper
+ @Inject lateinit var uel: UserEntryLogger
+
+ override fun doWork(): Result {
+ val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT
+ if (!acceptNSData) return Result.success()
+
+ var ret = Result.success()
+
+ val treatments = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
+ ?: return Result.failure(workDataOf("Error" to "missing input data"))
+
+ for (i in 0 until treatments.length()) {
+ val json = treatments.getJSONObject(i)
+ val nsId = JsonHelper.safeGetString(json, "_id") ?: continue
+
+ // room Temporary target
+ val temporaryTarget = temporaryTargetFromNsIdForInvalidating(nsId)
+ repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget, invalidateByNsOnly = true))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary target", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.invalidated.forEach { tt ->
+ uel.log(
+ Action.TT_REMOVED, Sources.NSClient,
+ ValueWithUnit.TherapyEventTTReason(tt.reason),
+ ValueWithUnit.Mgdl(tt.lowTarget),
+ ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
+ ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt()).takeIf { tt.duration != 0L }
+ )
+ }
+ }
+
+ // room Therapy Event
+ val therapyEvent = therapyEventFromNsIdForInvalidating(nsId)
+ repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent, invalidateByNsOnly = true))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while invalidating therapy event", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.invalidated.forEach {
+ uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient,
+ (it.note ?: ""),
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.TherapyEventType(it.type))
+ }
+ }
+
+ // room Bolus
+ val bolus = bolusFromNsIdForInvalidating(nsId)
+ repository.runTransactionForResult(SyncNsBolusTransaction(bolus, invalidateByNsOnly = true))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while invalidating bolus", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.invalidated.forEach {
+ uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.Insulin(it.amount))
+ }
+ }
+
+ // room Carbs
+ val carbs = carbsFromNsIdForInvalidating(nsId)
+ repository.runTransactionForResult(SyncNsCarbsTransaction(carbs, invalidateByNsOnly = true))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while invalidating carbs", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.invalidated.forEach {
+ uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.Gram(it.amount.toInt()))
+ }
+ }
+
+ // room TemporaryBasal
+ val temporaryBasal = temporaryBasalFromNsIdForInvalidating(nsId)
+ repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasal, invalidateByNsOnly = true))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.invalidated.forEach {
+ uel.log(
+ Action.CAREPORTAL_REMOVED, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.UnitPerHour(it.rate))
+ }
+ }
+ // room ExtendedBolus
+ val extendedBolus = extendedBolusFromNsIdForInvalidating(nsId)
+ repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBolus, invalidateByNsOnly = true))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while invalidating extended bolus", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.invalidated.forEach {
+ uel.log(
+ Action.CAREPORTAL_REMOVED, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp),
+ ValueWithUnit.UnitPerHour(it.rate))
+ }
+ }
+
+ // room ProfileSwitch
+ repository.runTransactionForResult(InvalidateNsIdProfileSwitchTransaction(nsId))
+ .doOnError {
+ aapsLogger.error(LTag.DATABASE, "Error while invalidating ProfileSwitch", it)
+ ret = Result.failure(workDataOf("Error" to it.toString()))
+ }
+ .blockingGet()
+ .also { result ->
+ result.invalidated.forEach {
+ uel.log(
+ Action.CAREPORTAL_REMOVED, Sources.NSClient,
+ ValueWithUnit.Timestamp(it.timestamp))
+ }
+ }
+ }
+
+ return ret
+ }
+
+ init {
+ (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientUpdateRemoveAckWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientUpdateRemoveAckWorker.kt
new file mode 100644
index 0000000000..cd818d4461
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientUpdateRemoveAckWorker.kt
@@ -0,0 +1,135 @@
+package info.nightscout.androidaps.plugins.general.nsclient
+
+import android.content.Context
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import androidx.work.workDataOf
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.database.AppRepository
+import info.nightscout.androidaps.interfaces.DataSyncSelector
+import info.nightscout.androidaps.interfaces.DataSyncSelector.*
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.general.nsclient.acks.NSUpdateAck
+import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog
+import info.nightscout.androidaps.receivers.DataWorker
+import info.nightscout.androidaps.utils.rx.AapsSchedulers
+import javax.inject.Inject
+
+class NSClientUpdateRemoveAckWorker(
+ context: Context,
+ params: WorkerParameters
+) : Worker(context, params) {
+
+ @Inject lateinit var dataWorker: DataWorker
+ @Inject lateinit var aapsLogger: AAPSLogger
+ @Inject lateinit var repository: AppRepository
+ @Inject lateinit var rxBus: RxBusWrapper
+ @Inject lateinit var dataSyncSelector: DataSyncSelector
+ @Inject lateinit var aapsSchedulers: AapsSchedulers
+
+ override fun doWork(): Result {
+ var ret = Result.success()
+
+ val ack = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as NSUpdateAck?
+ ?: return Result.failure(workDataOf("Error" to "missing input data"))
+
+ // new room way
+ when (ack.originalObject) {
+ is PairTemporaryTarget -> {
+ val pair = ack.originalObject
+ dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.updateRecordId)
+ rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked TemporaryTarget" + ack._id))
+ // Send new if waiting
+ dataSyncSelector.processChangedTempTargetsCompat()
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ }
+
+ is PairGlucoseValue -> {
+ val pair = ack.originalObject
+ dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.updateRecordId)
+ rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked GlucoseValue " + ack._id))
+ // Send new if waiting
+ dataSyncSelector.processChangedGlucoseValuesCompat()
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ }
+
+ is PairFood -> {
+ val pair = ack.originalObject
+ dataSyncSelector.confirmLastFoodIdIfGreater(pair.updateRecordId)
+ rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked Food " + ack._id))
+ // Send new if waiting
+ dataSyncSelector.processChangedFoodsCompat()
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ }
+
+ is PairTherapyEvent -> {
+ val pair = ack.originalObject
+ dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.updateRecordId)
+ rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked TherapyEvent " + ack._id))
+ // Send new if waiting
+ dataSyncSelector.processChangedTherapyEventsCompat()
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ }
+
+ is PairBolus -> {
+ val pair = ack.originalObject
+ dataSyncSelector.confirmLastBolusIdIfGreater(pair.updateRecordId)
+ rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked Bolus " + ack._id))
+ // Send new if waiting
+ dataSyncSelector.processChangedBolusesCompat()
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ }
+
+ is PairCarbs -> {
+ val pair = ack.originalObject
+ dataSyncSelector.confirmLastCarbsIdIfGreater(pair.updateRecordId)
+ rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked Carbs " + ack._id))
+ // Send new if waiting
+ dataSyncSelector.processChangedCarbsCompat()
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ }
+
+ is PairBolusCalculatorResult -> {
+ val pair = ack.originalObject
+ dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.updateRecordId)
+ rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked BolusCalculatorResult " + ack._id))
+ // Send new if waiting
+ dataSyncSelector.processChangedBolusCalculatorResultsCompat()
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ }
+
+ is PairTemporaryBasal -> {
+ val pair = ack.originalObject
+ dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.updateRecordId)
+ rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked TemporaryBasal " + ack._id))
+ // Send new if waiting
+ dataSyncSelector.processChangedTemporaryBasalsCompat()
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ }
+
+ is PairExtendedBolus -> {
+ val pair = ack.originalObject
+ dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.updateRecordId)
+ rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked ExtendedBolus " + ack._id))
+ // Send new if waiting
+ dataSyncSelector.processChangedExtendedBolusesCompat()
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ }
+
+ is PairProfileSwitch -> {
+ val pair = ack.originalObject
+ dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.updateRecordId)
+ rxBus.send(EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked ProfileSwitch " + ack._id))
+ // Send new if waiting
+ dataSyncSelector.processChangedProfileSwitchesCompat()
+ ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
+ }
+ }
+ return ret
+ }
+
+ init {
+ (context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientWorker.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientWorker.java
deleted file mode 100644
index b36557c534..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientWorker.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package info.nightscout.androidaps.plugins.general.nsclient;
-
-import android.content.Context;
-import android.os.Bundle;
-
-import androidx.annotation.NonNull;
-import androidx.work.Worker;
-import androidx.work.WorkerParameters;
-
-import org.jetbrains.annotations.NotNull;
-
-import javax.inject.Inject;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.receivers.BundleStore;
-import info.nightscout.androidaps.receivers.DataReceiver;
-
-// cannot be inner class because of needed injection
-public class NSClientWorker extends Worker {
-
- public NSClientWorker(
- @NonNull Context context,
- @NonNull WorkerParameters params) {
- super(context, params);
- ((HasAndroidInjector) context.getApplicationContext()).androidInjector().inject(this);
- }
-
- @Inject NSClientPlugin nsClientPlugin;
- @Inject BundleStore bundleStore;
-
- @NotNull
- @Override
- public Result doWork() {
- Bundle bundle = bundleStore.pickup(getInputData().getLong(DataReceiver.STORE_KEY, -1));
- if (bundle == null) return Result.failure();
- String action = getInputData().getString(DataReceiver.ACTION_KEY);
- nsClientPlugin.handleNewDataFromNSClient(action, bundle);
- return Result.success();
- }
-}
-
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/UploadQueue.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/UploadQueue.java
index 08fecd9283..f7669b182d 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/UploadQueue.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/UploadQueue.java
@@ -11,12 +11,11 @@ import org.json.JSONObject;
import java.sql.SQLException;
-import javax.inject.Inject;
-
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.db.DbRequest;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
+import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface;
import info.nightscout.androidaps.interfaces.UploadQueueInterface;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
@@ -28,14 +27,13 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP;
/**
* Created by mike on 21.02.2016.
*/
-public class UploadQueue implements UploadQueueInterface {
+public class UploadQueue implements UploadQueueAdminInterface {
private final AAPSLogger aapsLogger;
private final DatabaseHelperInterface databaseHelper;
private final Context context;
private final SP sp;
private final RxBusWrapper rxBus;
- @Inject
public UploadQueue(
AAPSLogger aapsLogger,
DatabaseHelperInterface databaseHelper,
@@ -54,6 +52,7 @@ public class UploadQueue implements UploadQueueInterface {
return "QUEUE: " + databaseHelper.size(DatabaseHelper.DATABASE_DBREQUESTS);
}
+ @Override
public long size() {
return databaseHelper.size(DatabaseHelper.DATABASE_DBREQUESTS);
}
@@ -76,7 +75,7 @@ public class UploadQueue implements UploadQueueInterface {
rxBus.send(new EventNSClientResend("newdata"));
}
- void clearQueue() {
+ @Override public void clearQueue() {
startService();
if (NSClientService.handler != null) {
NSClientService.handler.post(() -> {
@@ -87,28 +86,8 @@ public class UploadQueue implements UploadQueueInterface {
}
}
- public void removeID(final JSONObject record) {
- startService();
- if (NSClientService.handler != null) {
- NSClientService.handler.post(() -> {
- try {
- String id;
- if (record.has("NSCLIENT_ID")) {
- id = record.getString("NSCLIENT_ID");
- } else {
- return;
- }
- if (databaseHelper.deleteDbRequest(id) == 1) {
- aapsLogger.debug(LTag.NSCLIENT, "Removed item from UploadQueue. " + status());
- }
- } catch (JSONException e) {
- aapsLogger.error("Unhandled exception", e);
- }
- });
- }
- }
-
- public void removeID(final String action, final String _id) {
+ @Override
+ public void removeByMongoId(final String action, final String _id) {
if (_id == null || _id.equals(""))
return;
startService();
@@ -120,11 +99,11 @@ public class UploadQueue implements UploadQueueInterface {
}
}
- String textList() {
+ @Override public String textList() {
String result = "";
CloseableIterator iterator;
try {
- iterator = databaseHelper.getDbRequestInterator();
+ iterator = databaseHelper.getDbRequestIterator();
try {
while (iterator.hasNext()) {
DbRequest dbr = iterator.next();
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSAddAck.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSAddAck.java
deleted file mode 100644
index dbd9151938..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSAddAck.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package info.nightscout.androidaps.plugins.general.nsclient.acks;
-
-import org.json.JSONArray;
-import org.json.JSONObject;
-
-import info.nightscout.androidaps.events.Event;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
-import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart;
-import io.socket.client.Ack;
-
-/**
- * Created by mike on 29.12.2015.
- */
-public class NSAddAck extends Event implements Ack {
- private final AAPSLogger aapsLogger;
- private final RxBusWrapper rxBus;
-
- public String _id = null;
- public String nsClientID = null;
- public JSONObject json = null;
-
- public NSAddAck(AAPSLogger aapsLogger, RxBusWrapper rxBus) {
- this.aapsLogger = aapsLogger;
- this.rxBus = rxBus;
- }
-
- public void call(Object... args) {
- // Regular response
- try {
- JSONArray responsearray = (JSONArray) (args[0]);
- JSONObject response;
- if (responsearray.length() > 0) {
- response = responsearray.getJSONObject(0);
- _id = response.getString("_id");
- json = response;
- if (response.has("NSCLIENT_ID")) {
- nsClientID = response.getString("NSCLIENT_ID");
- }
- }
- rxBus.send(this);
- return;
- } catch (Exception e) {
- aapsLogger.error("Unhandled exception", e);
- }
- // Check for not authorized
- try {
- JSONObject response = (JSONObject) (args[0]);
- if (response.has("result")) {
- _id = null;
- if (response.getString("result").contains("Not")) {
- rxBus.send(new EventNSClientRestart());
- return;
- }
- aapsLogger.debug(LTag.NSCLIENT, "DBACCESS " + response.getString("result"));
- }
- } catch (Exception e) {
- aapsLogger.error("Unhandled exception", e);
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSAddAck.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSAddAck.kt
new file mode 100644
index 0000000000..930defad05
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSAddAck.kt
@@ -0,0 +1,54 @@
+package info.nightscout.androidaps.plugins.general.nsclient.acks
+
+import info.nightscout.androidaps.events.Event
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
+import io.socket.client.Ack
+import org.json.JSONArray
+import org.json.JSONObject
+
+class NSAddAck(
+ private val aapsLogger: AAPSLogger,
+ private val rxBus: RxBusWrapper,
+ val originalObject: Any? = null
+) : Event(), Ack {
+
+ var id: String? = null
+ @JvmField var nsClientID: String? = null
+ @JvmField var json: JSONObject? = null
+ override fun call(vararg args: Any) {
+ // Regular response
+ try {
+ val responseArray = args[0] as JSONArray
+ val response: JSONObject
+ if (responseArray.length() > 0) {
+ response = responseArray.getJSONObject(0)
+ id = response.getString("_id")
+ json = response
+ if (response.has("NSCLIENT_ID")) {
+ nsClientID = response.getString("NSCLIENT_ID")
+ }
+ }
+ rxBus.send(this)
+ return
+ } catch (e: Exception) {
+ aapsLogger.error("Unhandled exception", e)
+ }
+ // Check for not authorized
+ try {
+ val response = args[0] as JSONObject
+ if (response.has("result")) {
+ id = null
+ if (response.getString("result").contains("Not")) {
+ rxBus.send(EventNSClientRestart())
+ return
+ }
+ aapsLogger.debug(LTag.NSCLIENT, "DBACCESS " + response.getString("result"))
+ }
+ } catch (e: Exception) {
+ aapsLogger.error("Unhandled exception", e)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSUpdateAck.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSUpdateAck.java
deleted file mode 100644
index 95a00279cf..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSUpdateAck.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package info.nightscout.androidaps.plugins.general.nsclient.acks;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import info.nightscout.androidaps.events.Event;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
-import io.socket.client.Ack;
-
-/**
- * Created by mike on 21.02.2016.
- */
-public class NSUpdateAck extends Event implements Ack {
- private final AAPSLogger aapsLogger;
- private final RxBusWrapper rxBus;
-
- public boolean result = false;
- public String _id;
- public String action;
-
- public void call(Object... args) {
- JSONObject response = (JSONObject) args[0];
- if (response.has("result"))
- try {
- if (response.getString("result").equals("success"))
- result = true;
- else if (response.getString("result").equals("Missing _id")) {
- result = true;
- aapsLogger.debug(LTag.NSCLIENT, "Internal error: Missing _id returned on dbUpdate ack");
- }
- rxBus.send(this);
- } catch (JSONException e) {
- aapsLogger.error("Unhandled exception", e);
- }
- }
-
- public NSUpdateAck(String action, String _id, AAPSLogger aapsLogger, RxBusWrapper rxBus) {
- super();
- this.action = action;
- this._id = _id;
- this.aapsLogger = aapsLogger;
- this.rxBus = rxBus;
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSUpdateAck.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSUpdateAck.kt
new file mode 100644
index 0000000000..5d91178f82
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/acks/NSUpdateAck.kt
@@ -0,0 +1,37 @@
+package info.nightscout.androidaps.plugins.general.nsclient.acks
+
+import info.nightscout.androidaps.events.Event
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.bus.RxBusWrapper
+import io.socket.client.Ack
+import org.json.JSONException
+import org.json.JSONObject
+
+/**
+ * Created by mike on 21.02.2016.
+ */
+class NSUpdateAck(
+ val action : String,
+ var _id: String,
+ private val aapsLogger: AAPSLogger,
+ private val rxBus: RxBusWrapper,
+ val originalObject: Any? = null
+) : Event(), Ack {
+
+ var result = false
+ override fun call(vararg args: Any) {
+ val response = args[0] as JSONObject
+ if (response.has("result")) try {
+ if (response.getString("result") == "success") {
+ result = true
+ } else if (response.getString("result") == "Missing _id") {
+ result = true
+ aapsLogger.debug(LTag.NSCLIENT, "Internal error: Missing _id returned on dbUpdate ack")
+ }
+ rxBus.send(this)
+ } catch (e: JSONException) {
+ aapsLogger.error("Unhandled exception", e)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.java
deleted file mode 100644
index 6d50c67e3a..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.java
+++ /dev/null
@@ -1,481 +0,0 @@
-package info.nightscout.androidaps.plugins.general.nsclient.data;
-
-import android.text.Spanned;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.interfaces.ConfigInterface;
-import info.nightscout.androidaps.logging.AAPSLogger;
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.plugins.aps.loop.APSResult;
-import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration;
-import info.nightscout.androidaps.utils.DateUtil;
-import info.nightscout.androidaps.utils.HtmlHelper;
-import info.nightscout.androidaps.utils.Round;
-import info.nightscout.androidaps.utils.resources.ResourceHelper;
-import info.nightscout.androidaps.utils.sharedPreferences.SP;
-
-/**
- * Created by mike on 25.06.2017.
- */
-
-/*
-{
- "_id": "594fdcec327b83c81b6b8c0f",
- "device": "openaps://Sony D5803",
- "pump": {
- "battery": {
- "percent": 100
- },
- "status": {
- "status": "normal",
- "timestamp": "2017-06-25T15:50:14Z"
- },
- "extended": {
- "Version": "1.5-ac98852-2017.06.25",
- "PumpIOB": 1.13,
- "LastBolus": "25. 6. 2017 17:25:00",
- "LastBolusAmount": 0.3,
- "BaseBasalRate": 0.4,
- "ActiveProfile": "2016 +30%"
- },
- "reservoir": 109,
- "clock": "2017-06-25T15:55:10Z"
- },
- "openaps": {
- "suggested": {
- "temp": "absolute",
- "bg": 115.9,
- "tick": "+5",
- "eventualBG": 105,
- "snoozeBG": 105,
- "predBGs": {
- "IOB": [116, 114, 112, 110, 109, 107, 106, 105, 105, 104, 104, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 106, 106, 106, 106, 106, 107]
- },
- "COB": 0,
- "IOB": -0.035,
- "reason": "COB: 0, Dev: -18, BGI: 0.43, ISF: 216, Target: 99; Eventual BG 105 > 99 but Min. Delta -2.60 < Exp. Delta 0.1; setting current basal of 0.4 as temp. Suggested rate is same as profile rate, no temp basal is active, doing nothing",
- "timestamp": "2017-06-25T15:55:10Z"
- },
- "iob": {
- "iob": -0.035,
- "basaliob": -0.035,
- "activity": -0.0004,
- "time": "2017-06-25T15:55:10Z"
- }
- },
- "uploaderBattery": 93,
- "created_at": "2017-06-25T15:55:10Z",
- "NSCLIENT_ID": 1498406118857
-}
- */
-@Singleton
-public class NSDeviceStatus {
- private final AAPSLogger aapsLogger;
- private final SP sp;
- private final ResourceHelper resourceHelper;
- private final NSSettingsStatus nsSettingsStatus;
- private final ConfigInterface config;
- private final RunningConfiguration runningConfiguration;
-
- private JSONObject data = null;
-
- @Inject
- public NSDeviceStatus(
- AAPSLogger aapsLogger,
- SP sp,
- ResourceHelper resourceHelper,
- NSSettingsStatus nsSettingsStatus,
- ConfigInterface config,
- RunningConfiguration runningConfiguration
- ) {
- this.aapsLogger = aapsLogger;
- this.sp = sp;
- this.resourceHelper = resourceHelper;
- this.nsSettingsStatus = nsSettingsStatus;
- this.config = config;
- this.runningConfiguration = runningConfiguration;
- }
-
- public void handleNewData(JSONArray devicestatuses) {
-
- aapsLogger.debug(LTag.NSCLIENT, "Got NS devicestatus: $devicestatuses}");
-
- for (int i = 0; i < devicestatuses.length(); i++) {
- try {
- JSONObject devicestatusJson = devicestatuses.getJSONObject(i);
- if (devicestatusJson != null) {
- setData(devicestatusJson);
- if (devicestatusJson.has("pump")) {
- // Objectives 0
- sp.putBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, true);
- }
- if (devicestatusJson.has("configuration") && config.getNSCLIENT()) {
- // copy configuration of Insulin and Sensitivity from main AAPS
- runningConfiguration.apply(devicestatusJson.getJSONObject("configuration"));
- }
- }
- } catch (JSONException jsonException) {
- jsonException.printStackTrace();
- }
- }
- }
-
- public NSDeviceStatus setData(JSONObject obj) {
- this.data = obj;
- updatePumpData();
- updateOpenApsData(obj);
- updateUploaderData(obj);
- return this;
- }
-
- public String getDevice() {
- try {
- if (data.has("device")) {
- String device = data.getString("device");
- if (device.startsWith("openaps://")) {
- device = device.substring(10);
- return device;
- }
- }
- } catch (JSONException e) {
- aapsLogger.error("Unhandled exception", e);
- }
- return "";
- }
-
- public static class Levels {
- static int URGENT = 2;
- static int WARN = 1;
- static int INFO = 0;
- int LOW = -1;
- int LOWEST = -2;
- static int NONE = -3;
- }
-
- // ***** PUMP DATA ******
-
- private DeviceStatusPumpData deviceStatusPumpData = null;
-
- public Spanned getExtendedPumpStatus() {
- if (deviceStatusPumpData != null && deviceStatusPumpData.extended != null)
- return deviceStatusPumpData.extended;
- return HtmlHelper.INSTANCE.fromHtml("");
- }
-
- public Spanned getPumpStatus() {
- //String[] ALL_STATUS_FIELDS = {"reservoir", "battery", "clock", "status", "device"};
-
- StringBuilder string = new StringBuilder();
- string.append("");
- string.append(resourceHelper.gs(R.string.pump));
- string.append(": ");
-
- if (deviceStatusPumpData == null)
- return HtmlHelper.INSTANCE.fromHtml("");
-
- // test warning level
- int level = Levels.INFO;
- long now = System.currentTimeMillis();
- if (deviceStatusPumpData.clock + nsSettingsStatus.extendedPumpSettings("urgentClock") * 60 * 1000L < now)
- level = Levels.URGENT;
- else if (deviceStatusPumpData.reservoir < nsSettingsStatus.extendedPumpSettings("urgentRes"))
- level = Levels.URGENT;
- else if (deviceStatusPumpData.isPercent && deviceStatusPumpData.percent < nsSettingsStatus.extendedPumpSettings("urgentBattP"))
- level = Levels.URGENT;
- else if (!deviceStatusPumpData.isPercent && deviceStatusPumpData.voltage < nsSettingsStatus.extendedPumpSettings("urgentBattV"))
- level = Levels.URGENT;
- else if (deviceStatusPumpData.clock + nsSettingsStatus.extendedPumpSettings("warnClock") * 60 * 1000L < now)
- level = Levels.WARN;
- else if (deviceStatusPumpData.reservoir < nsSettingsStatus.extendedPumpSettings("warnRes"))
- level = Levels.WARN;
- else if (deviceStatusPumpData.isPercent && deviceStatusPumpData.percent < nsSettingsStatus.extendedPumpSettings("warnBattP"))
- level = Levels.WARN;
- else if (!deviceStatusPumpData.isPercent && deviceStatusPumpData.voltage < nsSettingsStatus.extendedPumpSettings("warnBattV"))
- level = Levels.WARN;
-
- string.append("");
- if (level == Levels.WARN) string.append("yellow\">");
- if (level == Levels.URGENT) string.append("red\">");
-
- String fields = nsSettingsStatus.pumpExtendedSettingsFields();
-
- if (fields.contains("reservoir")) {
- string.append((int) deviceStatusPumpData.reservoir).append("U ");
- }
-
- if (fields.contains("battery") && deviceStatusPumpData.isPercent) {
- string.append(deviceStatusPumpData.percent).append("% ");
- }
- if (fields.contains("battery") && !deviceStatusPumpData.isPercent) {
- string.append(Round.roundTo(deviceStatusPumpData.voltage, 0.001d)).append(" ");
- }
-
- if (fields.contains("clock")) {
- string.append(DateUtil.minAgo(resourceHelper, deviceStatusPumpData.clock)).append(" ");
- }
-
- if (fields.contains("status")) {
- string.append(deviceStatusPumpData.status).append(" ");
- }
-
- if (fields.contains("device")) {
- string.append(getDevice()).append(" ");
- }
-
-
- string.append(""); // color
-
- return HtmlHelper.INSTANCE.fromHtml(string.toString());
- }
-
- static class DeviceStatusPumpData {
- long clock = 0L;
- boolean isPercent = false;
- int percent = 0;
- double voltage = 0;
-
- String status = "N/A";
- double reservoir = 0d;
-
- Spanned extended = null;
- }
-
- private void updatePumpData() {
- try {
- JSONObject pump = data != null && data.has("pump") ? data.getJSONObject("pump") : new JSONObject();
-
- long clock = 0L;
- if (pump.has("clock"))
- clock = DateUtil.fromISODateString(pump.getString("clock")).getTime();
- // check if this is new data
- if (clock == 0 || deviceStatusPumpData != null && clock < deviceStatusPumpData.clock)
- return;
- // create new status and process data
- deviceStatusPumpData = new DeviceStatusPumpData();
- deviceStatusPumpData.clock = clock;
- if (pump.has("status") && pump.getJSONObject("status").has("status"))
- deviceStatusPumpData.status = pump.getJSONObject("status").getString("status");
- if (pump.has("reservoir"))
- deviceStatusPumpData.reservoir = pump.getDouble("reservoir");
- if (pump.has("battery") && pump.getJSONObject("battery").has("percent")) {
- deviceStatusPumpData.isPercent = true;
- deviceStatusPumpData.percent = pump.getJSONObject("battery").getInt("percent");
- } else if (pump.has("battery") && pump.getJSONObject("battery").has("voltage")) {
- deviceStatusPumpData.isPercent = false;
- deviceStatusPumpData.voltage = pump.getJSONObject("battery").getDouble("voltage");
- }
- if (pump.has("extended")) {
- JSONObject extendedJson = pump.getJSONObject("extended");
- StringBuilder exteneded = new StringBuilder();
- Iterator> keys = extendedJson.keys();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- String value = extendedJson.getString(key);
- exteneded.append("").append(key).append(": ").append(value).append("
");
- }
- deviceStatusPumpData.extended = HtmlHelper.INSTANCE.fromHtml(exteneded.toString());
- }
- } catch (Exception e) {
- aapsLogger.error("Unhandled exception", e);
- }
- }
-
-
- // ********* OpenAPS data ***********
-
- public static DeviceStatusOpenAPSData deviceStatusOpenAPSData = new DeviceStatusOpenAPSData();
-
- public static class DeviceStatusOpenAPSData {
- public long clockSuggested = 0L;
- public long clockEnacted = 0L;
-
- public JSONObject suggested = null;
- public JSONObject enacted = null;
- }
-
- private void updateOpenApsData(JSONObject object) {
- try {
- JSONObject openaps = object.has("openaps") ? object.getJSONObject("openaps") : new JSONObject();
- JSONObject suggested = openaps.has("suggested") ? openaps.getJSONObject("suggested") : new JSONObject();
- JSONObject enacted = openaps.has("enacted") ? openaps.getJSONObject("enacted") : new JSONObject();
-
- long clock = 0L;
- if (suggested.has("timestamp"))
- clock = DateUtil.fromISODateString(suggested.getString("timestamp")).getTime();
- // check if this is new data
- if (clock != 0 && clock > deviceStatusOpenAPSData.clockSuggested) {
- deviceStatusOpenAPSData.suggested = suggested;
- deviceStatusOpenAPSData.clockSuggested = clock;
- }
-
- clock = 0L;
- if (enacted.has("timestamp"))
- clock = DateUtil.fromISODateString(enacted.getString("timestamp")).getTime();
- // check if this is new data
- if (clock != 0 && clock > deviceStatusOpenAPSData.clockEnacted) {
- deviceStatusOpenAPSData.enacted = enacted;
- deviceStatusOpenAPSData.clockEnacted = clock;
- }
- } catch (Exception e) {
- aapsLogger.error("Unhandled exception", e);
- }
- }
-
- public Spanned getOpenApsStatus() {
- StringBuilder string = new StringBuilder();
- string.append("");
- string.append(resourceHelper.gs(R.string.openaps_short));
- string.append(": ");
-
- // test warning level
- int level = Levels.INFO;
- long now = System.currentTimeMillis();
- if (deviceStatusOpenAPSData.clockSuggested != 0 && deviceStatusOpenAPSData.clockSuggested + sp.getInt(R.string.key_nsalarm_urgent_staledatavalue, 31) * 60 * 1000L < now)
- level = Levels.URGENT;
- else if (deviceStatusOpenAPSData.clockSuggested != 0 && deviceStatusOpenAPSData.clockSuggested + sp.getInt(R.string.key_nsalarm_staledatavalue, 16) * 60 * 1000L < now)
- level = Levels.WARN;
-
- string.append("");
- if (level == Levels.WARN) string.append("yellow\">");
- if (level == Levels.URGENT) string.append("red\">");
-
- if (deviceStatusOpenAPSData.clockSuggested != 0) {
- string.append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append(" ");
- }
- string.append(""); // color
-
- return HtmlHelper.INSTANCE.fromHtml(string.toString());
- }
-
- public static long getOpenApsTimestamp() {
-
- if (deviceStatusOpenAPSData.clockSuggested != 0) {
- return deviceStatusOpenAPSData.clockSuggested;
- } else {
- return -1;
- }
- }
-
- public Spanned getExtendedOpenApsStatus() {
- StringBuilder string = new StringBuilder();
-
- try {
- if (deviceStatusOpenAPSData.enacted != null && deviceStatusOpenAPSData.clockEnacted != deviceStatusOpenAPSData.clockSuggested)
- string.append("").append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockEnacted)).append(" ").append(deviceStatusOpenAPSData.enacted.getString("reason")).append("
");
- if (deviceStatusOpenAPSData.suggested != null)
- string.append("").append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append(" ").append(deviceStatusOpenAPSData.suggested.getString("reason")).append("
");
- return HtmlHelper.INSTANCE.fromHtml(string.toString());
- } catch (JSONException e) {
- aapsLogger.error("Unhandled exception", e);
- }
- return HtmlHelper.INSTANCE.fromHtml("");
- }
-
- // ********* Uploader data ***********
-
- private static final HashMap uploaders = new HashMap<>();
-
- static class Uploader {
- long clock = 0L;
- int battery = 0;
- }
-
- private void updateUploaderData(JSONObject object) {
- try {
-
- long clock = 0L;
- if (object.has("mills"))
- clock = object.getLong("mills");
- else if (object.has("created_at"))
- clock = DateUtil.fromISODateString(object.getString("created_at")).getTime();
- String device = getDevice();
- Integer battery = null;
- if (object.has("uploaderBattery"))
- battery = object.getInt("uploaderBattery");
- else if (object.has("uploader")) {
- if (object.getJSONObject("uploader").has("battery"))
- battery = object.getJSONObject("uploader").getInt("battery");
- }
- Uploader uploader = uploaders.get(device);
- // check if this is new data
- if (clock != 0 && battery != null && (uploader == null || clock > uploader.clock)) {
- if (uploader == null)
- uploader = new Uploader();
- uploader.battery = battery;
- uploader.clock = clock;
- uploaders.put(device, uploader);
- }
- } catch (Exception e) {
- aapsLogger.error("Unhandled exception", e);
- }
- }
-
- public String getUploaderStatus() {
- Iterator iter = uploaders.entrySet().iterator();
- int minBattery = 100;
- while (iter.hasNext()) {
- Map.Entry pair = (Map.Entry) iter.next();
- Uploader uploader = (Uploader) pair.getValue();
- if (minBattery > uploader.battery)
- minBattery = uploader.battery;
- }
-
- return minBattery + "%";
- }
-
- public Spanned getUploaderStatusSpanned() {
- StringBuilder string = new StringBuilder();
- string.append("");
- string.append(resourceHelper.gs(R.string.uploader_short));
- string.append(": ");
-
- Iterator iter = uploaders.entrySet().iterator();
- int minBattery = 100;
- while (iter.hasNext()) {
- Map.Entry pair = (Map.Entry) iter.next();
- Uploader uploader = (Uploader) pair.getValue();
- if (minBattery > uploader.battery)
- minBattery = uploader.battery;
- }
-
- string.append(minBattery);
- string.append("%");
- return HtmlHelper.INSTANCE.fromHtml(string.toString());
- }
-
- public Spanned getExtendedUploaderStatus() {
- StringBuilder string = new StringBuilder();
-
- Iterator iter = uploaders.entrySet().iterator();
- while (iter.hasNext()) {
- Map.Entry pair = (Map.Entry) iter.next();
- Uploader uploader = (Uploader) pair.getValue();
- String device = (String) pair.getKey();
- string.append("").append(device).append(": ").append(uploader.battery).append("%
");
- }
-
- return HtmlHelper.INSTANCE.fromHtml(string.toString());
- }
-
- public static APSResult getAPSResult(HasAndroidInjector injector) {
- APSResult result = new APSResult(injector);
- result.setJson(deviceStatusOpenAPSData.suggested);
- result.setDate(deviceStatusOpenAPSData.clockSuggested);
- return result;
- }
-
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.kt
new file mode 100644
index 0000000000..5faa6861c1
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.kt
@@ -0,0 +1,396 @@
+package info.nightscout.androidaps.plugins.general.nsclient.data
+
+import android.text.Spanned
+import dagger.android.HasAndroidInjector
+import info.nightscout.androidaps.R
+import info.nightscout.androidaps.interfaces.Config
+import info.nightscout.androidaps.logging.AAPSLogger
+import info.nightscout.androidaps.logging.LTag
+import info.nightscout.androidaps.plugins.aps.loop.APSResult
+import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
+import info.nightscout.androidaps.utils.DateUtil
+import info.nightscout.androidaps.utils.HtmlHelper.fromHtml
+import info.nightscout.androidaps.utils.Round
+import info.nightscout.androidaps.utils.T
+import info.nightscout.androidaps.utils.resources.ResourceHelper
+import info.nightscout.androidaps.utils.sharedPreferences.SP
+import org.json.JSONArray
+import org.json.JSONException
+import org.json.JSONObject
+import java.util.*
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/*
+{
+ "_id": "594fdcec327b83c81b6b8c0f",
+ "device": "openaps://Sony D5803",
+ "pump": {
+ "battery": {
+ "percent": 100
+ },
+ "status": {
+ "status": "normal",
+ "timestamp": "2017-06-25T15:50:14Z"
+ },
+ "extended": {
+ "Version": "1.5-ac98852-2017.06.25",
+ "PumpIOB": 1.13,
+ "LastBolus": "25. 6. 2017 17:25:00",
+ "LastBolusAmount": 0.3,
+ "BaseBasalRate": 0.4,
+ "ActiveProfile": "2016 +30%"
+ },
+ "reservoir": 109,
+ "clock": "2017-06-25T15:55:10Z"
+ },
+ "openaps": {
+ "suggested": {
+ "temp": "absolute",
+ "bg": 115.9,
+ "tick": "+5",
+ "eventualBG": 105,
+ "snoozeBG": 105,
+ "predBGs": {
+ "IOB": [116, 114, 112, 110, 109, 107, 106, 105, 105, 104, 104, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 106, 106, 106, 106, 106, 107]
+ },
+ "COB": 0,
+ "IOB": -0.035,
+ "reason": "COB: 0, Dev: -18, BGI: 0.43, ISF: 216, Target: 99; Eventual BG 105 > 99 but Min. Delta -2.60 < Exp. Delta 0.1; setting current basal of 0.4 as temp. Suggested rate is same as profile rate, no temp basal is active, doing nothing",
+ "timestamp": "2017-06-25T15:55:10Z"
+ },
+ "iob": {
+ "iob": -0.035,
+ "basaliob": -0.035,
+ "activity": -0.0004,
+ "time": "2017-06-25T15:55:10Z"
+ }
+ },
+ "uploaderBattery": 93,
+ "created_at": "2017-06-25T15:55:10Z",
+ "NSCLIENT_ID": 1498406118857
+}
+ */
+@Suppress("SpellCheckingInspection")
+@Singleton
+class NSDeviceStatus @Inject constructor(
+ private val aapsLogger: AAPSLogger,
+ private val sp: SP,
+ private val resourceHelper: ResourceHelper,
+ private val nsSettingsStatus: NSSettingsStatus,
+ private val config: Config,
+ private val dateUtil: DateUtil,
+ private val runningConfiguration: RunningConfiguration
+) {
+
+ private var data: JSONObject? = null
+ fun handleNewData(deviceStatuses: JSONArray) {
+ aapsLogger.debug(LTag.NSCLIENT, "Got NS deviceStatus: \$deviceStatuses}")
+ try {
+ for (i in 0 until deviceStatuses.length()) {
+ val devicestatusJson = deviceStatuses.getJSONObject(i)
+ if (devicestatusJson != null) {
+ setData(devicestatusJson)
+ if (devicestatusJson.has("pump")) {
+ // Objectives 0
+ sp.putBoolean(R.string.key_ObjectivespumpStatusIsAvailableInNS, true)
+ }
+ if (devicestatusJson.has("configuration") && config.NSCLIENT) {
+ // copy configuration of Insulin and Sensitivity from main AAPS
+ runningConfiguration.apply(devicestatusJson.getJSONObject("configuration"))
+ }
+ }
+ }
+ } catch (jsonException: JSONException) {
+ jsonException.printStackTrace()
+ }
+ }
+
+ private fun setData(obj: JSONObject): NSDeviceStatus {
+ data = obj
+ updatePumpData()
+ updateOpenApsData(obj)
+ updateUploaderData(obj)
+ return this
+ }
+
+ val device: String
+ get() {
+ try {
+ if (data!!.has("device")) {
+ var device = data!!.getString("device")
+ if (device.startsWith("openaps://")) {
+ device = device.substring(10)
+ return device
+ }
+ }
+ } catch (e: JSONException) {
+ aapsLogger.error("Unhandled exception", e)
+ }
+ return ""
+ }
+
+ enum class Levels(val level: Int) {
+
+ URGENT(2),
+ WARN(1),
+ INFO(0);
+
+ fun toColor(): String =
+ when (level) {
+ INFO.level -> "white"
+ WARN.level -> "yellow"
+ URGENT.level -> "red"
+ else -> "white"
+ }
+ }
+
+ // ***** PUMP DATA ******
+ private var deviceStatusPumpData: DeviceStatusPumpData? = null
+
+ val extendedPumpStatus: Spanned
+ get() = deviceStatusPumpData?.extended ?: fromHtml("")
+
+ val pumpStatus: Spanned
+ // test warning level // color
+ get() {
+ val pumpData = deviceStatusPumpData ?: return fromHtml("")
+
+ //String[] ALL_STATUS_FIELDS = {"reservoir", "battery", "clock", "status", "device"};
+ val string = StringBuilder()
+ .append("")
+ .append(resourceHelper.gs(R.string.pump))
+ .append(": ")
+
+ // test warning level
+ val level = when {
+ pumpData.clock + nsSettingsStatus.extendedPumpSettings("urgentClock") * 60 * 1000L < dateUtil.now() -> Levels.URGENT
+ pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("urgentRes") -> Levels.URGENT
+ pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("urgentBattP") -> Levels.URGENT
+ !pumpData.isPercent && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("urgentBattV") -> Levels.URGENT
+ pumpData.clock + nsSettingsStatus.extendedPumpSettings("warnClock") * 60 * 1000L < dateUtil.now() -> Levels.WARN
+ pumpData.reservoir < nsSettingsStatus.extendedPumpSettings("warnRes") -> Levels.WARN
+ pumpData.isPercent && pumpData.percent < nsSettingsStatus.extendedPumpSettings("warnBattP") -> Levels.WARN
+ !pumpData.isPercent && pumpData.voltage < nsSettingsStatus.extendedPumpSettings("warnBattV") -> Levels.WARN
+ else -> Levels.INFO
+ }
+ string.append("")
+ val fields = nsSettingsStatus.pumpExtendedSettingsFields()
+ if (fields.contains("reservoir")) string.append(pumpData.reservoir.toInt()).append("U ")
+ if (fields.contains("battery") && pumpData.isPercent) string.append(pumpData.percent).append("% ")
+ if (fields.contains("battery") && !pumpData.isPercent) string.append(Round.roundTo(pumpData.voltage, 0.001)).append(" ")
+ if (fields.contains("clock")) string.append(dateUtil.minAgo(resourceHelper, pumpData.clock)).append(" ")
+ if (fields.contains("status")) string.append(pumpData.status).append(" ")
+ if (fields.contains("device")) string.append(device).append(" ")
+ string.append("") // color
+ return fromHtml(string.toString())
+ }
+
+ internal class DeviceStatusPumpData {
+
+ var clock = 0L
+ var isPercent = false
+ var percent = 0
+ var voltage = 0.0
+ var status = "N/A"
+ var reservoir = 0.0
+ var extended: Spanned? = null
+ }
+
+ private fun updatePumpData() {
+ try {
+ val data = this.data ?: return
+ val pump = if (data.has("pump")) data.getJSONObject("pump") else JSONObject()
+ val clock = if (pump.has("clock")) dateUtil.fromISODateString(pump.getString("clock")) else 0L
+ // check if this is new data
+ if (clock == 0L || deviceStatusPumpData != null && clock < deviceStatusPumpData!!.clock) return
+
+ // create new status and process data
+ val deviceStatusPumpData = DeviceStatusPumpData()
+ deviceStatusPumpData.clock = clock
+ if (pump.has("status") && pump.getJSONObject("status").has("status")) deviceStatusPumpData.status = pump.getJSONObject("status").getString("status")
+ if (pump.has("reservoir")) deviceStatusPumpData.reservoir = pump.getDouble("reservoir")
+ if (pump.has("battery") && pump.getJSONObject("battery").has("percent")) {
+ deviceStatusPumpData.isPercent = true
+ deviceStatusPumpData.percent = pump.getJSONObject("battery").getInt("percent")
+ } else if (pump.has("battery") && pump.getJSONObject("battery").has("voltage")) {
+ deviceStatusPumpData.isPercent = false
+ deviceStatusPumpData.voltage = pump.getJSONObject("battery").getDouble("voltage")
+ }
+ if (pump.has("extended")) {
+ val extendedJson = pump.getJSONObject("extended")
+ val extended = StringBuilder()
+ val keys: Iterator<*> = extendedJson.keys()
+ while (keys.hasNext()) {
+ val key = keys.next() as String
+ val value = extendedJson.getString(key)
+ extended.append("").append(key).append(": ").append(value).append("
")
+ }
+ deviceStatusPumpData.extended = fromHtml(extended.toString())
+ }
+ this.deviceStatusPumpData = deviceStatusPumpData
+ } catch (e: Exception) {
+ aapsLogger.error("Unhandled exception", e)
+ }
+ }
+
+ class DeviceStatusOpenAPSData {
+
+ var clockSuggested = 0L
+ var clockEnacted = 0L
+ var suggested: JSONObject? = null
+ var enacted: JSONObject? = null
+ }
+
+ private fun updateOpenApsData(jsonObject: JSONObject) {
+ try {
+ val openAps = if (jsonObject.has("openaps")) jsonObject.getJSONObject("openaps") else JSONObject()
+ val suggested = if (openAps.has("suggested")) openAps.getJSONObject("suggested") else JSONObject()
+ val enacted = if (openAps.has("enacted")) openAps.getJSONObject("enacted") else JSONObject()
+ var clock = if (suggested.has("timestamp")) dateUtil.fromISODateString(suggested.getString("timestamp")) else 0L
+ // check if this is new data
+ if (clock != 0L && clock > deviceStatusOpenAPSData.clockSuggested) {
+ deviceStatusOpenAPSData.suggested = suggested
+ deviceStatusOpenAPSData.clockSuggested = clock
+ }
+ clock = if (enacted.has("timestamp")) dateUtil.fromISODateString(enacted.getString("timestamp")) else 0L
+ // check if this is new data
+ if (clock != 0L && clock > deviceStatusOpenAPSData.clockEnacted) {
+ deviceStatusOpenAPSData.enacted = enacted
+ deviceStatusOpenAPSData.clockEnacted = clock
+ }
+ } catch (e: Exception) {
+ aapsLogger.error("Unhandled exception", e)
+ }
+ }
+
+ val openApsStatus: Spanned
+ get() {
+ val string = StringBuilder()
+ .append("")
+ .append(resourceHelper.gs(R.string.openaps_short))
+ .append(": ")
+
+ // test warning level
+ val level = when {
+ deviceStatusOpenAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_urgent_staledatavalue, 31)).msecs() < dateUtil.now() -> Levels.URGENT
+ deviceStatusOpenAPSData.clockSuggested + T.mins(sp.getLong(R.string.key_nsalarm_staledatavalue, 16)).msecs() < dateUtil.now() -> Levels.WARN
+ else -> Levels.INFO
+ }
+ string.append("")
+ if (deviceStatusOpenAPSData.clockSuggested != 0L) string.append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append(" ")
+ string.append("") // color
+ return fromHtml(string.toString())
+ }
+
+ val extendedOpenApsStatus: Spanned
+ get() {
+ val string = StringBuilder()
+ try {
+ if (deviceStatusOpenAPSData.enacted != null && deviceStatusOpenAPSData.clockEnacted != deviceStatusOpenAPSData.clockSuggested) string.append("").append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockEnacted)).append(" ").append(deviceStatusOpenAPSData.enacted!!.getString("reason")).append("
")
+ if (deviceStatusOpenAPSData.suggested != null) string.append("").append(dateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append(" ").append(deviceStatusOpenAPSData.suggested!!.getString("reason")).append("
")
+ return fromHtml(string.toString())
+ } catch (e: JSONException) {
+ aapsLogger.error("Unhandled exception", e)
+ }
+ return fromHtml("")
+ }
+
+ internal class Uploader {
+
+ var clock = 0L
+ var battery = 0
+ }
+
+ private fun updateUploaderData(jsonObject: JSONObject) {
+ try {
+ val clock =
+ when {
+ jsonObject.has("mills") -> jsonObject.getLong("mills")
+ jsonObject.has("created_at") -> dateUtil.fromISODateString(jsonObject.getString("created_at"))
+ else -> 0L
+ }
+ val device = device
+ val battery: Int =
+ when {
+ jsonObject.has("uploaderBattery") -> jsonObject.getInt("uploaderBattery")
+ jsonObject.has("uploader") && jsonObject.getJSONObject("uploader").has("battery") -> jsonObject.getJSONObject("uploader").getInt("battery")
+ else -> 0
+ }
+
+ var uploader = uploaderMap[device]
+ // check if this is new data
+ if (clock != 0L && battery != 0 && (uploader == null || clock > uploader.clock)) {
+ if (uploader == null) uploader = Uploader()
+ uploader.battery = battery
+ uploader.clock = clock
+ uploaderMap[device] = uploader
+ }
+ } catch (e: Exception) {
+ aapsLogger.error("Unhandled exception", e)
+ }
+ }
+
+ val uploaderStatus: String
+ get() {
+ val iterator: Iterator<*> = uploaderMap.entries.iterator()
+ var minBattery = 100
+ while (iterator.hasNext()) {
+ val pair = iterator.next() as Map.Entry<*, *>
+ val uploader = pair.value as Uploader
+ if (minBattery > uploader.battery) minBattery = uploader.battery
+ }
+ return "$minBattery%"
+ }
+
+ val uploaderStatusSpanned: Spanned
+ get() {
+ val string = StringBuilder()
+ string.append("")
+ string.append(resourceHelper.gs(R.string.uploader_short))
+ string.append(": ")
+ val iterator: Iterator<*> = uploaderMap.entries.iterator()
+ var minBattery = 100
+ while (iterator.hasNext()) {
+ val pair = iterator.next() as Map.Entry<*, *>
+ val uploader = pair.value as Uploader
+ if (minBattery > uploader.battery) minBattery = uploader.battery
+ }
+ string.append(minBattery)
+ string.append("%")
+ return fromHtml(string.toString())
+ }
+
+ val extendedUploaderStatus: Spanned
+ get() {
+ val string = StringBuilder()
+ val iterator: Iterator<*> = uploaderMap.entries.iterator()
+ while (iterator.hasNext()) {
+ val pair = iterator.next() as Map.Entry<*, *>
+ val uploader = pair.value as Uploader
+ val device = pair.key as String
+ string.append("").append(device).append(": ").append(uploader.battery).append("%
")
+ }
+ return fromHtml(string.toString())
+ }
+
+ // ********* OpenAPS data ***********
+ var deviceStatusOpenAPSData = DeviceStatusOpenAPSData()
+ val openApsTimestamp: Long
+ get() =
+ if (deviceStatusOpenAPSData.clockSuggested != 0L) {
+ deviceStatusOpenAPSData.clockSuggested
+ } else {
+ -1
+ }
+
+ // ********* Uploader data ***********
+ private val uploaderMap = HashMap()
+
+ fun getAPSResult(injector: HasAndroidInjector): APSResult {
+ val result = APSResult(injector)
+ result.json = deviceStatusOpenAPSData.suggested
+ result.date = deviceStatusOpenAPSData.clockSuggested
+ return result
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSettingsStatus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSettingsStatus.kt
index fe53640252..7efeb7c466 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSettingsStatus.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSettingsStatus.kt
@@ -1,8 +1,10 @@
package info.nightscout.androidaps.plugins.general.nsclient.data
import android.content.Context
-import info.nightscout.androidaps.Config
+import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.R
+import info.nightscout.androidaps.database.entities.UserEntry
+import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger
@@ -110,6 +112,7 @@ import javax.inject.Singleton
"activeProfile": "2016 +30%"
}
*/
+@Suppress("SpellCheckingInspection")
@Singleton
class NSSettingsStatus @Inject constructor(
private val aapsLogger: AAPSLogger,
@@ -121,15 +124,30 @@ class NSSettingsStatus @Inject constructor(
private val uel: UserEntryLogger
) {
- var nightscoutVersionName = ""
-
// ***** PUMP STATUS ******
- var data: JSONObject? = null
+ private var data: JSONObject? = null
- fun handleNewData(nightscoutVersionName: String, nightscoutVersionCode: Int, status: JSONObject) {
- this.nightscoutVersionName = nightscoutVersionName
- aapsLogger.debug(LTag.NSCLIENT, "Got versions: Nightscout: $nightscoutVersionName")
- if (nightscoutVersionCode != 0 && nightscoutVersionCode < config.SUPPORTEDNSVERSION) {
+ /* Other received data to 2016/02/10
+ {
+ status: 'ok'
+ , name: env.name
+ , version: env.version
+ , versionNum: versionNum (for ver 1.2.3 contains 10203)
+ , serverTime: new Date().toISOString()
+ , apiEnabled: apiEnabled
+ , careportalEnabled: apiEnabled && env.settings.enable.indexOf('careportal') > -1
+ , boluscalcEnabled: apiEnabled && env.settings.enable.indexOf('boluscalc') > -1
+ , head: env.head
+ , settings: env.settings
+ , extendedSettings: ctx.plugins && ctx.plugins.extendedClientSettings ? ctx.plugins.extendedClientSettings(env.extendedSettings) : {}
+ , activeProfile ..... calculated from treatments or missing
+ }
+ */
+
+ fun handleNewData(status: JSONObject) {
+ data = status
+ aapsLogger.debug(LTag.NSCLIENT, "Got versions: Nightscout: ${getVersion()}")
+ if (getVersionNum() < config.SUPPORTEDNSVERSION) {
val notification = Notification(Notification.OLD_NS, resourceHelper.gs(R.string.unsupportednsversion), Notification.NORMAL)
rxBus.send(EventNewNotification(notification))
} else {
@@ -144,13 +162,10 @@ class NSSettingsStatus @Inject constructor(
if (config.NSCLIENT) copyStatusLightsNsSettings(null)
}
- fun getName(): String? =
- JsonHelper.safeGetStringAllowNull(data, "name", null)
+ fun getVersion(): String =
+ JsonHelper.safeGetStringAllowNull(data, "version", null) ?: "UNKNOWN"
- fun getVersion(): String? =
- JsonHelper.safeGetStringAllowNull(data, "version", null)
-
- fun getVersionNum(): Int =
+ private fun getVersionNum(): Int =
JsonHelper.safeGetInt(data, "versionNum")
private fun getSettings() =
@@ -161,13 +176,13 @@ class NSSettingsStatus @Inject constructor(
// valid property is "warn" or "urgent"
// plugings "iage" "sage" "cage" "pbage"
- fun getExtendedWarnValue(plugin: String, property: String): Double? {
+ private fun getExtendedWarnValue(plugin: String, property: String): Double? {
val extendedSettings = getExtendedSettings() ?: return null
val pluginJson = extendedSettings.optJSONObject(plugin) ?: return null
- try {
- return pluginJson.getDouble(property)
+ return try {
+ pluginJson.getDouble(property)
} catch (e: Exception) {
- return null
+ null
}
}
@@ -175,7 +190,7 @@ class NSSettingsStatus @Inject constructor(
// "bgTargetTop": 180,
// "bgTargetBottom": 72,
// "bgLow": 71
- fun getSettingsThreshold(what: String): Double? {
+ private fun getSettingsThreshold(what: String): Double? {
val threshold = JsonHelper.safeGetJSONObject(getSettings(), "thresholds", null)
return JsonHelper.safeGetDoubleAllowNull(threshold, what)
}
@@ -214,9 +229,6 @@ class NSSettingsStatus @Inject constructor(
private fun extendedPumpSettings(): JSONObject? =
JsonHelper.safeGetJSONObject(getExtendedSettings(), "pump", null)
- fun pumpExtendedSettingsEnabledAlerts(): Boolean =
- JsonHelper.safeGetBoolean(extendedPumpSettings(), "enableAlerts")
-
fun pumpExtendedSettingsFields(): String =
JsonHelper.safeGetString(extendedPumpSettings(), "fields", "")
@@ -235,7 +247,7 @@ class NSSettingsStatus @Inject constructor(
getExtendedWarnValue("sage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_sage_critical, it) }
getExtendedWarnValue("bage", "warn")?.let { sp.putDouble(R.string.key_statuslights_bage_warning, it) }
getExtendedWarnValue("bage", "urgent")?.let { sp.putDouble(R.string.key_statuslights_bage_critical, it) }
- uel.log("NS SETTINGS COPIED")
+ uel.log(Action.NS_SETTINGS_COPIED, UserEntry.Sources.NSClient)
}
if (context != null) OKDialog.showConfirmation(context, resourceHelper.gs(R.string.statuslights), resourceHelper.gs(R.string.copyexistingvalues), action)
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSgv.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSgv.kt
new file mode 100644
index 0000000000..11d3b39127
--- /dev/null
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSSgv.kt
@@ -0,0 +1,32 @@
+package info.nightscout.androidaps.plugins.general.nsclient.data
+
+import info.nightscout.androidaps.utils.JsonHelper
+import org.json.JSONObject
+
+/**
+ *
+ * {"mgdl":105,"mills":1455136282375,"device":"xDrip-BluetoothWixel","direction":"Flat","filtered":98272,"unfiltered":98272,"noise":1,"rssi":100}
+ */
+@Suppress("SpellCheckingInspection")
+class NSSgv(val data: JSONObject) {
+
+ val mgdl: Int?
+ get() = JsonHelper.safeGetIntAllowNull(data, "mgdl")
+ val filtered: Int?
+ get() = JsonHelper.safeGetIntAllowNull(data, "filtered")
+ val unfiltered: Int?
+ get() = JsonHelper.safeGetIntAllowNull(data, "unfiltered")
+ val noise: Int?
+ get() = JsonHelper.safeGetIntAllowNull(data, "noise")
+ val rssi: Int?
+ get() = JsonHelper.safeGetIntAllowNull(data, "rssi")
+ val mills: Long?
+ get() = JsonHelper.safeGetLongAllowNull(data, "mills")
+ val device: String?
+ get() = JsonHelper.safeGetStringAllowNull(data, "device", null)
+ val direction: String?
+ get() = JsonHelper.safeGetStringAllowNull(data, "direction", null)
+ val id: String?
+ get() = JsonHelper.safeGetStringAllowNull(data, "_id", null)
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSTreatment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSTreatment.java
deleted file mode 100644
index 01e8830a64..0000000000
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSTreatment.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package info.nightscout.androidaps.plugins.general.nsclient.data;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.slf4j.Logger;
-
-import java.util.Date;
-
-import info.nightscout.androidaps.logging.LTag;
-import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
-
-public class NSTreatment {
- private static final Logger log = StacktraceLoggerWrapper.getLogger(LTag.NSCLIENT);
-
- private final JSONObject data;
- private String action = null; // "update", "remove" or null (add)
-
- public NSTreatment(JSONObject obj) {
- this.data = obj;
- this.action = getStringOrNull("action");
- this.data.remove("action");
- }
-
- private String getStringOrNull(String key) {
- String ret = null;
- if (data.has(key)) {
- try {
- ret = data.getString(key);
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- }
- return ret;
- }
-
- private Double getDoubleOrNull(String key) {
- Double ret = null;
- if (data.has(key)) {
- try {
- ret = data.getDouble(key);
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- }
- return ret;
- }
-
- private Integer getIntegerOrNull(String key) {
- Integer ret = null;
- if (data.has(key)) {
- try {
- ret = data.getInt(key);
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- }
- return ret;
- }
-
- private Long getLongOrNull(String key) {
- Long ret = null;
- if (data.has(key)) {
- try {
- ret = data.getLong(key);
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- }
- return ret;
- }
-
- private Date getDateOrNull(String key) {
- Date ret = null;
- if (data.has(key)) {
- try {
- ret = new Date(data.getString(key));
- } catch (JSONException e) {
- log.error("Unhandled exception", e);
- }
- }
- return ret;
- }
-
- public String getAction() {
- return action;
- }
-
- public JSONObject getData() {
- return data;
- }
-
- public String get_id() {
- return getStringOrNull("_id");
- }
-
- public String getEnteredBy() {
- return getStringOrNull("enteredBy");
- }
-
- public String getEventType() {
- return getStringOrNull("eventType");
- }
-
- public Integer getHapp_id() {
- return getIntegerOrNull("happ_id");
- }
-
- public Integer getDuration() {
- return getIntegerOrNull("duration");
- }
-
- public Integer getMgdl() {
- return getIntegerOrNull("mgdl");
- }
-
- public Double getAbsolute() {
- return getDoubleOrNull("absolute");
- }
-
- public Long getMills() {
- return getLongOrNull("mills");
- }
-
- public Date getCreated_at() {
- return getDateOrNull("created_at");
- }
-}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java
index 90c461b7a8..078d56943e 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java
@@ -10,7 +10,7 @@ import android.os.IBinder;
import android.os.PowerManager;
import android.os.SystemClock;
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import androidx.work.OneTimeWorkRequest;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
@@ -29,21 +29,27 @@ import javax.inject.Inject;
import dagger.android.DaggerService;
import dagger.android.HasAndroidInjector;
-import info.nightscout.androidaps.Config;
+import info.nightscout.androidaps.interfaces.Config;
import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.db.DbRequest;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventConfigBuilderChange;
-import info.nightscout.androidaps.events.EventNsFood;
import info.nightscout.androidaps.events.EventPreferenceChange;
+import info.nightscout.androidaps.interfaces.DataSyncSelector;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
import info.nightscout.androidaps.interfaces.PluginType;
-import info.nightscout.androidaps.interfaces.ProfileStore;
+import info.nightscout.androidaps.interfaces.UploadQueueInterface;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
+import info.nightscout.androidaps.plugins.general.food.FoodPlugin;
+import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddAckWorker;
+import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddUpdateWorker;
+import info.nightscout.androidaps.plugins.general.nsclient.NSClientMbgWorker;
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
-import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue;
+import info.nightscout.androidaps.plugins.general.nsclient.NSClientRemoveWorker;
+import info.nightscout.androidaps.plugins.general.nsclient.NSClientUpdateRemoveAckWorker;
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAddAck;
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAuthAck;
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSUpdateAck;
@@ -51,8 +57,6 @@ import info.nightscout.androidaps.plugins.general.nsclient.data.AlarmAck;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus;
-import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv;
-import info.nightscout.androidaps.plugins.general.nsclient.data.NSTreatment;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus;
@@ -61,6 +65,9 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNo
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction;
+import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin;
+import info.nightscout.androidaps.plugins.source.NSClientSourcePlugin;
+import info.nightscout.androidaps.receivers.DataWorker;
import info.nightscout.androidaps.services.Intents;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy;
@@ -90,15 +97,16 @@ public class NSClientService extends DaggerService {
@Inject BuildHelper buildHelper;
@Inject Config config;
@Inject DateUtil dateUtil;
- @Inject UploadQueue uploadQueue;
+ @Inject UploadQueueInterface uploadQueue;
+ @Inject DataWorker dataWorker;
+ @Inject DataSyncSelector dataSyncSelector;
+ @Inject AppRepository repository;
private final CompositeDisposable disposable = new CompositeDisposable();
static public PowerManager.WakeLock mWakeLock;
private final IBinder mBinder = new NSClientService.LocalBinder();
- static ProfileStore profileStore;
-
static public Handler handler;
public static Socket mSocket;
@@ -108,9 +116,6 @@ public class NSClientService extends DaggerService {
private static Integer connectCounter = 0;
- public static String nightscoutVersionName = "";
- public static Integer nightscoutVersionCode = 0;
-
private boolean nsEnabled = false;
static public String nsURL = "";
private String nsAPISecret = "";
@@ -118,6 +123,7 @@ public class NSClientService extends DaggerService {
private final Integer nsHours = 48;
public long lastResendTime = 0;
+ public long lastAckTime = 0;
public long latestDateInReceivedData = 0;
@@ -126,7 +132,7 @@ public class NSClientService extends DaggerService {
private final ArrayList reconnections = new ArrayList<>();
private final int WATCHDOG_INTERVAL_MINUTES = 2;
private final int WATCHDOG_RECONNECT_IN = 15;
- private final int WATCHDOG_MAXCONNECTIONS = 5;
+ private final int WATCHDOG_MAX_CONNECTIONS = 5;
public NSClientService() {
super();
@@ -213,21 +219,19 @@ public class NSClientService extends DaggerService {
}
public void processAddAck(NSAddAck ack) {
- if (ack.nsClientID != null) {
- uploadQueue.removeID(ack.json);
- rxBus.send(new EventNSClientNewLog("DBADD", "Acked " + ack.nsClientID));
- } else {
- rxBus.send(new EventNSClientNewLog("ERROR", "DBADD Unknown response"));
- }
+ lastAckTime = dateUtil.now();
+ dataWorker.enqueue(
+ new OneTimeWorkRequest.Builder(NSClientAddAckWorker.class)
+ .setInputData(dataWorker.storeInputData(ack, null))
+ .build());
}
public void processUpdateAck(NSUpdateAck ack) {
- if (ack.result) {
- uploadQueue.removeID(ack.action, ack._id);
- rxBus.send(new EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked " + ack._id));
- } else {
- rxBus.send(new EventNSClientNewLog("ERROR", "DBUPDATE/DBREMOVE Unknown response"));
- }
+ lastAckTime = dateUtil.now();
+ dataWorker.enqueue(
+ new OneTimeWorkRequest.Builder(NSClientUpdateRemoveAckWorker.class)
+ .setInputData(dataWorker.storeInputData(ack, null))
+ .build());
}
public void processAuthAck(NSAuthAck ack) {
@@ -258,6 +262,7 @@ public class NSClientService extends DaggerService {
public NSClientService getServiceInstance() {
return NSClientService.this;
}
+
}
@Override
@@ -337,7 +342,7 @@ public class NSClientService extends DaggerService {
void watchdog() {
synchronized (reconnections) {
- long now = DateUtil.now();
+ long now = dateUtil.now();
reconnections.add(now);
for (int i = 0; i < reconnections.size(); i++) {
Long r = reconnections.get(i);
@@ -345,9 +350,9 @@ public class NSClientService extends DaggerService {
reconnections.remove(r);
}
}
- rxBus.send(new EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " mins: " + reconnections.size() + "/" + WATCHDOG_MAXCONNECTIONS));
- if (reconnections.size() >= WATCHDOG_MAXCONNECTIONS) {
- Notification n = new Notification(Notification.NSMALFUNCTION, resourceHelper.gs(R.string.nsmalfunction), Notification.URGENT);
+ rxBus.send(new EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " mins: " + reconnections.size() + "/" + WATCHDOG_MAX_CONNECTIONS));
+ if (reconnections.size() >= WATCHDOG_MAX_CONNECTIONS) {
+ Notification n = new Notification(Notification.NS_MALFUNCTION, resourceHelper.gs(R.string.nsmalfunction), Notification.URGENT);
rxBus.send(new EventNewNotification(n));
rxBus.send(new EventNSClientNewLog("WATCHDOG", "pausing for " + WATCHDOG_RECONNECT_IN + " mins"));
nsClientPlugin.pause(true);
@@ -508,8 +513,8 @@ public class NSClientService extends DaggerService {
try {
data = (JSONObject) args[0];
rxBus.send(new EventNSClientNewLog("CLEARALARM", "received"));
- rxBus.send(new EventDismissNotification(Notification.NSALARM));
- rxBus.send(new EventDismissNotification(Notification.NSURGENTALARM));
+ rxBus.send(new EventDismissNotification(Notification.NS_ALARM));
+ rxBus.send(new EventDismissNotification(Notification.NS_URGENT_ALARM));
aapsLogger.debug(LTag.NSCLIENT, data.toString());
} catch (Exception e) {
aapsLogger.error("Unhandled exception", e);
@@ -535,185 +540,142 @@ public class NSClientService extends DaggerService {
boolean isFull = !isDelta;
rxBus.send(new EventNSClientNewLog("DATA", "Data packet #" + dataCounter++ + (isDelta ? " delta" : " full")));
- if (data.has("profiles")) {
- JSONArray profiles = data.getJSONArray("profiles");
- if (profiles.length() > 0) {
- JSONObject profile = (JSONObject) profiles.get(profiles.length() - 1);
- profileStore = new ProfileStore(injector, profile);
- broadcastProfile = true;
- rxBus.send(new EventNSClientNewLog("PROFILE", "profile received"));
- }
- }
-
if (data.has("status")) {
JSONObject status = data.getJSONObject("status");
- nsSettingsStatus.setData(status);
-
- if (!status.has("versionNum")) {
- if (status.getInt("versionNum") < config.getSUPPORTEDNSVERSION()) {
- rxBus.send(new EventNSClientNewLog("ERROR", "Unsupported Nightscout version !!!!"));
- }
- } else {
- nightscoutVersionName = nsSettingsStatus.getVersion();
- nightscoutVersionCode = nsSettingsStatus.getVersionNum();
- }
- nsSettingsStatus.handleNewData(nightscoutVersionName, nightscoutVersionCode, status);
-
- /* Other received data to 2016/02/10
- {
- status: 'ok'
- , name: env.name
- , version: env.version
- , versionNum: versionNum (for ver 1.2.3 contains 10203)
- , serverTime: new Date().toISOString()
- , apiEnabled: apiEnabled
- , careportalEnabled: apiEnabled && env.settings.enable.indexOf('careportal') > -1
- , boluscalcEnabled: apiEnabled && env.settings.enable.indexOf('boluscalc') > -1
- , head: env.head
- , settings: env.settings
- , extendedSettings: ctx.plugins && ctx.plugins.extendedClientSettings ? ctx.plugins.extendedClientSettings(env.extendedSettings) : {}
- , activeProfile ..... calculated from treatments or missing
- }
- */
+ nsSettingsStatus.handleNewData(status);
} else if (!isDelta) {
rxBus.send(new EventNSClientNewLog("ERROR", "Unsupported Nightscout version !!!!"));
}
- // If new profile received or change detected broadcast it
- if (broadcastProfile && profileStore != null) {
- handleNewProfile(profileStore, isDelta);
- rxBus.send(new EventNSClientNewLog("PROFILE", "broadcasting"));
+ if (data.has("profiles")) {
+ JSONArray profiles = data.getJSONArray("profiles");
+ if (profiles.length() > 0) {
+ // take the newest
+ JSONObject profileStoreJson = (JSONObject) profiles.get(profiles.length() - 1);
+ rxBus.send(new EventNSClientNewLog("PROFILE", "profile received"));
+ dataWorker.enqueue(
+ new OneTimeWorkRequest.Builder(NSProfilePlugin.NSProfileWorker.class)
+ .setInputData(dataWorker.storeInputData(profileStoreJson, null))
+ .build());
+
+ if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
+ Bundle bundle = new Bundle();
+ bundle.putString("profile", profileStoreJson.toString());
+ bundle.putBoolean("delta", isDelta);
+ Intent intent = new Intent(Intents.ACTION_NEW_PROFILE);
+ intent.putExtras(bundle);
+ intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+ sendBroadcast(intent);
+ }
+ }
}
if (data.has("treatments")) {
JSONArray treatments = data.getJSONArray("treatments");
JSONArray removedTreatments = new JSONArray();
- JSONArray updatedTreatments = new JSONArray();
- JSONArray addedTreatments = new JSONArray();
+ JSONArray addedOrUpdatedTreatments = new JSONArray();
if (treatments.length() > 0)
rxBus.send(new EventNSClientNewLog("DATA", "received " + treatments.length() + " treatments"));
for (Integer index = 0; index < treatments.length(); index++) {
JSONObject jsonTreatment = treatments.getJSONObject(index);
- NSTreatment treatment = new NSTreatment(jsonTreatment);
+ String action = JsonHelper.safeGetStringAllowNull(jsonTreatment, "action", null);
+ long mills = JsonHelper.safeGetLong(jsonTreatment, "mills");
- // remove from upload queue if Ack is failing
- uploadQueue.removeID(jsonTreatment);
- //Find latest date in treatment
- if (treatment.getMills() != null && treatment.getMills() < System.currentTimeMillis())
- if (treatment.getMills() > latestDateInReceivedData)
- latestDateInReceivedData = treatment.getMills();
-
- if (treatment.getAction() == null) {
- addedTreatments.put(jsonTreatment);
- } else if (treatment.getAction().equals("update")) {
- updatedTreatments.put(jsonTreatment);
- } else if (treatment.getAction().equals("remove")) {
- if (treatment.getMills() != null && treatment.getMills() > System.currentTimeMillis() - 24 * 60 * 60 * 1000L) // handle 1 day old deletions only
- removedTreatments.put(jsonTreatment);
- }
+ if (action == null) addedOrUpdatedTreatments.put(jsonTreatment);
+ else if (action.equals("update"))
+ addedOrUpdatedTreatments.put(jsonTreatment);
+ else if (action.equals("remove") && mills > dateUtil.now() - T.days(1).msecs()) // handle 1 day old deletions only
+ removedTreatments.put(jsonTreatment);
}
if (removedTreatments.length() > 0) {
- handleRemovedTreatment(removedTreatments, isDelta);
+ dataWorker.enqueue(
+ new OneTimeWorkRequest.Builder(NSClientRemoveWorker.class)
+ .setInputData(dataWorker.storeInputData(removedTreatments, null))
+ .build());
+
+ if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
+ Bundle bundle = new Bundle();
+ bundle.putString("treatments", removedTreatments.toString());
+ bundle.putBoolean("delta", isDelta);
+ Intent intent = new Intent(Intents.ACTION_REMOVED_TREATMENT);
+ intent.putExtras(bundle);
+ intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+ sendBroadcast(intent);
+ }
}
- if (updatedTreatments.length() > 0) {
- handleChangedTreatment(updatedTreatments, isDelta);
- }
- if (addedTreatments.length() > 0) {
- handleNewTreatment(addedTreatments, isDelta);
+ if (addedOrUpdatedTreatments.length() > 0) {
+ dataWorker.enqueue(
+ new OneTimeWorkRequest.Builder(NSClientAddUpdateWorker.class)
+ .setInputData(dataWorker.storeInputData(addedOrUpdatedTreatments, null))
+ .build());
+
+ if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
+ List splitted = splitArray(addedOrUpdatedTreatments);
+ for (JSONArray part : splitted) {
+ Bundle bundle = new Bundle();
+ bundle.putString("treatments", part.toString());
+ bundle.putBoolean("delta", isDelta);
+ Intent intent = new Intent(Intents.ACTION_CHANGED_TREATMENT);
+ intent.putExtras(bundle);
+ intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+ sendBroadcast(intent);
+ }
+ }
}
}
if (data.has("devicestatus")) {
JSONArray devicestatuses = data.getJSONArray("devicestatus");
if (devicestatuses.length() > 0) {
- rxBus.send(new EventNSClientNewLog("DATA", "received " + devicestatuses.length() + " devicestatuses"));
- for (Integer index = 0; index < devicestatuses.length(); index++) {
- JSONObject jsonStatus = devicestatuses.getJSONObject(index);
- // remove from upload queue if Ack is failing
- uploadQueue.removeID(jsonStatus);
- }
+ rxBus.send(new EventNSClientNewLog("DATA", "received " + devicestatuses.length() + " device statuses"));
nsDeviceStatus.handleNewData(devicestatuses);
}
}
if (data.has("food")) {
JSONArray foods = data.getJSONArray("food");
- JSONArray removedFoods = new JSONArray();
- JSONArray updatedFoods = new JSONArray();
- JSONArray addedFoods = new JSONArray();
if (foods.length() > 0)
rxBus.send(new EventNSClientNewLog("DATA", "received " + foods.length() + " foods"));
- for (Integer index = 0; index < foods.length(); index++) {
- JSONObject jsonFood = foods.getJSONObject(index);
-
- // remove from upload queue if Ack is failing
- uploadQueue.removeID(jsonFood);
-
- String action = JsonHelper.safeGetString(jsonFood, "action");
-
- if (action == null) {
- addedFoods.put(jsonFood);
- } else if (action.equals("update")) {
- updatedFoods.put(jsonFood);
- } else if (action.equals("remove")) {
- removedFoods.put(jsonFood);
- }
- }
- if (removedFoods.length() > 0) {
- EventNsFood evt = new EventNsFood(EventNsFood.Companion.getREMOVE(), removedFoods);
- rxBus.send(evt);
- }
- if (updatedFoods.length() > 0) {
- EventNsFood evt = new EventNsFood(EventNsFood.Companion.getUPDATE(), updatedFoods);
- rxBus.send(evt);
- }
- if (addedFoods.length() > 0) {
- EventNsFood evt = new EventNsFood(EventNsFood.Companion.getADD(), addedFoods);
- rxBus.send(evt);
- }
+ dataWorker.enqueue(
+ new OneTimeWorkRequest.Builder(FoodPlugin.FoodWorker.class)
+ .setInputData(dataWorker.storeInputData(foods, null))
+ .build());
}
+ //noinspection SpellCheckingInspection
if (data.has("mbgs")) {
- JSONArray mbgs = data.getJSONArray("mbgs");
- if (mbgs.length() > 0)
- rxBus.send(new EventNSClientNewLog("DATA", "received " + mbgs.length() + " mbgs"));
- for (Integer index = 0; index < mbgs.length(); index++) {
- JSONObject jsonMbg = mbgs.getJSONObject(index);
- // remove from upload queue if Ack is failing
- uploadQueue.removeID(jsonMbg);
- }
- handleNewMbg(mbgs, isDelta);
+ JSONArray mbgArray = data.getJSONArray("mbgs");
+ if (mbgArray.length() > 0)
+ rxBus.send(new EventNSClientNewLog("DATA", "received " + mbgArray.length() + " mbgs"));
+ dataWorker.enqueue(
+ new OneTimeWorkRequest.Builder(NSClientMbgWorker.class)
+ .setInputData(dataWorker.storeInputData(mbgArray, null))
+ .build());
}
if (data.has("cals")) {
JSONArray cals = data.getJSONArray("cals");
if (cals.length() > 0)
rxBus.send(new EventNSClientNewLog("DATA", "received " + cals.length() + " cals"));
- // Retreive actual calibration
- for (Integer index = 0; index < cals.length(); index++) {
- // remove from upload queue if Ack is failing
- uploadQueue.removeID(cals.optJSONObject(index));
- }
- handleNewCal(cals, isDelta);
+ // Calibrations ignored
}
if (data.has("sgvs")) {
JSONArray sgvs = data.getJSONArray("sgvs");
if (sgvs.length() > 0)
rxBus.send(new EventNSClientNewLog("DATA", "received " + sgvs.length() + " sgvs"));
- for (int index = 0; index < sgvs.length(); index++) {
- JSONObject jsonSgv = sgvs.getJSONObject(index);
- // rxBus.send(new EventNSClientNewLog("DATA", "svg " + sgvs.getJSONObject(index).toString());
- NSSgv sgv = new NSSgv(jsonSgv);
- // Handle new sgv here
- // remove from upload queue if Ack is failing
- uploadQueue.removeID(jsonSgv);
- //Find latest date in sgv
- if (sgv.getMills() != null && sgv.getMills() < System.currentTimeMillis())
- if (sgv.getMills() > latestDateInReceivedData)
- latestDateInReceivedData = sgv.getMills();
+
+ dataWorker.enqueue(new OneTimeWorkRequest.Builder(NSClientSourcePlugin.NSClientSourceWorker.class)
+ .setInputData(dataWorker.storeInputData(sgvs, null))
+ .build());
+
+ List splitted = splitArray(sgvs);
+ if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
+ for (JSONArray part : splitted) {
+ Bundle bundle = new Bundle();
+ bundle.putString("sgvs", part.toString());
+ bundle.putBoolean("delta", isDelta);
+ Intent intent = new Intent(Intents.ACTION_NEW_SGV);
+ intent.putExtras(bundle);
+ intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+ sendBroadcast(intent);
+ }
}
- // Was that sgv more less 5 mins ago ?
- if ((System.currentTimeMillis() - latestDateInReceivedData) / (60 * 1000L) < 5L) {
- rxBus.send(new EventDismissNotification(Notification.NSALARM));
- rxBus.send(new EventDismissNotification(Notification.NSURGENTALARM));
- }
- handleNewSgv(sgvs, isDelta);
}
rxBus.send(new EventNSClientNewLog("LAST", dateUtil.dateAndTimeString(latestDateInReceivedData)));
} catch (JSONException e) {
@@ -741,15 +703,15 @@ public class NSClientService extends DaggerService {
}
}
- public void dbUpdateUnset(DbRequest dbr, NSUpdateAck ack) {
+ public void dbUpdate(String collection, String _id, JSONObject data, Object originalObject) {
try {
if (!isConnected || !hasWriteAuth) return;
JSONObject message = new JSONObject();
- message.put("collection", dbr.collection);
- message.put("_id", dbr._id);
- message.put("data", new JSONObject(dbr.data));
- mSocket.emit("dbUpdateUnset", message, ack);
- rxBus.send(new EventNSClientNewLog("DBUPDATEUNSET " + dbr.collection, "Sent " + dbr._id));
+ message.put("collection", collection);
+ message.put("_id", _id);
+ message.put("data", data);
+ mSocket.emit("dbUpdate", message, new NSUpdateAck("dbUpdate", _id, aapsLogger, rxBus, originalObject));
+ rxBus.send(new EventNSClientNewLog("DBUPDATE " + collection, "Sent " + originalObject.getClass().getSimpleName() + " " + _id));
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
@@ -768,6 +730,19 @@ public class NSClientService extends DaggerService {
}
}
+ public void dbRemove(String collection, String _id, Object originalObject) {
+ try {
+ if (!isConnected || !hasWriteAuth) return;
+ JSONObject message = new JSONObject();
+ message.put("collection", collection);
+ message.put("_id", _id);
+ mSocket.emit("dbRemove", message, new NSUpdateAck("dbRemove", _id, aapsLogger, rxBus, originalObject));
+ rxBus.send(new EventNSClientNewLog("DBREMOVE " + collection, "Sent " + originalObject.getClass().getSimpleName() + " " + _id));
+ } catch (JSONException e) {
+ aapsLogger.error("Unhandled exception", e);
+ }
+ }
+
public void dbAdd(DbRequest dbr, NSAddAck ack) {
try {
if (!isConnected || !hasWriteAuth) return;
@@ -781,6 +756,19 @@ public class NSClientService extends DaggerService {
}
}
+ public void dbAdd(String collection, JSONObject data, Object originalObject) {
+ try {
+ if (!isConnected || !hasWriteAuth) return;
+ JSONObject message = new JSONObject();
+ message.put("collection", collection);
+ message.put("data", data);
+ mSocket.emit("dbAdd", message, new NSAddAck(aapsLogger, rxBus, originalObject));
+ rxBus.send(new EventNSClientNewLog("DBADD " + collection, "Sent " + originalObject.getClass().getSimpleName() + " " + data));
+ } catch (JSONException e) {
+ aapsLogger.error("Unhandled exception", e);
+ }
+ }
+
public void sendAlarmAck(AlarmAck alarmAck) {
if (!isConnected || !hasWriteAuth) return;
mSocket.emit("ack", alarmAck.level, alarmAck.group, alarmAck.silenceTime);
@@ -788,41 +776,55 @@ public class NSClientService extends DaggerService {
}
public void resend(final String reason) {
- if (uploadQueue.size() == 0)
- return;
-
if (!isConnected || !hasWriteAuth) return;
handler.post(() -> {
if (mSocket == null || !mSocket.connected()) return;
+ rxBus.send(new EventNSClientNewLog("QUEUE", "Resend started: " + reason));
+
+ if (lastAckTime > System.currentTimeMillis() - 10 * 1000L) {
+ aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastAckTime: " + ((System.currentTimeMillis() - lastAckTime) / 1000L) + " sec");
+ return;
+ }
+
+ dataSyncSelector.processChangedBolusesCompat();
+ dataSyncSelector.processChangedCarbsCompat();
+ dataSyncSelector.processChangedBolusCalculatorResultsCompat();
+ dataSyncSelector.processChangedTemporaryBasalsCompat();
+ dataSyncSelector.processChangedExtendedBolusesCompat();
+ dataSyncSelector.processChangedProfileSwitchesCompat();
+ dataSyncSelector.processChangedGlucoseValuesCompat();
+ dataSyncSelector.processChangedTempTargetsCompat();
+ dataSyncSelector.processChangedFoodsCompat();
+ dataSyncSelector.processChangedTherapyEventsCompat();
+ dataSyncSelector.processChangedDeviceStatusesCompat();
+
+ if (uploadQueue.size() == 0)
+ return;
+
if (lastResendTime > System.currentTimeMillis() - 10 * 1000L) {
aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastResendTime: " + ((System.currentTimeMillis() - lastResendTime) / 1000L) + " sec");
return;
}
lastResendTime = System.currentTimeMillis();
- rxBus.send(new EventNSClientNewLog("QUEUE", "Resend started: " + reason));
-
CloseableIterator iterator;
int maxcount = 30;
try {
- iterator = databaseHelper.getDbRequestInterator();
+ iterator = databaseHelper.getDbRequestIterator();
try {
while (iterator.hasNext() && maxcount > 0) {
DbRequest dbr = iterator.next();
if (dbr.action.equals("dbAdd")) {
- NSAddAck addAck = new NSAddAck(aapsLogger, rxBus);
+ NSAddAck addAck = new NSAddAck(aapsLogger, rxBus, null);
dbAdd(dbr, addAck);
} else if (dbr.action.equals("dbRemove")) {
- NSUpdateAck removeAck = new NSUpdateAck(dbr.action, dbr._id, aapsLogger, rxBus);
+ NSUpdateAck removeAck = new NSUpdateAck("dbRemove", dbr._id, aapsLogger, rxBus, null);
dbRemove(dbr, removeAck);
} else if (dbr.action.equals("dbUpdate")) {
- NSUpdateAck updateAck = new NSUpdateAck(dbr.action, dbr._id, aapsLogger, rxBus);
+ NSUpdateAck updateAck = new NSUpdateAck("dbUpdate", dbr._id, aapsLogger, rxBus, null);
dbUpdate(dbr, updateAck);
- } else if (dbr.action.equals("dbUpdateUnset")) {
- NSUpdateAck updateUnsetAck = new NSUpdateAck(dbr.action, dbr._id, aapsLogger, rxBus);
- dbUpdateUnset(dbr, updateUnsetAck);
}
maxcount--;
}
@@ -881,145 +883,6 @@ public class NSClientService extends DaggerService {
}
}
- public void handleNewCal(JSONArray cals, boolean isDelta) {
- Bundle bundle = new Bundle();
- bundle.putString("cals", cals.toString());
- bundle.putBoolean("delta", isDelta);
- Intent intent = new Intent(Intents.ACTION_NEW_CAL);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
- }
-
- public void handleNewMbg(JSONArray mbgs, boolean isDelta) {
- Bundle bundle = new Bundle();
- bundle.putString("mbgs", mbgs.toString());
- bundle.putBoolean("delta", isDelta);
- Intent intent = new Intent(Intents.ACTION_NEW_MBG);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
- }
-
- public void handleNewProfile(ProfileStore profile, boolean isDelta) {
- Bundle bundle = new Bundle();
- bundle.putString("profile", profile.getData().toString());
- bundle.putBoolean("delta", isDelta);
- Intent intent = new Intent(Intents.ACTION_NEW_PROFILE);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
-
- if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
- bundle = new Bundle();
- bundle.putString("profile", profile.getData().toString());
- bundle.putBoolean("delta", isDelta);
- intent = new Intent(Intents.ACTION_NEW_PROFILE);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- this.sendBroadcast(intent);
- }
- }
-
- public void handleNewSgv(JSONArray sgvs, boolean isDelta) {
- List splitted = splitArray(sgvs);
- for (JSONArray part : splitted) {
- Bundle bundle = new Bundle();
- bundle.putString("sgvs", part.toString());
- bundle.putBoolean("delta", isDelta);
- Intent intent = new Intent(Intents.ACTION_NEW_SGV);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
- }
-
- if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
- for (JSONArray part : splitted) {
- Bundle bundle = new Bundle();
- bundle.putString("sgvs", part.toString());
- bundle.putBoolean("delta", isDelta);
- Intent intent = new Intent(Intents.ACTION_NEW_SGV);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- this.sendBroadcast(intent);
- }
- }
- }
-
- public void handleNewTreatment(JSONArray treatments, boolean isDelta) {
- List splitted = splitArray(treatments);
- for (JSONArray part : splitted) {
- Bundle bundle = new Bundle();
- bundle.putString("treatments", part.toString());
- bundle.putBoolean("delta", isDelta);
- Intent intent = new Intent(Intents.ACTION_NEW_TREATMENT);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
- }
-
- if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
- splitted = splitArray(treatments);
- for (JSONArray part : splitted) {
- Bundle bundle = new Bundle();
- bundle.putString("treatments", part.toString());
- bundle.putBoolean("delta", isDelta);
- Intent intent = new Intent(Intents.ACTION_NEW_TREATMENT);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- this.getApplicationContext().sendBroadcast(intent);
- }
- }
- }
-
- public void handleChangedTreatment(JSONArray treatments, boolean isDelta) {
- List splitted = splitArray(treatments);
- for (JSONArray part : splitted) {
- Bundle bundle = new Bundle();
- bundle.putString("treatments", part.toString());
- bundle.putBoolean("delta", isDelta);
- Intent intent = new Intent(Intents.ACTION_CHANGED_TREATMENT);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
- }
-
- if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
- splitted = splitArray(treatments);
- for (JSONArray part : splitted) {
- Bundle bundle = new Bundle();
- bundle.putString("treatments", part.toString());
- bundle.putBoolean("delta", isDelta);
- Intent intent = new Intent(Intents.ACTION_CHANGED_TREATMENT);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- this.getApplicationContext().sendBroadcast(intent);
- }
- }
- }
-
- public void handleRemovedTreatment(JSONArray treatments, boolean isDelta) {
- Bundle bundle = new Bundle();
- bundle.putString("treatments", treatments.toString());
- bundle.putBoolean("delta", isDelta);
- Intent intent = new Intent(Intents.ACTION_REMOVED_TREATMENT);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
-
-
- if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
- bundle = new Bundle();
- bundle.putString("treatments", treatments.toString());
- bundle.putBoolean("delta", isDelta);
- intent = new Intent(Intents.ACTION_REMOVED_TREATMENT);
- intent.putExtras(bundle);
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- this.getApplicationContext().sendBroadcast(intent);
- }
- }
-
-
public List splitArray(JSONArray array) {
List ret = new ArrayList<>();
try {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansFragment.kt
index 07bbea6753..e6d26b1bb9 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansFragment.kt
@@ -7,21 +7,19 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
-import androidx.lifecycle.Observer
-import androidx.work.WorkInfo
import androidx.work.WorkManager
import dagger.android.support.DaggerFragment
-import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.Event
+import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
-import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.BackpressureStrategy
import io.reactivex.Single
import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.rxkotlin.plusAssign
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@@ -40,10 +38,11 @@ class OpenHumansFragment : DaggerFragment() {
@Inject lateinit var openHumansUploader: OpenHumansUploader
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var aapsSchedulers: AapsSchedulers
+ @Inject lateinit var databaseHelper: DatabaseHelperInterface
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- compositeDisposable += Single.fromCallable { MainApp.getDbHelper().ohQueueSize }
+ compositeDisposable += Single.fromCallable { databaseHelper.getOHQueueSize() }
.subscribeOn(aapsSchedulers.io)
.repeatWhen {
rxBus.toObservable(UpdateViewEvent::class.java)
@@ -58,7 +57,7 @@ class OpenHumansFragment : DaggerFragment() {
updateGUI()
}, {})
context?.applicationContext?.let { appContext ->
- WorkManager.getInstance(appContext).getWorkInfosForUniqueWorkLiveData(OpenHumansUploader.WORK_NAME).observe(this, Observer> {
+ WorkManager.getInstance(appContext).getWorkInfosForUniqueWorkLiveData(OpenHumansUploader.WORK_NAME).observe(this, {
val workInfo = it.lastOrNull()
if (workInfo == null) {
workerState?.visibility = View.GONE
@@ -84,7 +83,7 @@ class OpenHumansFragment : DaggerFragment() {
workerState = view.findViewById(R.id.worker_state)
login!!.setOnClickListener { startActivity(Intent(context, OpenHumansLoginActivity::class.java)) }
logout!!.setOnClickListener {
- activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.oh_logout_confirmation), Runnable { openHumansUploader.logout() }) }
+ activity?.let { activity -> OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.oh_logout_confirmation)) { openHumansUploader.logout() } }
}
viewsCreated = true
updateGUI()
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt
index 31aa345d65..cf4f0c62fa 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/openhumans/OpenHumansUploader.kt
@@ -14,20 +14,21 @@ import androidx.core.app.NotificationManagerCompat
import androidx.work.*
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.BuildConfig
-import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
+import info.nightscout.androidaps.database.entities.TemporaryTarget
+import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.db.*
import info.nightscout.androidaps.events.EventPreferenceChange
+import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
-import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
-import io.reactivex.rxkotlin.plusAssign
+import info.nightscout.androidaps.extensions.toConstant
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
@@ -36,6 +37,7 @@ import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
+import io.reactivex.rxkotlin.plusAssign
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
@@ -58,7 +60,7 @@ class OpenHumansUploader @Inject constructor(
private val sp: SP,
private val rxBus: RxBusWrapper,
private val context: Context,
- private val treatmentsPlugin: TreatmentsPlugin,
+ private val databaseHelper: DatabaseHelperInterface,
val repository: AppRepository
) : PluginBase(
PluginDescription()
@@ -196,23 +198,15 @@ class OpenHumansUploader @Inject constructor(
}
@JvmOverloads
- fun enqueueCareportalEvent(careportalEvent: CareportalEvent, deleted: Boolean = false) = insertQueueItem("CareportalEvents") {
- put("date", careportalEvent.date)
- put("isValid", careportalEvent.isValid)
- put("source", careportalEvent.source)
- put("nsId", careportalEvent._id)
- put("eventType", careportalEvent.eventType)
- val data = JSONObject(careportalEvent.json)
- val reducedData = JSONObject()
- if (data.has("mgdl")) reducedData.put("mgdl", data.getDouble("mgdl"))
- if (data.has("glucose")) reducedData.put("glucose", data.getDouble("glucose"))
- if (data.has("units")) reducedData.put("units", data.getString("units"))
- if (data.has("created_at")) reducedData.put("created_at", data.getString("created_at"))
- if (data.has("glucoseType")) reducedData.put("glucoseType", data.getString("glucoseType"))
- if (data.has("duration")) reducedData.put("duration", data.getInt("duration"))
- if (data.has("mills")) reducedData.put("mills", data.getLong("mills"))
- if (data.has("eventType")) reducedData.put("eventType", data.getString("eventType"))
- put("data", reducedData)
+ fun enqueueTherapyEvent(therapyEvent: TherapyEvent, deleted: Boolean = false) = insertQueueItem("TherapyEvents") {
+ put("date", therapyEvent.timestamp)
+ put("isValid", therapyEvent.isValid)
+ put("nsId", therapyEvent.interfaceIDs.nightscoutId)
+ put("eventType", therapyEvent.type.text)
+ put("glucose", therapyEvent.glucose)
+ put("units", therapyEvent.glucoseUnit.toConstant())
+ put("glucoseType", therapyEvent.glucoseType?.text)
+ put("duration", therapyEvent.duration)
put("isDeletion", deleted)
}
@@ -228,27 +222,27 @@ class OpenHumansUploader @Inject constructor(
put("isDeletion", deleted)
}
- @JvmOverloads
- fun enqueueProfileSwitch(profileSwitch: ProfileSwitch, deleted: Boolean = false) = insertQueueItem("ProfileSwitches") {
- put("date", profileSwitch.date)
- put("isValid", profileSwitch.isValid)
- put("source", profileSwitch.source)
- put("nsId", profileSwitch._id)
- put("isCPP", profileSwitch.isCPP)
- put("timeshift", profileSwitch.timeshift)
- put("percentage", profileSwitch.percentage)
- put("profile", JSONObject(profileSwitch.profileJson))
- put("profilePlugin", profileSwitch.profilePlugin)
- put("durationInMinutes", profileSwitch.durationInMinutes)
- put("isDeletion", deleted)
- }
+ // @JvmOverloads
+ // fun enqueueProfileSwitch(profileSwitch: ProfileSwitch, deleted: Boolean = false) = insertQueueItem("ProfileSwitches") {
+ // put("date", profileSwitch.date)
+ // put("isValid", profileSwitch.isValid)
+ // put("source", profileSwitch.source)
+ // put("nsId", profileSwitch._id)
+ // put("isCPP", profileSwitch.isCPP)
+ // put("timeshift", profileSwitch.timeshift)
+ // put("percentage", profileSwitch.percentage)
+ // put("profile", JSONObject(profileSwitch.profileJson))
+ // put("profilePlugin", profileSwitch.profilePlugin)
+ // put("durationInMinutes", profileSwitch.durationInMinutes)
+ // put("isDeletion", deleted)
+ // }
- fun enqueueTotalDailyDose(tdd: TDD) = insertQueueItem("TotalDailyDoses") {
- put("double", tdd.date)
- put("double", tdd.bolus)
- put("double", tdd.basal)
- put("double", tdd.total)
- }
+ // fun enqueueTotalDailyDose(tdd: TDD) = insertQueueItem("TotalDailyDoses") {
+ // put("double", tdd.date)
+ // put("double", tdd.bolus)
+ // put("double", tdd.basal)
+ // put("double", tdd.total)
+ // }
@JvmOverloads
fun enqueueTemporaryBasal(temporaryBasal: TemporaryBasal?, deleted: Boolean = false) = temporaryBasal?.let {
@@ -268,16 +262,15 @@ class OpenHumansUploader @Inject constructor(
}
@JvmOverloads
- fun enqueueTempTarget(tempTarget: TempTarget?, deleted: Boolean = false) = tempTarget?.let {
+ fun enqueueTempTarget(tempTarget: TemporaryTarget?, deleted: Boolean = false) = tempTarget?.let {
insertQueueItem("TempTargets") {
- put("date", tempTarget.date)
+ put("date", tempTarget.timestamp)
put("isValid", tempTarget.isValid)
- put("source", tempTarget.source)
- put("nsId", tempTarget._id)
- put("low", tempTarget.low)
- put("high", tempTarget.high)
+ put("nsId", tempTarget.interfaceIDs_backing?.nightscoutId)
+ put("low", tempTarget.lowTarget)
+ put("high", tempTarget.highTarget)
put("reason", tempTarget.reason)
- put("durationInMinutes", tempTarget.durationInMinutes)
+ put("durationInMinutes", tempTarget.duration)
put("isDeletion", deleted)
}
}
@@ -317,7 +310,7 @@ class OpenHumansUploader @Inject constructor(
file = file,
content = jsonObject.toString()
)
- MainApp.getDbHelper().createOrUpdate(queueItem)
+ databaseHelper.createOrUpdate(queueItem)
rxBus.send(OpenHumansFragment.UpdateQueueEvent)
} catch (e: JSONException) {
e.printStackTrace()
@@ -347,7 +340,7 @@ class OpenHumansUploader @Inject constructor(
isSetup = false
oAuthTokens = null
projectMemberId = null
- MainApp.getDbHelper().clearOpenHumansQueue()
+ databaseHelper.clearOpenHumansQueue()
rxBus.send(OpenHumansFragment.UpdateViewEvent)
}
@@ -360,31 +353,31 @@ class OpenHumansUploader @Inject constructor(
//Updating the notification for every item drastically slows down the operation
if (currentProgress % 1000L == 0L) showOngoingNotification(maxProgress, currentProgress)
}
- copyDisposable = Completable.fromCallable { MainApp.getDbHelper().clearOpenHumansQueue() }
- .andThen(Single.defer { Single.just(MainApp.getDbHelper().countOfAllRows + treatmentsPlugin.service.count()) })
- .doOnSuccess { maxProgress = it }
- .flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.getTreatmentData()) } }
- .map { enqueueTreatment(it); increaseCounter() }
- .ignoreElements()
+ copyDisposable = Completable.fromCallable { databaseHelper.clearOpenHumansQueue() }
+// .andThen(Single.defer { Single.just(databaseHelper.getCountOfAllRows() + treatmentsPlugin.service.count()) })
+// .doOnSuccess { maxProgress = it }
+// .flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.getTreatmentData()) } }
+// .map { enqueueTreatment(it); increaseCounter() }
+// .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetBgReadingsDataFromTime(0, true).blockingGet()) })
.map { enqueueBGReading(it); increaseCounter() }
.ignoreElements()
- .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allCareportalEvents) })
- .map { enqueueCareportalEvent(it); increaseCounter() }
+ .andThen(Observable.defer { Observable.fromIterable(repository.compatGetTherapyEventDataFromTime(0, true).blockingGet()) })
+ .map { enqueueTherapyEvent(it); increaseCounter() }
.ignoreElements()
- .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allExtendedBoluses) })
- .map { enqueueExtendedBolus(it); increaseCounter() }
- .ignoreElements()
- .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allProfileSwitches) })
- .map { enqueueProfileSwitch(it); increaseCounter() }
- .ignoreElements()
- .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allTDDs) })
- .map { enqueueTotalDailyDose(it); increaseCounter() }
- .ignoreElements()
- .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allTemporaryBasals) })
- .map { enqueueTemporaryBasal(it); increaseCounter() }
- .ignoreElements()
- .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allTempTargets) })
+// .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllExtendedBoluses()) })
+// .map { enqueueExtendedBolus(it); increaseCounter() }
+// .ignoreElements()
+// .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllProfileSwitches()) })
+// .map { enqueueProfileSwitch(it); increaseCounter() }
+// .ignoreElements()
+ // .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllTDDs()) })
+ // .map { enqueueTotalDailyDose(it); increaseCounter() }
+ // .ignoreElements()
+ // .andThen(Observable.defer { Observable.fromIterable(databaseHelper.getAllTemporaryBasals()) })
+ // .map { enqueueTemporaryBasal(it); increaseCounter() }
+ // .ignoreElements()
+ .andThen(Observable.defer { Observable.fromIterable(repository.compatGetTemporaryTargetData().blockingGet()) })
.map { enqueueTempTarget(it); increaseCounter() }
.ignoreElements()
.doOnSubscribe {
@@ -448,7 +441,7 @@ class OpenHumansUploader @Inject constructor(
fun uploadDataSegmentally(): Completable =
uploadData(UPLOAD_SEGMENT_SIZE)
- .repeatUntil { MainApp.getDbHelper().ohQueueSize == 0L }
+ .repeatUntil { databaseHelper.getOHQueueSize() == 0L }
.doOnSubscribe {
aapsLogger.info(LTag.OHUPLOADER, "Starting segmental upload")
}
@@ -460,7 +453,7 @@ class OpenHumansUploader @Inject constructor(
}
@Suppress("SameParameterValue")
- private fun uploadData(maxEntries: Long?): Completable = gatherData(maxEntries)
+ private fun uploadData(maxEntries: Long): Completable = gatherData(maxEntries)
.flatMap { data -> refreshAccessTokensIfNeeded().map { accessToken -> accessToken to data } }
.flatMap { uploadFile(it.first, it.second).andThen(Single.just(it.second)) }
.flatMapCompletable {
@@ -501,8 +494,8 @@ class OpenHumansUploader @Inject constructor(
}
}
- private fun gatherData(maxEntries: Long?) = Single.defer {
- val items = MainApp.getDbHelper().getAllOHQueueItems(maxEntries)
+ private fun gatherData(maxEntries: Long) = Single.defer {
+ val items = databaseHelper.getAllOHQueueItems(maxEntries)
val baos = ByteArrayOutputStream()
val zos = ZipOutputStream(baos)
val tags = mutableListOf()
@@ -583,7 +576,7 @@ class OpenHumansUploader @Inject constructor(
}
private fun removeUploadedEntriesFromQueue(highestId: Long) = Completable.fromCallable {
- MainApp.getDbHelper().removeAllOHQueueItemsWithIdSmallerThan(highestId)
+ databaseHelper.removeAllOHQueueItemsWithIdSmallerThan(highestId)
}
private fun handleSignOut() {
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt
index e254c4f025..8810a7613f 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt
@@ -24,29 +24,34 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.jjoe64.graphview.GraphView
import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerFragment
-import info.nightscout.androidaps.Config
+import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
-import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.interfaces.Profile
+import info.nightscout.androidaps.database.AppRepository
+import info.nightscout.androidaps.database.ValueWrapper
+import info.nightscout.androidaps.database.entities.TemporaryTarget
+import info.nightscout.androidaps.database.entities.UserEntry.Action
+import info.nightscout.androidaps.database.entities.UserEntry.Sources
+import info.nightscout.androidaps.database.interfaces.end
import info.nightscout.androidaps.databinding.OverviewFragmentBinding
import info.nightscout.androidaps.dialogs.*
import info.nightscout.androidaps.events.*
+import info.nightscout.androidaps.extensions.*
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
-import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
+import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
-import info.nightscout.androidaps.plugins.general.wear.events.EventWearDoAction
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
-import info.nightscout.androidaps.events.EventAutosensCalculationFinished
+import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
+import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.source.DexcomPlugin
@@ -57,8 +62,7 @@ import info.nightscout.androidaps.skins.SkinProvider
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
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.*
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
@@ -91,10 +95,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var statusLightHandler: StatusLightHandler
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
@Inject lateinit var loopPlugin: LoopPlugin
- @Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
- @Inject lateinit var activePlugin: ActivePluginProvider
+ @Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
- @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
+ @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var dexcomPlugin: DexcomPlugin
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
@Inject lateinit var xdripPlugin: XdripPlugin
@@ -106,10 +109,13 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var overviewMenus: OverviewMenus
@Inject lateinit var skinProvider: SkinProvider
+ @Inject lateinit var trendCalculator: TrendCalculator
@Inject lateinit var config: Config
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var databaseHelper: DatabaseHelperInterface
@Inject lateinit var uel: UserEntryLogger
+ @Inject lateinit var repository: AppRepository
+ @Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider
private val disposable = CompositeDisposable()
@@ -238,7 +244,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventAcceptOpenLoopChange") }, fabricPrivacy::logException))
disposable.add(rxBus
- .toObservable(EventCareportalEventChange::class.java)
+ .toObservable(EventTherapyEventChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventCareportalEventChange") }, fabricPrivacy::logException))
disposable.add(rxBus
@@ -250,7 +256,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventAutosensCalculationFinished") }, fabricPrivacy::logException))
disposable.add(rxBus
- .toObservable(EventProfileNeedsUpdate::class.java)
+ .toObservable(EventProfileSwitchChanged::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventProfileNeedsUpdate") }, fabricPrivacy::logException))
disposable.add(rxBus
@@ -301,7 +307,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
R.id.active_profile -> {
ProfileViewerDialog().also { pvd ->
pvd.arguments = Bundle().also {
- it.putLong("time", DateUtil.now())
+ it.putLong("time", dateUtil.now())
it.putInt("mode", ProfileViewerDialog.Mode.RUNNING_PROFILE.ordinal)
}
}.show(childFragmentManager, "ProfileViewDialog")
@@ -342,10 +348,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned()
?: "".toSpanned(), {
- uel.log("ACCEPT TEMP BASAL")
+ uel.log(Action.ACCEPTS_TEMP_BASAL, Sources.Overview)
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
- rxBus.send(EventWearDoAction("cancelChangeRequest"))
+ rxBus.send(EventWearInitiateAction("cancelChangeRequest"))
loopPlugin.acceptChangeRequest()
})
})
@@ -403,7 +409,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
private fun onClickQuickWizard() {
- val actualBg = iobCobCalculatorPlugin.actualBg()
+ val actualBg = iobCobCalculator.ads.actualBg()
val profile = profileFunction.getProfile()
val profileName = profileFunction.getProfileName()
val pump = activePlugin.activePump
@@ -438,11 +444,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@SuppressLint("SetTextI18n")
private fun processButtonsVisibility() {
- val lastBG = iobCobCalculatorPlugin.lastBg()
+ val lastBG = iobCobCalculator.ads.lastBg()
val pump = activePlugin.activePump
val profile = profileFunction.getProfile()
val profileName = profileFunction.getProfileName()
- val actualBG = iobCobCalculatorPlugin.actualBg()
+ val actualBG = iobCobCalculator.ads.actualBg()
// QuickWizard button
val quickWizardEntry = quickWizard.getActive()
@@ -541,7 +547,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (_binding == null) return
aapsLogger.debug("UpdateGUI from $from")
- binding.infoLayout.time.text = dateUtil.timeString(Date())
+ binding.infoLayout.time.text = dateUtil.timeString(dateUtil.now())
if (!profileFunction.isProfileValid("Overview")) {
binding.loopPumpStatusLayout.pumpStatus.setText(R.string.noprofileset)
@@ -554,8 +560,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
binding.loopPumpStatusLayout.loopLayout.visibility = View.VISIBLE
val profile = profileFunction.getProfile() ?: return
- val actualBG = iobCobCalculatorPlugin.actualBg()
- val lastBG = iobCobCalculatorPlugin.lastBg()
+ val actualBG = iobCobCalculator.ads.actualBg()
+ val lastBG = iobCobCalculator.ads.lastBg()
val pump = activePlugin.activePump
val units = profileFunction.getUnits()
val lowLine = defaultValueHelper.determineLowLine()
@@ -580,10 +586,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
binding.infoLayout.bg.text = lastBG.valueToUnitsString(units)
binding.infoLayout.bg.setTextColor(color)
- binding.infoLayout.arrow.setImageResource(lastBG.trendArrow.directionToIcon())
+ binding.infoLayout.arrow.setImageResource(trendCalculator.getTrendArrow(lastBG).directionToIcon())
binding.infoLayout.arrow.setColorFilter(color)
- val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
+ val glucoseStatus = glucoseStatusProvider.glucoseStatusData
if (glucoseStatus != null) {
binding.infoLayout.deltaLarge.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
binding.infoLayout.deltaLarge.setTextColor(color)
@@ -604,8 +610,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
} else flag and Paint.STRIKE_THRU_TEXT_FLAG.inv()
overview_bg.paintFlags = flag
}
- binding.infoLayout.timeAgo.text = DateUtil.minAgo(resourceHelper, lastBG.timestamp)
- binding.infoLayout.timeAgoShort.text = "(" + DateUtil.minAgoShort(lastBG.timestamp) + ")"
+ binding.infoLayout.timeAgo.text = dateUtil.minAgo(resourceHelper, lastBG.timestamp)
+ binding.infoLayout.timeAgoShort.text = "(" + dateUtil.minAgoShort(lastBG.timestamp) + ")"
}
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
@@ -617,24 +623,24 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
when {
loopPlugin.isEnabled() && loopPlugin.isSuperBolus -> {
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_superbolus)
- binding.infoLayout.apsModeText.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
+ binding.infoLayout.apsModeText.text = dateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
binding.infoLayout.apsModeText.visibility = View.VISIBLE
}
loopPlugin.isDisconnected -> {
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_disconnected)
- binding.infoLayout.apsModeText.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
+ binding.infoLayout.apsModeText.text = dateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
binding.infoLayout.apsModeText.visibility = View.VISIBLE
}
loopPlugin.isEnabled() && loopPlugin.isSuspended -> {
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_paused)
- binding.infoLayout.apsModeText.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
+ binding.infoLayout.apsModeText.text = dateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
binding.infoLayout.apsModeText.visibility = View.VISIBLE
}
pump.isSuspended() -> {
- binding.infoLayout.apsMode.setImageResource(if (pump.model() == PumpType.Omnipod_Eros || pump.model() == PumpType.Omnipod_Dash) {
+ binding.infoLayout.apsMode.setImageResource(if (pump.model() == PumpType.OMNIPOD_EROS || pump.model() == PumpType.OMNIPOD_DASH) {
// For Omnipod, indicate the pump as disconnected when it's suspended.
// The only way to 'reconnect' it, is through the Omnipod tab
R.drawable.ic_loop_disconnected
@@ -672,35 +678,35 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
// temp target
- val tempTarget = treatmentsPlugin.tempTargetFromHistory
- if (tempTarget != null) {
+ val tempTarget: ValueWrapper = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
+ if (tempTarget is ValueWrapper.Existing) {
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
- binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(tempTarget.low, tempTarget.high, Constants.MGDL, units) + " " + DateUtil.untilString(tempTarget.end(), resourceHelper)
+ binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(tempTarget.value.lowTarget, tempTarget.value.highTarget, GlucoseUnit.MGDL, units) + " " + dateUtil.untilString(tempTarget.value.end, resourceHelper)
} else {
// If the target is not the same as set in the profile then oref has overridden it
val targetUsed = lastRun?.constraintsProcessed?.targetBG ?: 0.0
- if (targetUsed != 0.0 && abs(profile.targetMgdl - targetUsed) > 0.01) {
- aapsLogger.debug("Adjusted target. Profile: ${profile.targetMgdl} APS: $targetUsed")
- binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(targetUsed, targetUsed, Constants.MGDL, units)
+ if (targetUsed != 0.0 && abs(profile.getTargetMgdl() - targetUsed) > 0.01) {
+ aapsLogger.debug("Adjusted target. Profile: ${profile.getTargetMgdl()} APS: $targetUsed")
+ binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(targetUsed, targetUsed, GlucoseUnit.MGDL, units)
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.tempTargetBackground))
} else {
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
- binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(profile.targetLowMgdl, profile.targetHighMgdl, Constants.MGDL, units)
+ binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(profile.getTargetLowMgdl(), profile.getTargetHighMgdl(), GlucoseUnit.MGDL, units)
}
}
// Basal, TBR
- val activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())
- binding.infoLayout.baseBasal.text = activeTemp?.let { "T:" + activeTemp.toStringVeryShort() }
- ?: resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)
+ val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis())
+ binding.infoLayout.baseBasal.text = activeTemp?.let { "T:" + activeTemp.toStringShort() }
+ ?: resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal())
binding.infoLayout.basalLayout.setOnClickListener {
- var fullText = "${resourceHelper.gs(R.string.basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)}"
+ var fullText = "${resourceHelper.gs(R.string.basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal())}"
if (activeTemp != null)
- fullText += "\n" + resourceHelper.gs(R.string.tempbasal_label) + ": " + activeTemp.toStringFull()
+ fullText += "\n" + resourceHelper.gs(R.string.tempbasal_label) + ": " + activeTemp.toStringFull(profile, dateUtil)
activity?.let {
OKDialog.show(it, resourceHelper.gs(R.string.basal), fullText)
}
@@ -709,26 +715,26 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
?: resourceHelper.gc(R.color.defaulttextcolor))
binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_no_tbr)
- val percentRate = activeTemp?.tempBasalConvertedToPercent(System.currentTimeMillis(), profile)
+ val percentRate = activeTemp?.convertedToPercent(System.currentTimeMillis(), profile)
?: 100
if (percentRate > 100) binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_tbr_high)
if (percentRate < 100) binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_tbr_low)
// Extended bolus
- val extendedBolus = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis())
+ val extendedBolus = repository.getExtendedBolusActiveAt(dateUtil.now()).blockingGet()
binding.infoLayout.extendedBolus.text =
- if (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses)
- resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.absoluteRate())
+ if (extendedBolus is ValueWrapper.Existing && !pump.isFakingTempsByExtendedBoluses)
+ resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.value.rate)
else ""
binding.infoLayout.extendedBolus.setOnClickListener {
- if (extendedBolus != null) activity?.let {
- OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), extendedBolus.toString())
+ if (extendedBolus is ValueWrapper.Existing) activity?.let {
+ OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), extendedBolus.value.toStringFull(dateUtil))
}
}
- binding.infoLayout.extendedLayout.visibility = (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses).toVisibility()
+ binding.infoLayout.extendedLayout.visibility = (extendedBolus is ValueWrapper.Existing && !pump.isFakingTempsByExtendedBoluses).toVisibility()
// Active profile
- binding.loopPumpStatusLayout.activeProfile.text = profileFunction.getProfileNameWithDuration()
+ binding.loopPumpStatusLayout.activeProfile.text = profileFunction.getProfileNameWithRemainingTime()
if (profile.percentage != 100 || profile.timeshift != 0) {
binding.loopPumpStatusLayout.activeProfile.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
binding.loopPumpStatusLayout.activeProfile.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
@@ -740,10 +746,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
processButtonsVisibility()
// iob
- treatmentsPlugin.updateTotalIOBTreatments()
- treatmentsPlugin.updateTotalIOBTempBasals()
- val bolusIob = treatmentsPlugin.lastCalculationTreatments.round()
- val basalIob = treatmentsPlugin.lastCalculationTempBasals.round()
+ val bolusIob = iobCobCalculator.calculateIobFromBolus().round()
+ val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
binding.infoLayout.iob.text = resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob)
binding.infoLayout.iobLayout.setOnClickListener {
@@ -762,7 +766,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// cob
var cobText: String = resourceHelper.gs(R.string.value_unavailable_short)
- val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Overview COB")
+ val cobInfo = iobCobCalculator.getCobInfo(false, "Overview COB")
if (cobInfo.displayCob != null) {
cobText = resourceHelper.gs(R.string.format_carbs, cobInfo.displayCob!!.toInt())
if (cobInfo.futureCarbs > 0) cobText += "(" + DecimalFormatter.to0Decimal(cobInfo.futureCarbs) + ")"
@@ -771,7 +775,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (config.APS && lastRun?.constraintsProcessed != null) {
if (lastRun.constraintsProcessed!!.carbsReq > 0) {
//only display carbsreq when carbs have not been entered recently
- if (treatmentsPlugin.lastCarbTime < lastRun.lastAPSRun) {
+ val lastCarb = repository.getLastCarbsRecordWrapped().blockingGet()
+ val lastCarbsTime = if (lastCarb is ValueWrapper.Existing) lastCarb.value.timestamp else 0L
+ if (lastCarbsTime < lastRun.lastAPSRun) {
cobText = cobText + " | " + lastRun.constraintsProcessed!!.carbsReq + " " + resourceHelper.gs(R.string.required)
}
binding.infoLayout.cob.text = cobText
@@ -804,17 +810,17 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
binding.infoLayout.sensitivity.text =
- iobCobCalculatorPlugin.getLastAutosensData("Overview")?.let { autosensData ->
+ iobCobCalculator.ads.getLastAutosensData("Overview", aapsLogger, dateUtil)?.let { autosensData ->
String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)
} ?: ""
}
- private fun updateGraph(lastRun: LoopInterface.LastRun?, predictionsAvailable: Boolean, lowLine: Double, highLine: Double, pump: PumpInterface, profile: Profile) {
+ private fun updateGraph(lastRun: LoopInterface.LastRun?, predictionsAvailable: Boolean, lowLine: Double, highLine: Double, pump: Pump, profile: Profile) {
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
if (_binding == null) return@launch
val menuChartSettings = overviewMenus.setting
prepareGraphsIfNeeded(menuChartSettings.size)
- val graphData = GraphData(injector, binding.graphsLayout.bgGraph, iobCobCalculatorPlugin, treatmentsPlugin)
+ val graphData = GraphData(injector, binding.graphsLayout.bgGraph, iobCobCalculator)
val secondaryGraphsData: ArrayList = ArrayList()
// do preparation in different thread
@@ -830,7 +836,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
val toTime: Long
val fromTime: Long
val endTime: Long
- val apsResult = if (config.APS) lastRun?.constraintsProcessed else NSDeviceStatus.getAPSResult(injector)
+ val apsResult = if (config.APS) lastRun?.constraintsProcessed else nsDeviceStatus.getAPSResult(injector)
if (predictionsAvailable && apsResult != null && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal]) {
var predictionHours = (ceil(apsResult.latestPredictionsTime - System.currentTimeMillis().toDouble()) / (60 * 60 * 1000)).toInt()
predictionHours = min(2, predictionHours)
@@ -854,8 +860,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// **** BG ****
if (predictionsAvailable && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal])
- graphData.addBgReadings(fromTime, toTime, lowLine, highLine, apsResult?.predictions)
- else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null)
+ graphData.addBgReadings(fromTime, toTime, highLine, apsResult?.predictions?.map { bg-> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper) }?.toMutableList())
+ else graphData.addBgReadings(fromTime, toTime, highLine, null)
+ if (buildHelper.isDev()) graphData.addBucketedData(fromTime, toTime)
// Treatments
graphData.addTreatments(fromTime, endTime)
@@ -881,7 +888,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// ------------------ 2nd graph
synchronized(graphLock) {
for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) {
- val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculatorPlugin, treatmentsPlugin)
+ val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculator)
var useABSForScale = false
var useIobForScale = false
var useCobForScale = false
@@ -894,8 +901,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
- menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true
+ menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
}
val alignIobScale = menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]
@@ -905,8 +912,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal], alignIobScale)
if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5)
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0, alignDevBgiScale)
- if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0)
if (menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]) secondGraphData.addMinusBGI(fromTime, endTime, useBGIForScale, if (alignDevBgiScale) 1.0 else 0.8, alignDevBgiScale)
+ if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, now, useRatioForScale, if (useRatioForScale) 1.0 else 0.8)
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0)
// set manual x bounds to have nice steps
@@ -926,8 +933,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] ||
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] ||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] ||
- menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] ||
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] ||
+ menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] ||
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal]
).toVisibility()
secondaryGraphsData[g].performUpdate()
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt
index fe9f14bb81..1dfa734247 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt
@@ -9,7 +9,7 @@ import androidx.annotation.ColorRes
import androidx.annotation.StringRes
import androidx.appcompat.widget.PopupMenu
import com.google.gson.Gson
-import info.nightscout.androidaps.Config
+import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.logging.AAPSLogger
@@ -38,10 +38,10 @@ class OverviewMenus @Inject constructor(
ABS(R.string.overview_show_absinsulin, R.color.iob, primary = false, secondary = true,shortnameId = R.string.abs_insulin_shortname),
IOB(R.string.overview_show_iob, R.color.iob, primary = false, secondary = true,shortnameId = R.string.iob),
COB(R.string.overview_show_cob, R.color.cob, primary = false, secondary = true,shortnameId = R.string.cob),
- DEV(R.string.overview_show_deviations, R.color.deviations, primary = false, secondary = true,shortnameId = R.string.deviation_shortname),
+ DEV(R.string.overview_show_deviations, R.color.bgi, primary = false, secondary = true,shortnameId = R.string.deviation_shortname),
+ BGI(R.string.overview_show_bgi, R.color.bgi, primary = false, secondary = true,shortnameId = R.string.bgi_shortname),
SEN(R.string.overview_show_sensitivity, R.color.ratio, primary = false, secondary = true,shortnameId = R.string.sensitivity_shortname),
ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = false,shortnameId = R.string.activity_shortname),
- BGI(R.string.overview_show_bgi, R.color.bgi, primary = false, secondary = true,shortnameId = R.string.bgi_shortname),
DEVSLOPE(R.string.overview_show_deviationslope, R.color.devslopepos, primary = false, secondary = true,shortnameId = R.string.devslope_shortname)
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt
index d8308f346e..8aadd2ea34 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewPlugin.kt
@@ -3,10 +3,11 @@ package info.nightscout.androidaps.plugins.general.overview
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import dagger.android.HasAndroidInjector
-import info.nightscout.androidaps.Config
+import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventRefreshOverview
-import info.nightscout.androidaps.interfaces.OverviewInterface
+import info.nightscout.androidaps.extensions.*
+import info.nightscout.androidaps.interfaces.Overview
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
@@ -16,7 +17,6 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNo
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
import info.nightscout.androidaps.utils.FabricPrivacy
-import info.nightscout.androidaps.utils.extensions.*
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
@@ -48,7 +48,7 @@ class OverviewPlugin @Inject constructor(
.preferencesId(R.xml.pref_overview)
.description(R.string.description_overview),
aapsLogger, resourceHelper, injector
-), OverviewInterface {
+), Overview {
private var disposable: CompositeDisposable = CompositeDisposable()
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt
index c414d1c5a2..917ff84630 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt
@@ -3,16 +3,19 @@ package info.nightscout.androidaps.plugins.general.overview
import android.graphics.Color
import android.widget.TextView
import androidx.annotation.StringRes
-import info.nightscout.androidaps.Config
-import info.nightscout.androidaps.MainApp
+import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.R
-import info.nightscout.androidaps.db.CareportalEvent
-import info.nightscout.androidaps.interfaces.ActivePluginProvider
+import info.nightscout.androidaps.database.AppRepository
+import info.nightscout.androidaps.database.ValueWrapper
+import info.nightscout.androidaps.database.entities.TherapyEvent
+import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.OmnipodConstants
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.WarnColors
+import info.nightscout.androidaps.extensions.age
+import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject
@@ -22,9 +25,11 @@ import javax.inject.Singleton
class StatusLightHandler @Inject constructor(
private val resourceHelper: ResourceHelper,
private val sp: SP,
- private val activePlugin: ActivePluginProvider,
+ private val dateUtil: DateUtil,
+ private val activePlugin: ActivePlugin,
private val warnColors: WarnColors,
- private val config: Config
+ private val config: Config,
+ private val repository: AppRepository
) {
/**
@@ -33,14 +38,14 @@ class StatusLightHandler @Inject constructor(
fun updateStatusLights(careportal_cannula_age: TextView?, careportal_insulin_age: TextView?, careportal_reservoir_level: TextView?, careportal_sensor_age: TextView?, careportal_sensor_battery_level: TextView?, careportal_pb_age: TextView?, careportal_battery_level: TextView?) {
val pump = activePlugin.activePump
val bgSource = activePlugin.activeBgSource
- handleAge(careportal_cannula_age, CareportalEvent.SITECHANGE, R.string.key_statuslights_cage_warning, 48.0, R.string.key_statuslights_cage_critical, 72.0)
- handleAge(careportal_insulin_age, CareportalEvent.INSULINCHANGE, R.string.key_statuslights_iage_warning, 72.0, R.string.key_statuslights_iage_critical, 144.0)
- handleAge(careportal_sensor_age, CareportalEvent.SENSORCHANGE, R.string.key_statuslights_sage_warning, 216.0, R.string.key_statuslights_sage_critical, 240.0)
+ handleAge(careportal_cannula_age, TherapyEvent.Type.CANNULA_CHANGE, R.string.key_statuslights_cage_warning, 48.0, R.string.key_statuslights_cage_critical, 72.0)
+ handleAge(careportal_insulin_age, TherapyEvent.Type.INSULIN_CHANGE, R.string.key_statuslights_iage_warning, 72.0, R.string.key_statuslights_iage_critical, 144.0)
+ handleAge(careportal_sensor_age, TherapyEvent.Type.SENSOR_CHANGE, R.string.key_statuslights_sage_warning, 216.0, R.string.key_statuslights_sage_critical, 240.0)
if (pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)) {
- handleAge(careportal_pb_age, CareportalEvent.PUMPBATTERYCHANGE, R.string.key_statuslights_bage_warning, 216.0, R.string.key_statuslights_bage_critical, 240.0)
+ handleAge(careportal_pb_age, TherapyEvent.Type.PUMP_BATTERY_CHANGE, R.string.key_statuslights_bage_warning, 216.0, R.string.key_statuslights_bage_critical, 240.0)
}
if (!config.NSCLIENT) {
- if (pump.model() == PumpType.Omnipod_Eros || pump.model() == PumpType.Omnipod_Dash) {
+ if (pump.model() == PumpType.OMNIPOD_EROS || pump.model() == PumpType.OMNIPOD_DASH) {
handleOmnipodReservoirLevel(careportal_reservoir_level, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, "U")
} else {
handleLevel(careportal_reservoir_level, R.string.key_statuslights_res_critical, 10.0, R.string.key_statuslights_res_warning, 80.0, pump.reservoirLevel, "U")
@@ -52,27 +57,27 @@ class StatusLightHandler @Inject constructor(
}
if (!config.NSCLIENT) {
- if (pump.model() == PumpType.Omnipod_Dash) {
+ if (pump.model() == PumpType.OMNIPOD_DASH) {
// Omnipod Dash does not report its battery level
careportal_battery_level?.text = resourceHelper.gs(R.string.notavailable)
careportal_battery_level?.setTextColor(Color.WHITE)
- } else if (pump.model() == PumpType.Omnipod_Eros && pump is OmnipodErosPumpPlugin) { // instance of check is needed because at startup, pump can still be VirtualPumpPlugin and that will cause a crash because of the class cast below
+ } else if (pump.model() == PumpType.OMNIPOD_EROS && pump is OmnipodErosPumpPlugin) { // instance of check is needed because at startup, pump can still be VirtualPumpPlugin and that will cause a crash because of the class cast below
// The Omnipod Eros does not report its battery level. However, some RileyLink alternatives do.
// Depending on the user's configuration, we will either show the battery level reported by the RileyLink or "n/a"
handleOmnipodErosBatteryLevel(careportal_battery_level, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%", pump.isUseRileyLinkBatteryLevel)
- } else if (pump.model() != PumpType.AccuChekCombo) {
+ } else if (pump.model() != PumpType.ACCU_CHEK_COMBO) {
handleLevel(careportal_battery_level, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%")
}
}
}
- private fun handleAge(view: TextView?, eventName: String, @StringRes warnSettings: Int, defaultWarnThreshold: Double, @StringRes urgentSettings: Int, defaultUrgentThreshold: Double) {
+ private fun handleAge(view: TextView?, type: TherapyEvent.Type, @StringRes warnSettings: Int, defaultWarnThreshold: Double, @StringRes urgentSettings: Int, defaultUrgentThreshold: Double) {
val warn = sp.getDouble(warnSettings, defaultWarnThreshold)
val urgent = sp.getDouble(urgentSettings, defaultUrgentThreshold)
- val careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(eventName)
- if (careportalEvent != null) {
- warnColors.setColorByAge(view, careportalEvent, warn, urgent)
- view?.text = careportalEvent.age(resourceHelper.shortTextMode(), resourceHelper)
+ val therapyEvent = repository.getLastTherapyRecord(type).blockingGet()
+ if (therapyEvent is ValueWrapper.Existing) {
+ warnColors.setColorByAge(view, therapyEvent.value, warn, urgent)
+ view?.text = therapyEvent.value.age(resourceHelper.shortTextMode(), resourceHelper, dateUtil)
} else {
view?.text = if (resourceHelper.shortTextMode()) "-" else resourceHelper.gs(R.string.notavailable)
}
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/EditQuickWizardDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/EditQuickWizardDialog.kt
index 237afba172..366850607f 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/EditQuickWizardDialog.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/dialogs/EditQuickWizardDialog.kt
@@ -83,7 +83,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
// create an OnTimeSetListener
val fromTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
fromSeconds = (T.hours(hour.toLong()).secs() + T.mins(minute.toLong()).secs()).toInt()
- binding.from.text = dateUtil.timeString(DateUtil.toDate(fromSeconds))
+ binding.from.text = dateUtil.timeString(dateUtil.secondsOfTheDayToMilliseconds(fromSeconds))
}
binding.from.setOnClickListener {
@@ -96,11 +96,11 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
}
}
fromSeconds = entry.validFrom()
- binding.from.text = dateUtil.timeString(DateUtil.toDate(fromSeconds))
+ binding.from.text = dateUtil.timeString(dateUtil.secondsOfTheDayToMilliseconds(fromSeconds))
val toTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
toSeconds = (T.hours(hour.toLong()).secs() + T.mins(minute.toLong()).secs()).toInt()
- binding.from.text = dateUtil.timeString(DateUtil.toDate(toSeconds))
+ binding.from.text = dateUtil.timeString(dateUtil.secondsOfTheDayToMilliseconds(toSeconds))
}
binding.to.setOnClickListener {
@@ -113,7 +113,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
}
}
toSeconds = entry.validFrom()
- binding.to.text = dateUtil.timeString(DateUtil.toDate(toSeconds))
+ binding.to.text = dateUtil.timeString(dateUtil.secondsOfTheDayToMilliseconds(toSeconds))
binding.buttonEdit.setText(entry.buttonText())
binding.carbsEdit.setText(entry.carbs().toString())
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt
index b0f526b2c7..a4da17f159 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt
@@ -9,25 +9,20 @@ import com.jjoe64.graphview.series.DataPoint
import com.jjoe64.graphview.series.LineGraphSeries
import com.jjoe64.graphview.series.Series
import dagger.android.HasAndroidInjector
-import info.nightscout.androidaps.Constants
-import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
-import info.nightscout.androidaps.data.GlucoseValueDataPoint
import info.nightscout.androidaps.data.IobTotal
-import info.nightscout.androidaps.data.Profile
+import info.nightscout.androidaps.database.AppRepository
+import info.nightscout.androidaps.database.ValueWrapper
+import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.database.entities.GlucoseValue
-import info.nightscout.androidaps.interfaces.ActivePluginProvider
-import info.nightscout.androidaps.interfaces.LoopInterface
-import info.nightscout.androidaps.interfaces.ProfileFunction
-import info.nightscout.androidaps.interfaces.TreatmentsInterface
+import info.nightscout.androidaps.extensions.target
+import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
-import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
-import info.nightscout.androidaps.utils.DecimalFormatter
-import info.nightscout.androidaps.utils.Round
+import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.resources.ResourceHelper
import java.util.*
import javax.inject.Inject
@@ -36,23 +31,26 @@ import kotlin.math.max
import kotlin.math.min
class GraphData(
- private val injector: HasAndroidInjector,
+ injector: HasAndroidInjector,
private val graph: GraphView,
- private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
- private val treatmentsPlugin: TreatmentsInterface
-
+ private val iobCobCalculator: IobCobCalculator
) {
// IobCobCalculatorPlugin Cannot be injected: HistoryBrowser
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var resourceHelper: ResourceHelper
- @Inject lateinit var activePlugin: ActivePluginProvider
+ @Inject lateinit var activePlugin: ActivePlugin
+ @Inject lateinit var databaseHelper: DatabaseHelperInterface
+ @Inject lateinit var repository: AppRepository
+ @Inject lateinit var dateUtil: DateUtil
+ @Inject lateinit var defaultValueHelper: DefaultValueHelper
+ @Inject lateinit var translator: Translator
var maxY = Double.MIN_VALUE
private var minY = Double.MAX_VALUE
private var bgReadingsArray: List? = null
- private val units: String
+ private val units: GlucoseUnit
private val series: MutableList> = ArrayList()
init {
@@ -60,13 +58,26 @@ class GraphData(
units = profileFunction.getUnits()
}
- @Suppress("UNUSED_PARAMETER")
- fun addBgReadings(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double, predictions: MutableList?) {
+ fun addBucketedData(fromTime: Long, toTime: Long) {
+ val bucketedData = iobCobCalculator.ads.getBucketedDataTableCopy() ?: return
+ if (bucketedData.isEmpty()) {
+ aapsLogger.debug("No bucketed data.")
+ return
+ }
+ val bucketedListArray: MutableList = ArrayList()
+ for (inMemoryGlucoseValue in bucketedData) {
+ if (inMemoryGlucoseValue.timestamp < fromTime || inMemoryGlucoseValue.timestamp > toTime) continue
+ bucketedListArray.add(InMemoryGlucoseValueDataPoint(inMemoryGlucoseValue, profileFunction, resourceHelper))
+ }
+ addSeries(PointsWithLabelGraphSeries(Array(bucketedListArray.size) { i -> bucketedListArray[i] }))
+ }
+
+ fun addBgReadings(fromTime: Long, toTime: Long, highLine: Double, predictions: MutableList?) {
var maxBgValue = Double.MIN_VALUE
- bgReadingsArray = iobCobCalculatorPlugin.bgReadings
+ bgReadingsArray = repository.compatGetBgReadingsDataFromTime(fromTime, toTime, false).blockingGet()
if (bgReadingsArray?.isEmpty() != false) {
aapsLogger.debug("No BG data.")
- maxY = if (units == Constants.MGDL) 180.0 else 10.0
+ maxY = if (units == GlucoseUnit.MGDL) 180.0 else 10.0
minY = 0.0
return
}
@@ -74,7 +85,7 @@ class GraphData(
for (bg in bgReadingsArray!!) {
if (bg.timestamp < fromTime || bg.timestamp > toTime) continue
if (bg.value > maxBgValue) maxBgValue = bg.value
- bgListArray.add(GlucoseValueDataPoint(injector, bg))
+ bgListArray.add(GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, resourceHelper))
}
if (predictions != null) {
predictions.sortWith(Comparator { o1: GlucoseValueDataPoint, o2: GlucoseValueDataPoint -> o1.x.compareTo(o2.x) })
@@ -88,12 +99,8 @@ class GraphData(
addSeries(PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }))
}
- internal fun setNumVerticalLabels() {
- graph.gridLabelRenderer.numVerticalLabels = if (units == Constants.MGDL) (maxY / 40 + 1).toInt() else (maxY / 2 + 1).toInt()
- }
-
private fun addUpperChartMargin(maxBgValue: Double) =
- if (units == Constants.MGDL) Round.roundTo(maxBgValue, 40.0) + 80 else Round.roundTo(maxBgValue, 2.0) + 4
+ if (units == GlucoseUnit.MGDL) Round.roundTo(maxBgValue, 40.0) + 80 else Round.roundTo(maxBgValue, 2.0) + 4
fun addInRangeArea(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double) {
val inRangeAreaSeries: AreaGraphSeries
@@ -127,7 +134,7 @@ class GraphData(
time += 60 * 1000L
continue
}
- val basalData = iobCobCalculatorPlugin.getBasalData(profile, time)
+ val basalData = iobCobCalculator.getBasalData(profile, time)
val baseBasalValue = basalData.basal
var absoluteLineValue = baseBasalValue
var tempBasalValue = 0.0
@@ -212,11 +219,11 @@ class GraphData(
lastRun?.constraintsProcessed?.let { toTime = max(it.latestPredictionsTime, toTime) }
var time = fromTime
while (time < toTime) {
- val tt = treatmentsPlugin.getTempTargetFromHistory(time)
- val value: Double = if (tt == null) {
- Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, units)
+ val tt = repository.getTemporaryTargetActiveAt(time).blockingGet()
+ val value: Double = if (tt is ValueWrapper.Existing) {
+ Profile.fromMgdlToUnits(tt.value.target(), units)
} else {
- Profile.fromMgdlToUnits(tt.target(), units)
+ Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, units)
}
if (lastTarget != value) {
if (lastTarget != -1.0) targetsSeriesArray.add(DataPoint(time.toDouble(), lastTarget))
@@ -237,23 +244,29 @@ class GraphData(
fun addTreatments(fromTime: Long, endTime: Long) {
val filteredTreatments: MutableList = ArrayList()
- treatmentsPlugin.treatmentsFromHistory
- .filterTimeframe(fromTime, endTime)
- .filter { !it.isSMB || it.isValid }
+ repository.getBolusesIncludingInvalidFromTimeToTime(fromTime, endTime, true).blockingGet()
+ .map { BolusDataPoint(it, resourceHelper, activePlugin, defaultValueHelper) }
+ .filter { it.data.type != Bolus.Type.SMB || it.data.isValid }
+ .forEach {
+ it.y = getNearestBg(it.x.toLong())
+ filteredTreatments.add(it)
+ }
+ repository.getCarbsIncludingInvalidFromTimeToTimeExpanded(fromTime, endTime, true).blockingGet()
+ .map { CarbsDataPoint(it, resourceHelper) }
.forEach {
it.y = getNearestBg(it.x.toLong())
filteredTreatments.add(it)
}
// ProfileSwitch
- treatmentsPlugin.profileSwitchesFromHistory.list
- .filterTimeframe(fromTime, endTime)
- .forEach(filteredTreatments::add)
+ repository.getEffectiveProfileSwitchDataFromTimeToTime(fromTime, endTime, true).blockingGet()
+ .map { EffectiveProfileSwitchDataPoint(it) }
+ .forEach(filteredTreatments::add)
// Extended bolus
if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) {
- treatmentsPlugin.extendedBolusesFromHistory.list
- .filterTimeframe(fromTime, endTime)
+ repository.getExtendedBolusDataFromTimeToTime(fromTime, endTime, true).blockingGet()
+ .map { ExtendedBolusDataPoint(it) }
.filter { it.duration != 0L }
.forEach {
it.y = getNearestBg(it.x.toLong())
@@ -262,10 +275,11 @@ class GraphData(
}
// Careportal
- MainApp.getDbHelper().getCareportalEventsFromTime(fromTime - 6 * 60 * 60 * 1000, true)
+ repository.compatGetTherapyEventDataFromToTime(fromTime - T.hours(6).msecs(), endTime).blockingGet()
+ .map { TherapyEventDataPoint(it, resourceHelper, profileFunction, translator) }
.filterTimeframe(fromTime, endTime)
.forEach {
- it.y = getNearestBg(it.x.toLong())
+ if (it.y == 0.0) it.y = getNearestBg(it.x.toLong())
filteredTreatments.add(it)
}
@@ -280,8 +294,7 @@ class GraphData(
private fun getNearestBg(date: Long): Double {
bgReadingsArray?.let { bgReadingsArray ->
- for (r in bgReadingsArray.indices) {
- val reading = bgReadingsArray[r]
+ for (reading in bgReadingsArray) {
if (reading.timestamp > date) continue
return Profile.fromMgdlToUnits(reading.value, units)
}
@@ -303,7 +316,7 @@ class GraphData(
time += 5 * 60 * 1000L
continue
}
- total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
+ total = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile)
val act: Double = total.activity
if (time <= now) actArrayHist.add(ScaledDataPoint(time, act, actScale)) else actArrayPrediction.add(ScaledDataPoint(time, act, actScale))
maxIAValue = max(maxIAValue, abs(act))
@@ -344,9 +357,10 @@ class GraphData(
time += 5 * 60 * 1000L
continue
}
- val deviation = if (devBgiScale) iobCobCalculatorPlugin.getAutosensData(time)?.deviation ?:0.0 else 0.0
+ val deviation = if (devBgiScale) iobCobCalculator.ads.getAutosensDataAtTime(time)?.deviation
+ ?: 0.0 else 0.0
- total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
+ total = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile)
val bgi: Double = total.activity * profile.getIsfMgdl(time) * 5.0
if (time <= now) bgiArrayHist.add(ScaledDataPoint(time, bgi, bgiScale)) else bgiArrayPrediction.add(ScaledDataPoint(time, bgi, bgiScale))
maxBGIValue = max(maxBGIValue, max(abs(bgi), deviation))
@@ -382,12 +396,14 @@ class GraphData(
var time = fromTime
while (time <= toTime) {
val profile = profileFunction.getProfile(time)
+ if (profile == null) {
+ time += 5 * 60 * 1000L
+ continue
+ }
var iob = 0.0
var absIob = 0.0
- if (profile != null) {
- iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile).iob
- if (absScale) absIob = iobCobCalculatorPlugin.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time).iob
- }
+ iob = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile).iob
+ if (absScale) absIob = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTemps(time).iob
if (abs(lastIob - iob) > 0.02) {
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
iobArray.add(ScaledDataPoint(time, iob, iobScale))
@@ -403,25 +419,25 @@ class GraphData(
it.thickness = 3
}
if (showPrediction) {
- val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("GraphData")
+ val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("GraphData")
val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult()
- val isTempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis()) != null
+ val isTempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing
val iobPrediction: MutableList = ArrayList()
- val iobPredictionArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
+ val iobPredictionArray = iobCobCalculator.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
for (i in iobPredictionArray) {
iobPrediction.add(i.setColor(resourceHelper.gc(R.color.iobPredAS)))
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
}
addSeries(PointsWithLabelGraphSeries(Array(iobPrediction.size) { i -> iobPrediction[i] }))
val iobPrediction2: MutableList = ArrayList()
- val iobPredictionArray2 = iobCobCalculatorPlugin.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
+ val iobPredictionArray2 = iobCobCalculator.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
for (i in iobPredictionArray2) {
iobPrediction2.add(i.setColor(resourceHelper.gc(R.color.iobPred)))
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
}
addSeries(PointsWithLabelGraphSeries(Array(iobPrediction2.size) { i -> iobPrediction2[i] }))
- aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredictionArray))
- aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredictionArray2))
+ aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray))
+ aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray2))
}
if (useForScale) {
maxY = maxIobValueFound
@@ -441,8 +457,12 @@ class GraphData(
var time = fromTime
while (time <= toTime) {
val profile = profileFunction.getProfile(time)
+ if (profile == null) {
+ time += 5 * 60 * 1000L
+ continue
+ }
var iob = 0.0
- if (profile != null) iob = iobCobCalculatorPlugin.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time).iob
+ iob = iobCobCalculator.calculateAbsInsulinFromTreatmentsAndTemps(time).iob
if (abs(lastIob - iob) > 0.02) {
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
iobArray.add(ScaledDataPoint(time, iob, iobScale))
@@ -474,7 +494,7 @@ class GraphData(
val cobScale = Scale()
var time = fromTime
while (time <= toTime) {
- iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
+ iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData ->
val cob = autosensData.cob.toInt()
if (cob != lastCob) {
if (autosensData.carbsFromBolus > 0) cobArray.add(ScaledDataPoint(time, lastCob.toDouble(), cobScale))
@@ -519,12 +539,16 @@ class GraphData(
while (time <= toTime) {
// if align Dev Scale with BGI scale, then calculate BGI value, else bgi = 0.0
val bgi: Double = if (devBgiScale) {
- val profile = profileFunction.getProfile(time)
- total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
- total.activity * (profile?.getIsfMgdl(time) ?: 0.0) * 5.0
- } else 0.0
+ val profile = profileFunction.getProfile(time)
+ if (profile == null) {
+ time += 5 * 60 * 1000L
+ continue
+ }
+ total = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile)
+ total.activity * profile.getIsfMgdl(time) * 5.0
+ } else 0.0
- iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
+ iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData ->
var color = resourceHelper.gc(R.color.deviationblack) // "="
if (autosensData.type == "" || autosensData.type == "non-meal") {
if (autosensData.pastSensitivity == "C") color = resourceHelper.gc(R.color.deviationgrey)
@@ -555,15 +579,15 @@ class GraphData(
// scale in % of vertical size (like 0.3)
fun addRatio(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
val ratioArray: MutableList = ArrayList()
- var maxRatioValueFound = Double.MIN_VALUE
- var minRatioValueFound = Double.MAX_VALUE
- val ratioScale = Scale()
+ var maxRatioValueFound = 5.0 //even if sens data equals 0 for all the period, minimum scale is between 95% and 105%
+ var minRatioValueFound = -maxRatioValueFound
+ val ratioScale = if (useForScale) Scale(100.0) else Scale()
var time = fromTime
while (time <= toTime) {
- iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
- ratioArray.add(ScaledDataPoint(time, autosensData.autosensResult.ratio - 1, ratioScale))
- maxRatioValueFound = max(maxRatioValueFound, autosensData.autosensResult.ratio - 1)
- minRatioValueFound = min(minRatioValueFound, autosensData.autosensResult.ratio - 1)
+ iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData ->
+ ratioArray.add(ScaledDataPoint(time, 100.0 * (autosensData.autosensResult.ratio - 1), ratioScale))
+ maxRatioValueFound = max(maxRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1))
+ minRatioValueFound = min(minRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1))
}
time += 5 * 60 * 1000L
}
@@ -574,10 +598,11 @@ class GraphData(
it.thickness = 3
})
if (useForScale) {
- maxY = max(maxRatioValueFound, abs(minRatioValueFound))
- minY = -maxY
- }
- ratioScale.setMultiplier(maxY * scale / max(maxRatioValueFound, abs(minRatioValueFound)))
+ maxY = 100.0 + max(maxRatioValueFound, abs(minRatioValueFound))
+ minY = 100.0 - max(maxRatioValueFound, abs(minRatioValueFound))
+ ratioScale.setMultiplier(1.0)
+ } else
+ ratioScale.setMultiplier(maxY * scale / max(maxRatioValueFound, abs(minRatioValueFound)))
}
// scale in % of vertical size (like 0.3)
@@ -590,7 +615,7 @@ class GraphData(
val dsMinScale = Scale()
var time = fromTime
while (time <= toTime) {
- iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
+ iobCobCalculator.ads.getAutosensDataAtTime(time)?.let { autosensData ->
dsMaxArray.add(ScaledDataPoint(time, autosensData.slopeFromMaxDeviation, dsMaxScale))
dsMinArray.add(ScaledDataPoint(time, autosensData.slopeFromMinDeviation, dsMinScale))
maxFromMaxValueFound = max(maxFromMaxValueFound, abs(autosensData.slopeFromMaxDeviation))
@@ -634,6 +659,10 @@ class GraphData(
})
}
+ fun setNumVerticalLabels() {
+ graph.gridLabelRenderer.numVerticalLabels = if (units == GlucoseUnit.MGDL) (maxY / 40 + 1).toInt() else (maxY / 2 + 1).toInt()
+ }
+
fun formatAxis(fromTime: Long, endTime: Long) {
graph.viewport.setMaxX(endTime.toDouble())
graph.viewport.setMinX(fromTime.toDouble())
diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/AreaGraphSeries.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/AreaGraphSeries.java
index 6d6cf27b51..1eef5c790c 100644
--- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/AreaGraphSeries.java
+++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphExtensions/AreaGraphSeries.java
@@ -39,7 +39,7 @@ public class AreaGraphSeries extends BaseSeries {
/**
* wrapped styles regarding the line
*/
- private final class Styles {
+ private static final class Styles {
/**
* the thickness of the line.
* This option will be ignored if you are
@@ -115,7 +115,7 @@ public class AreaGraphSeries extends BaseSeries