From a2fbab02f9662be6acb3fd67d5304c3fabbc9a5b Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Fri, 19 Mar 2021 18:49:34 +0100 Subject: [PATCH 1/9] food -> Room --- .../info/nightscout/androidaps/MainApp.kt | 1 + .../androidaps/db/CompatDBHelper.kt | 6 + .../dependencyInjection/DataClassesModule.kt | 2 - .../dependencyInjection/WorkersModule.kt | 2 + .../androidaps/events/EventNsFood.kt | 20 - .../androidaps/plugins/general/food/Food.java | 145 - .../plugins/general/food/FoodFragment.kt | 110 +- .../plugins/general/food/FoodPlugin.kt | 89 +- .../plugins/general/food/FoodService.java | 359 -- .../general/maintenance/ImportExportPrefs.kt | 10 +- .../maintenance/MaintenanceFragment.kt | 3 - .../nsclient/services/NSClientService.java | 46 +- .../androidaps/receivers/DataReceiver.kt | 28 +- .../nightscout/androidaps/services/Intents.kt | 1 + app/src/main/res/layout/food_fragment.xml | 14 +- app/src/main/res/layout/food_item.xml | 36 +- app/src/main/res/values/strings.xml | 2 +- .../interfaces/ImportExportPrefsInterface.kt | 2 +- .../nightscout/androidaps/utils/JsonHelper.kt | 17 +- .../utils/extensions/FoodExtension.kt | 40 + .../7.json | 2924 +++++++++++++++++ .../androidaps/database/AppDatabase.kt | 7 +- .../androidaps/database/AppRepository.kt | 9 + .../androidaps/database/DatabaseModule.kt | 6 + .../database/DelegatedAppDatabase.kt | 1 + .../androidaps/database/TableNames.kt | 1 + .../androidaps/database/daos/FoodDao.kt | 25 + .../androidaps/database/daos/TraceableDao.kt | 1 - .../daos/delegated/DelegatedFoodDao.kt | 18 + .../androidaps/database/entities/Food.kt | 73 + .../androidaps/database/entities/UserEntry.kt | 1 + .../InsertOrUpdateFoodTransaction.kt | 28 + .../transactions/InvalidateFoodTransaction.kt | 11 + .../transactions/SyncFoodTransaction.kt | 42 + 34 files changed, 3437 insertions(+), 643 deletions(-) delete mode 100644 app/src/main/java/info/nightscout/androidaps/events/EventNsFood.kt delete mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/food/Food.java delete mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodService.java create mode 100644 core/src/main/java/info/nightscout/androidaps/utils/extensions/FoodExtension.kt create mode 100644 database/schemas/info.nightscout.androidaps.database.AppDatabase/7.json create mode 100644 database/src/main/java/info/nightscout/androidaps/database/daos/FoodDao.kt create mode 100644 database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedFoodDao.kt create mode 100644 database/src/main/java/info/nightscout/androidaps/database/entities/Food.kt create mode 100644 database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateFoodTransaction.kt create mode 100644 database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateFoodTransaction.kt create mode 100644 database/src/main/java/info/nightscout/androidaps/database/transactions/SyncFoodTransaction.kt diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.kt b/app/src/main/java/info/nightscout/androidaps/MainApp.kt index da263b17de..420f27427d 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.kt @@ -109,6 +109,7 @@ class MainApp : DaggerApplication() { filter.addAction(Intents.ACTION_NEW_PROFILE) filter.addAction(Intents.ACTION_NEW_MBG) filter.addAction(Intents.ACTION_NEW_CAL) + filter.addAction(Intents.ACTION_FOOD) LocalBroadcastManager.getInstance(this).registerReceiver(DataReceiver(), filter) filter = IntentFilter() filter.addAction(Intent.ACTION_TIME_CHANGED) diff --git a/app/src/main/java/info/nightscout/androidaps/db/CompatDBHelper.kt b/app/src/main/java/info/nightscout/androidaps/db/CompatDBHelper.kt index 08f7cb01ad..aef3c28a3b 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/CompatDBHelper.kt +++ b/app/src/main/java/info/nightscout/androidaps/db/CompatDBHelper.kt @@ -1,9 +1,11 @@ package info.nightscout.androidaps.db import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.Food 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.events.EventFoodDatabaseChanged import info.nightscout.androidaps.events.EventNewBG import info.nightscout.androidaps.events.EventTempTargetChange import info.nightscout.androidaps.events.EventTherapyEventChange @@ -44,5 +46,9 @@ class CompatDBHelper @Inject constructor( aapsLogger.debug(LTag.DATABASE, "Firing EventTherapyEventChange") rxBus.send(EventTherapyEventChange()) } + it.filterIsInstance().firstOrNull()?.let { + aapsLogger.debug(LTag.DATABASE, "Firing EventFoodDatabaseChanged") + rxBus.send(EventFoodDatabaseChanged()) + } } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/DataClassesModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/DataClassesModule.kt index 98f15e668c..de4df287a4 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/DataClassesModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/DataClassesModule.kt @@ -3,7 +3,6 @@ package info.nightscout.androidaps.dependencyInjection import dagger.Module import dagger.android.ContributesAndroidInjector import info.nightscout.androidaps.db.DatabaseHelper -import info.nightscout.androidaps.plugins.general.food.FoodService import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.treatments.TreatmentService import info.nightscout.androidaps.utils.wizard.BolusWizard @@ -17,7 +16,6 @@ abstract class DataClassesModule { @ContributesAndroidInjector abstract fun DatabaseHelperInjector(): DatabaseHelper @ContributesAndroidInjector abstract fun treatmentServiceInjector(): TreatmentService - @ContributesAndroidInjector abstract fun foodServiceInjector(): FoodService @ContributesAndroidInjector abstract fun bolusWizardInjector(): BolusWizard @ContributesAndroidInjector abstract fun quickWizardEntryInjector(): QuickWizardEntry diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt index 5f48be718c..a82965d391 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt @@ -2,6 +2,7 @@ package info.nightscout.androidaps.dependencyInjection import dagger.Module import dagger.android.ContributesAndroidInjector +import info.nightscout.androidaps.plugins.general.food.FoodPlugin import info.nightscout.androidaps.plugins.general.nsclient.NSClientWorker import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin @@ -22,4 +23,5 @@ abstract class WorkersModule { @ContributesAndroidInjector abstract fun contributesNSProfileWorker(): NSProfilePlugin.NSProfileWorker @ContributesAndroidInjector abstract fun contributesSmsCommunicatorWorker(): SmsCommunicatorPlugin.SmsCommunicatorWorker @ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientWorker + @ContributesAndroidInjector abstract fun contributesFoodWorker(): FoodPlugin.FoodWorker } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventNsFood.kt b/app/src/main/java/info/nightscout/androidaps/events/EventNsFood.kt deleted file mode 100644 index 67bc23b168..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/events/EventNsFood.kt +++ /dev/null @@ -1,20 +0,0 @@ -package info.nightscout.androidaps.events - -import org.json.JSONArray - -/** - * Event which is published with data fetched from NightScout specific for the - * Food-class. - * - * Payload is the from NS retrieved JSON-String which should be handled by all - * subscriber. - */ - -class EventNsFood(val mode: Int, val foods: JSONArray) : Event() { - - companion object { - val ADD = 0 - val UPDATE = 1 - val REMOVE = 2 - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/Food.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/Food.java deleted file mode 100644 index 61c5f0b16f..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/Food.java +++ /dev/null @@ -1,145 +0,0 @@ -package info.nightscout.androidaps.plugins.general.food; - -import androidx.annotation.NonNull; - -import com.j256.ormlite.field.DatabaseField; -import com.j256.ormlite.table.DatabaseTable; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.Objects; - -import info.nightscout.androidaps.utils.JsonHelper; - -/** - * Created by mike on 20.09.2017. - */ - -@DatabaseTable(tableName = Food.TABLE_FOODS) -public class Food { - static final String TABLE_FOODS = "Foods"; - - @DatabaseField(id = true) - public long key; - - @DatabaseField - public boolean isValid = true; - - @DatabaseField - public String _id; // NS _id - - @DatabaseField - public String name; - - @DatabaseField - public String category; - - @DatabaseField - public String subcategory; - - // Example: - // name="juice" portion=250 units="ml" carbs=12 - // means 250ml of juice has 12g of carbs - - @DatabaseField - public double portion; // common portion in "units" - - @DatabaseField - public int carbs; // in grams - - @DatabaseField - public int fat = 0; // in grams - - @DatabaseField - public int protein = 0; // in grams - - @DatabaseField - public int energy = 0; // in kJ - - @DatabaseField - public String units = "g"; - - @DatabaseField - public int gi; // not used yet - - private Food() { - key = System.currentTimeMillis(); - } - - public static Food createFromJson(JSONObject json) throws JSONException { - Food food = new Food(); - if ("food".equals(JsonHelper.safeGetString(json, "type"))) { - food._id = JsonHelper.safeGetString(json, "_id"); - food.category = JsonHelper.safeGetString(json, "category"); - food.subcategory = JsonHelper.safeGetString(json, "subcategory"); - food.name = JsonHelper.safeGetString(json, "name"); - food.units = JsonHelper.safeGetString(json, "unit"); - food.portion = JsonHelper.safeGetDouble(json, "portion"); - food.carbs = JsonHelper.safeGetInt(json, "carbs"); - food.gi = JsonHelper.safeGetInt(json, "gi"); - food.energy = JsonHelper.safeGetInt(json, "energy"); - food.protein = JsonHelper.safeGetInt(json, "protein"); - food.fat = JsonHelper.safeGetInt(json, "fat"); - } - - return food; - } - - public boolean isEqual(Food other) { - if (portion != other.portion) - return false; - if (carbs != other.carbs) - return false; - if (fat != other.fat) - return false; - if (protein != other.protein) - return false; - if (energy != other.energy) - return false; - if (gi != other.gi) - return false; - if (!Objects.equals(_id, other._id)) - return false; - if (!Objects.equals(name, other.name)) - return false; - if (!Objects.equals(category, other.category)) - return false; - if (!Objects.equals(subcategory, other.subcategory)) - return false; - return Objects.equals(units, other.units); - } - - public void copyFrom(Food other) { - isValid = other.isValid; - _id = other._id; - name = other.name; - category = other.category; - subcategory = other.subcategory; - portion = other.portion; - carbs = other.carbs; - fat = other.fat; - protein = other.protein; - energy = other.energy; - units = other.units; - gi = other.gi; - } - - @Override @NonNull - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("_id=" + _id + ";"); - sb.append("isValid=" + isValid + ";"); - sb.append("name=" + name + ";"); - sb.append("category=" + category + ";"); - sb.append("subcategory=" + subcategory + ";"); - sb.append("portion=" + portion + ";"); - sb.append("carbs=" + carbs + ";"); - sb.append("protein=" + protein + ";"); - sb.append("energy=" + energy + ";"); - sb.append("units=" + units + ";"); - sb.append("gi=" + gi + ";"); - - return sb.toString(); - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodFragment.kt index f9ce2e17bb..10ff172727 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodFragment.kt @@ -1,7 +1,6 @@ package info.nightscout.androidaps.plugins.general.food import android.annotation.SuppressLint -import android.content.DialogInterface import android.graphics.Paint import android.os.Bundle import android.text.Editable @@ -15,20 +14,30 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R -import info.nightscout.androidaps.database.entities.UserEntry.* +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.Food +import info.nightscout.androidaps.database.entities.UserEntry.Action +import info.nightscout.androidaps.database.transactions.InvalidateFoodTransaction import info.nightscout.androidaps.databinding.FoodFragmentBinding import info.nightscout.androidaps.databinding.FoodItemBinding import info.nightscout.androidaps.events.EventFoodDatabaseChanged +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.food.FoodFragment.RecyclerViewAdapter.FoodsViewHolder import info.nightscout.androidaps.plugins.general.nsclient.NSUpload +import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.alertDialogs.OKDialog +import info.nightscout.androidaps.utils.extensions.toVisibility import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers +import io.reactivex.Completable import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign +import io.reactivex.rxkotlin.subscribeBy import java.util.* +import java.util.concurrent.TimeUnit import javax.inject.Inject import kotlin.collections.ArrayList @@ -36,10 +45,11 @@ class FoodFragment : DaggerFragment() { @Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var resourceHelper: ResourceHelper @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var foodPlugin: FoodPlugin @Inject lateinit var nsUpload: NSUpload + @Inject lateinit var repository: AppRepository @Inject lateinit var uel: UserEntryLogger private val disposable = CompositeDisposable() @@ -62,8 +72,23 @@ class FoodFragment : DaggerFragment() { binding.recyclerview.setHasFixedSize(true) binding.recyclerview.layoutManager = LinearLayoutManager(view.context) - binding.recyclerview.adapter = RecyclerViewAdapter(foodPlugin.service?.foodData - ?: ArrayList()) + + binding.refreshFromNightscout.setOnClickListener { + context?.let { context -> + OKDialog.showConfirmation(context, resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", { + uel.log(Action.FOOD_FROM_NS) + disposable += Completable.fromAction { repository.deleteAllFoods() } + .subscribeOn(aapsSchedulers.io) + .observeOn(aapsSchedulers.main) + .subscribeBy( + onError = { aapsLogger.error("Error removing foods", it) }, + onComplete = { rxBus.send(EventFoodDatabaseChanged()) } + ) + + rxBus.send(EventNSClientRestart()) + }) + } + } binding.clearfilter.setOnClickListener { binding.filter.setText("") @@ -99,10 +124,6 @@ class FoodFragment : DaggerFragment() { override fun afterTextChanged(s: Editable) {} }) - loadData() - fillCategories() - fillSubcategories() - filterData() } @Synchronized @@ -111,9 +132,23 @@ class FoodFragment : DaggerFragment() { disposable.add(rxBus .toObservable(EventFoodDatabaseChanged::class.java) .observeOn(aapsSchedulers.main) - .subscribe({ updateGui() }, fabricPrivacy::logException) + .debounce(1L, TimeUnit.SECONDS) + .subscribe({ swapAdapter() }, fabricPrivacy::logException) ) - updateGui() + swapAdapter() + } + + private fun swapAdapter() { + disposable += repository + .getFoodData() + .observeOn(aapsSchedulers.main) + .subscribe { list -> + unfiltered = list + fillCategories() + fillSubcategories() + filterData() + binding.recyclerview.swapAdapter(RecyclerViewAdapter(filtered), true) + } } @Synchronized @@ -128,14 +163,11 @@ class FoodFragment : DaggerFragment() { _binding = null } - private fun loadData() { - unfiltered = foodPlugin.service?.foodData ?: ArrayList() - } - private fun fillCategories() { val catSet: MutableSet = HashSet() for (f in unfiltered) { - if (f.category != null && f.category != "") catSet.add(f.category) + val category = f.category + if (!category.isNullOrBlank()) catSet.add(category) } // make it unique val categories = ArrayList(catSet) @@ -151,7 +183,10 @@ class FoodFragment : DaggerFragment() { val subCatSet: MutableSet = HashSet() if (categoryFilter != resourceHelper.gs(R.string.none)) { for (f in unfiltered) { - if (f.category != null && f.category == categoryFilter) if (f.subcategory != null && f.subcategory != "") subCatSet.add(f.subcategory) + if (f.category != null && f.category == categoryFilter) { + val subCategory = f.subCategory + if (!subCategory.isNullOrEmpty()) subCatSet.add(subCategory) + } } } // make it unique @@ -169,21 +204,19 @@ class FoodFragment : DaggerFragment() { val subcategoryFilter = binding.subcategory.selectedItem.toString() val newFiltered = ArrayList() for (f in unfiltered) { - if (f.name == null || f.category == null || f.subcategory == null) continue - if (subcategoryFilter != resourceHelper.gs(R.string.none) && f.subcategory != subcategoryFilter) continue + if (f.category == null || f.subCategory == null) continue + if (subcategoryFilter != resourceHelper.gs(R.string.none) && f.subCategory != subcategoryFilter) continue if (categoryFilter != resourceHelper.gs(R.string.none) && f.category != categoryFilter) continue if (textFilter != "" && !f.name.toLowerCase(Locale.getDefault()).contains(textFilter.toLowerCase(Locale.getDefault()))) continue newFiltered.add(f) } filtered = newFiltered - updateGui() - } - - private fun updateGui() { binding.recyclerview.swapAdapter(RecyclerViewAdapter(filtered), true) } - inner class RecyclerViewAdapter internal constructor(var foodList: List) : RecyclerView.Adapter() { + fun Int?.isNotZero(): Boolean = this != null && this != 0 + + inner class RecyclerViewAdapter internal constructor(private var foodList: List) : RecyclerView.Adapter() { override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): FoodsViewHolder { val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.food_item, viewGroup, false) @@ -193,16 +226,16 @@ class FoodFragment : DaggerFragment() { @SuppressLint("SetTextI18n") override fun onBindViewHolder(holder: FoodsViewHolder, position: Int) { val food = foodList[position] - holder.binding.nsSign.visibility = if (food._id != null) View.VISIBLE else View.GONE + holder.binding.nsSign.visibility = (food.interfaceIDs.nightscoutId != null).toVisibility() holder.binding.name.text = food.name - holder.binding.portion.text = food.portion.toString() + food.units + holder.binding.portion.text = food.portion.toString() + food.unit holder.binding.carbs.text = food.carbs.toString() + resourceHelper.gs(R.string.shortgramm) holder.binding.fat.text = resourceHelper.gs(R.string.shortfat) + ": " + food.fat + resourceHelper.gs(R.string.shortgramm) - if (food.fat == 0) holder.binding.fat.visibility = View.INVISIBLE + holder.binding.fat.visibility = food.fat.isNotZero().toVisibility() holder.binding.protein.text = resourceHelper.gs(R.string.shortprotein) + ": " + food.protein + resourceHelper.gs(R.string.shortgramm) - if (food.protein == 0) holder.binding.protein.visibility = View.INVISIBLE + holder.binding.protein.visibility = food.protein.isNotZero().toVisibility() holder.binding.energy.text = resourceHelper.gs(R.string.shortenergy) + ": " + food.energy + resourceHelper.gs(R.string.shortkilojoul) - if (food.energy == 0) holder.binding.energy.visibility = View.INVISIBLE + holder.binding.energy.visibility = food.energy.isNotZero().toVisibility() holder.binding.remove.tag = food } @@ -216,12 +249,17 @@ class FoodFragment : DaggerFragment() { binding.remove.setOnClickListener { v: View -> val food = v.tag as Food activity?.let { activity -> - OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.confirmation), resourceHelper.gs(R.string.removerecord) + "\n" + food.name, DialogInterface.OnClickListener { _: DialogInterface?, _: Int -> + OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + "\n" + food.name, { uel.log(Action.FOOD_REMOVED, food.name) - if (food._id != null && food._id != "") { - nsUpload.removeFoodFromNS(food._id) - } - foodPlugin.service?.delete(food) + disposable += repository.runTransactionForResult(InvalidateFoodTransaction(food.id)) + .subscribe({ + val id = food.interfaceIDs.nightscoutId + if (NSUpload.isIdValid(id)) nsUpload.removeFoodFromNS(id) + // no create at the moment + // else uploadQueue.removeID("dbAdd", food.timestamp.toString()) + }, { + aapsLogger.error(LTag.BGSOURCE, "Error while invalidating food", it) + }) }, null) } } @@ -229,4 +267,4 @@ class FoodFragment : DaggerFragment() { } } } -} +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt index d44550a11d..6b5125eb0a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt @@ -1,12 +1,28 @@ package info.nightscout.androidaps.plugins.general.food +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.Food +import info.nightscout.androidaps.database.transactions.SyncFoodTransaction 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.receivers.BundleStore +import info.nightscout.androidaps.receivers.DataReceiver +import info.nightscout.androidaps.utils.JsonHelper +import info.nightscout.androidaps.utils.extensions.foodFromJson import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.sharedPreferences.SP +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign +import org.json.JSONArray +import org.json.JSONObject import javax.inject.Inject import javax.inject.Singleton @@ -25,10 +41,75 @@ class FoodPlugin @Inject constructor( aapsLogger, resourceHelper, injector ) { - var service: FoodService? = null + private val disposable = CompositeDisposable() - override fun onStart() { - super.onStart() - service = FoodService(injector) + // cannot be inner class because of needed injection + class FoodWorker( + context: Context, + params: WorkerParameters + ) : Worker(context, params) { + + @Inject lateinit var injector: HasAndroidInjector + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var repository: AppRepository + @Inject lateinit var sp: SP + @Inject lateinit var bundleStore: BundleStore + @Inject lateinit var foodPlugin: FoodPlugin + + init { + (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) + } + + override fun doWork(): Result { + aapsLogger.debug(LTag.DATAFOOD, "Received Food Data: $inputData}") + val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1)) + ?: return Result.failure() + + var ret = Result.success() + + val foodsString = bundle.getString("foods") ?: return Result.failure() + val foods = JSONArray(foodsString) + for (index in 0 until foods.length()) { + val jsonFood: JSONObject = foods.getJSONObject(index) + + if (JsonHelper.safeGetString(jsonFood, "type") != "food") continue + + when (JsonHelper.safeGetString(jsonFood, "action")) { + "remove" -> { + val delFood = Food( + name = "", + portion = 0.0, + carbs = 0, + isValid = false + ).also { it.interfaceIDs.nightscoutId = JsonHelper.safeGetString(jsonFood, "_id") } + + foodPlugin.disposable += repository.runTransactionForResult(SyncFoodTransaction(delFood)).subscribe({ result -> + result.invalidated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Invalidated food ${it.interfaceIDs.nightscoutId}") } + }, { + aapsLogger.error(LTag.DATAFOOD, "Error while removing food", it) + ret = Result.failure() + }) + } + + else -> { + val food = foodFromJson(jsonFood) + if (food != null) { + foodPlugin.disposable += repository.runTransactionForResult(SyncFoodTransaction(food)).subscribe({ result -> + result.inserted.forEach { aapsLogger.debug(LTag.DATAFOOD, "Inserted food $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Updated food $it") } + result.invalidated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Invalidated food $it") } + }, { + aapsLogger.error(LTag.DATAFOOD, "Error while adding/updating food", it) + ret = Result.failure() + }) + } else { + aapsLogger.error(LTag.DATAFOOD, "Error parsing food", jsonFood.toString()) + ret = Result.failure() + } + } + } + } + return ret + } } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodService.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodService.java deleted file mode 100644 index ceb72727a1..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodService.java +++ /dev/null @@ -1,359 +0,0 @@ -package info.nightscout.androidaps.plugins.general.food; - -import android.content.Intent; -import android.os.IBinder; - -import androidx.annotation.Nullable; - -import com.j256.ormlite.android.apptools.OpenHelperManager; -import com.j256.ormlite.android.apptools.OrmLiteBaseService; -import com.j256.ormlite.dao.Dao; -import com.j256.ormlite.dao.DaoManager; -import com.j256.ormlite.support.ConnectionSource; -import com.j256.ormlite.table.TableUtils; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import javax.inject.Inject; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.db.DatabaseHelper; -import info.nightscout.androidaps.db.ICallback; -import info.nightscout.androidaps.events.Event; -import info.nightscout.androidaps.events.EventFoodDatabaseChanged; -import info.nightscout.androidaps.events.EventNsFood; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.utils.rx.AapsSchedulers; -import io.reactivex.disposables.CompositeDisposable; - -/** - * Created by mike on 24.09.2017. - */ - -public class FoodService extends OrmLiteBaseService { - @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/ImportExportPrefs.kt index 8e9456ffda..9acdf53e8a 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/ImportExportPrefs.kt @@ -108,6 +108,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") @@ -346,7 +347,7 @@ 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 { + OKDialog.show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp)) { uel.log(Action.IMPORT_SETTINGS) log.debug(LTag.CORE, "Exiting") rxBus.send(EventAppExit()) @@ -355,14 +356,13 @@ class ImportExportPrefs @Inject constructor( } System.runFinalization() exitProcess(0) - }) + } } - override fun exportUserEntriesCsv(activity: FragmentActivity, listEntries: Single>) { - val entries = listEntries.blockingGet() + override fun exportUserEntriesCsv(activity: FragmentActivity, singleEntries: Single>) { + val entries = singleEntries.blockingGet() prefFileList.ensureExportDirExists() val newFile = prefFileList.newExportXmlFile() - //log.debug("XXXXX " + classicPrefsFormat.UserEntriesToCsv(entries)) try { classicPrefsFormat.saveCsv(newFile, entries) 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 882cfc389f..32b3001911 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 @@ -16,7 +16,6 @@ import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface 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.utils.alertDialogs.OKDialog @@ -34,7 +33,6 @@ class MaintenanceFragment : DaggerFragment() { @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 aapsSchedulers: AapsSchedulers @Inject lateinit var repository: AppRepository @@ -70,7 +68,6 @@ class MaintenanceFragment : DaggerFragment() { databaseHelper.resetDatabases() // should be handled by Plugin-Interface and // additional service interface and plugin registry - foodPlugin.service?.resetFood() treatmentsPlugin.service.resetTreatments() repository.clearDatabases() } 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 24006267f0..b4be8d61c7 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 @@ -34,7 +34,6 @@ import info.nightscout.androidaps.R; 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.DatabaseHelperInterface; import info.nightscout.androidaps.interfaces.PluginType; @@ -636,39 +635,8 @@ public class NSClientService extends DaggerService { } 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); - } + if (foods.length() > 0) rxBus.send(new EventNSClientNewLog("DATA", "received " + foods.length() + " foods")); + handleFood(foods, isDelta); } if (data.has("mbgs")) { JSONArray mbgs = data.getJSONArray("mbgs"); @@ -881,6 +849,16 @@ public class NSClientService extends DaggerService { } } + public void handleFood(JSONArray foods, boolean isDelta) { + Bundle bundle = new Bundle(); + bundle.putString("foods", foods.toString()); + bundle.putBoolean("delta", isDelta); + Intent intent = new Intent(Intents.ACTION_FOOD); + intent.putExtras(bundle); + intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + LocalBroadcastManager.getInstance(this).sendBroadcast(intent); + } + public void handleNewCal(JSONArray cals, boolean isDelta) { Bundle bundle = new Bundle(); bundle.putString("cals", cals.toString()); diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt index 3d4d04dbf7..862d470dfd 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt +++ b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt @@ -12,6 +12,7 @@ import dagger.android.DaggerBroadcastReceiver import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.BundleLogger import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.general.food.FoodPlugin import info.nightscout.androidaps.plugins.general.nsclient.NSClientWorker import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin @@ -21,7 +22,6 @@ import info.nightscout.androidaps.utils.extensions.copyDouble import info.nightscout.androidaps.utils.extensions.copyInt import info.nightscout.androidaps.utils.extensions.copyLong import info.nightscout.androidaps.utils.extensions.copyString -import org.json.JSONObject import javax.inject.Inject open class DataReceiver : DaggerBroadcastReceiver() { @@ -38,37 +38,37 @@ open class DataReceiver : DaggerBroadcastReceiver() { when (intent.action) { - Intents.ACTION_NEW_BG_ESTIMATE -> + Intents.ACTION_NEW_BG_ESTIMATE -> OneTimeWorkRequest.Builder(XdripPlugin.XdripWorker::class.java) .setInputData(bundleInputData(bundle, intent)).build() - Intents.POCTECH_BG -> + Intents.POCTECH_BG -> OneTimeWorkRequest.Builder(PoctechPlugin.PoctechWorker::class.java) .setInputData(Data.Builder().also { it.copyString("data", bundle) }.build()).build() - Intents.GLIMP_BG -> + Intents.GLIMP_BG -> OneTimeWorkRequest.Builder(GlimpPlugin.GlimpWorker::class.java) .setInputData(Data.Builder().also { it.copyDouble("mySGV", bundle) it.copyString("myTrend", bundle) it.copyLong("myTimestamp", bundle) }.build()).build() - Intents.TOMATO_BG -> + Intents.TOMATO_BG -> OneTimeWorkRequest.Builder(TomatoPlugin.TomatoWorker::class.java) .setInputData(Data.Builder().also { it.copyDouble("com.fanqies.tomatofn.Extras.BgEstimate", bundle) it.copyLong("com.fanqies.tomatofn.Extras.Time", bundle) }.build()).build() - Intents.ACTION_NEW_PROFILE -> + Intents.ACTION_NEW_PROFILE -> OneTimeWorkRequest.Builder(NSProfilePlugin.NSProfileWorker::class.java) .setInputData(bundleInputData(bundle, intent)).build() - Intents.ACTION_NEW_SGV -> + Intents.ACTION_NEW_SGV -> OneTimeWorkRequest.Builder(NSClientSourcePlugin.NSClientSourceWorker::class.java) .setInputData(Data.Builder().also { it.copyString("sgv", bundle, null) it.copyString("sgvs", bundle, null) }.build()).build() - Intents.NS_EMULATOR -> + Intents.NS_EMULATOR -> OneTimeWorkRequest.Builder(MM640gPlugin.MM640gWorker::class.java) .setInputData(Data.Builder().also { it.copyDouble(Intents.EXTRA_BG_ESTIMATE, bundle) @@ -81,23 +81,26 @@ open class DataReceiver : DaggerBroadcastReceiver() { Telephony.Sms.Intents.SMS_RECEIVED_ACTION -> OneTimeWorkRequest.Builder(SmsCommunicatorPlugin.SmsCommunicatorWorker::class.java) .setInputData(bundleInputData(bundle, intent)).build() - Intents.EVERSENSE_BG -> + Intents.EVERSENSE_BG -> OneTimeWorkRequest.Builder(EversensePlugin.EversenseWorker::class.java) .setInputData(bundleInputData(bundle, intent)).build() - Intents.DEXCOM_BG -> + Intents.DEXCOM_BG -> OneTimeWorkRequest.Builder(DexcomPlugin.DexcomWorker::class.java) .setInputData(bundleInputData(bundle, intent)).build() + Intents.ACTION_FOOD -> + OneTimeWorkRequest.Builder(FoodPlugin.FoodWorker::class.java) + .setInputData(bundleInputData(bundle, intent)).build() Intents.ACTION_NEW_TREATMENT, Intents.ACTION_CHANGED_TREATMENT, Intents.ACTION_REMOVED_TREATMENT, Intents.ACTION_NEW_CAL, - Intents.ACTION_NEW_MBG -> + Intents.ACTION_NEW_MBG -> OneTimeWorkRequest.Builder(NSClientWorker::class.java) .setInputData(bundleInputData(bundle, intent)).build() else -> null }?.let { request -> WorkManager.getInstance(context) - .enqueueUniqueWork(jobGroupName, ExistingWorkPolicy.APPEND_OR_REPLACE , request) + .enqueueUniqueWork(jobGroupName, ExistingWorkPolicy.APPEND_OR_REPLACE, request) } } @@ -105,6 +108,7 @@ open class DataReceiver : DaggerBroadcastReceiver() { Data.Builder().putLong(STORE_KEY, bundleStore.store(bundle)).putString(ACTION_KEY, intent.action).build() companion object { + const val STORE_KEY = "storeKey" const val ACTION_KEY = "action" } diff --git a/app/src/main/java/info/nightscout/androidaps/services/Intents.kt b/app/src/main/java/info/nightscout/androidaps/services/Intents.kt index 5e38fdb15b..7255548a03 100644 --- a/app/src/main/java/info/nightscout/androidaps/services/Intents.kt +++ b/app/src/main/java/info/nightscout/androidaps/services/Intents.kt @@ -13,6 +13,7 @@ interface Intents { const val ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV" const val ACTION_NEW_MBG = "info.nightscout.client.NEW_MBG" const val ACTION_NEW_CAL = "info.nightscout.client.NEW_CAL" + const val ACTION_FOOD = "info.nightscout.client.FOOD" // xDrip -> App const val ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate" diff --git a/app/src/main/res/layout/food_fragment.xml b/app/src/main/res/layout/food_fragment.xml index f192bdf62e..c96ed1f3cd 100644 --- a/app/src/main/res/layout/food_fragment.xml +++ b/app/src/main/res/layout/food_fragment.xml @@ -4,7 +4,17 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - tools:context="info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsExtendedBolusesFragment"> + tools:context="info.nightscout.androidaps.plugins.general.food.TreatmentsFoodFragment"> + + + card_view:cardBackgroundColor="?android:colorBackground"> + android:textStyle="bold" + tools:ignore="HardcodedText" /> + android:text="Portion" + tools:ignore="HardcodedText" /> + android:text="Carbs" + tools:ignore="HardcodedText" /> @@ -56,21 +57,24 @@ android:layout_width="70dp" android:layout_height="wrap_content" android:gravity="end" - android:text="Fat" /> + android:text="Fat" + tools:ignore="HardcodedText" /> + android:text="Protein" + tools:ignore="HardcodedText" /> + android:text="Energy" + tools:ignore="HardcodedText" /> + android:textColor="@color/colorSetTempButton" + tools:ignore="HardcodedText" /> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dd550020b4..52a1be72c3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -317,7 +317,7 @@ Autosens data Script debug Use Autosens feature - Refresh events from NS + Refresh from NS Delete treatments in the future ACT CONF diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/ImportExportPrefsInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/ImportExportPrefsInterface.kt index b20afdd1df..e003e02fcf 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/ImportExportPrefsInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/ImportExportPrefsInterface.kt @@ -14,5 +14,5 @@ interface ImportExportPrefsInterface { fun prefsFileExists(): Boolean fun verifyStoragePermissions(fragment: Fragment, onGranted: Runnable) fun exportSharedPreferences(f: Fragment) - fun exportUserEntriesCsv(activity: FragmentActivity, entries: Single>) + fun exportUserEntriesCsv(activity: FragmentActivity, singleEntries: Single>) } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/utils/JsonHelper.kt b/core/src/main/java/info/nightscout/androidaps/utils/JsonHelper.kt index 65748dca7e..f3105b755e 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/JsonHelper.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/JsonHelper.kt @@ -5,7 +5,6 @@ import org.json.JSONObject object JsonHelper { - @JvmStatic fun safeGetObject(json: JSONObject?, fieldName: String, defaultValue: Any): Any { var result = defaultValue if (json != null && json.has(fieldName)) { @@ -17,7 +16,6 @@ object JsonHelper { return result } - @JvmStatic fun safeGetJSONObject(json: JSONObject?, fieldName: String, defaultValue: JSONObject?): JSONObject? { var result = defaultValue if (json != null && json.has(fieldName)) { @@ -53,7 +51,6 @@ object JsonHelper { return result } - @JvmStatic fun safeGetStringAllowNull(json: JSONObject?, fieldName: String, defaultValue: String?): String? { var result = defaultValue if (json != null && json.has(fieldName)) { @@ -77,7 +74,6 @@ object JsonHelper { return result } - @JvmStatic fun safeGetDoubleAllowNull(json: JSONObject?, fieldName: String): Double? { var result: Double? = null if (json != null && json.has(fieldName)) { @@ -89,7 +85,6 @@ object JsonHelper { return result } - @JvmStatic fun safeGetDouble(json: JSONObject?, fieldName: String, defaultValue: Double): Double { var result = defaultValue if (json != null && json.has(fieldName)) { @@ -105,7 +100,6 @@ object JsonHelper { fun safeGetInt(json: JSONObject?, fieldName: String): Int = safeGetInt(json, fieldName, 0) - @JvmStatic fun safeGetInt(json: JSONObject?, fieldName: String, defaultValue: Int): Int { var result = defaultValue if (json != null && json.has(fieldName)) { @@ -117,6 +111,17 @@ object JsonHelper { return result } + fun safeGetIntAllowNull(json: JSONObject?, fieldName: String): Int? { + var result : Int? = null + if (json != null && json.has(fieldName)) { + try { + result = json.getInt(fieldName) + } catch (ignored: JSONException) { + } + } + return result + } + @JvmStatic fun safeGetLong(json: JSONObject?, fieldName: String): Long { var result: Long = 0 diff --git a/core/src/main/java/info/nightscout/androidaps/utils/extensions/FoodExtension.kt b/core/src/main/java/info/nightscout/androidaps/utils/extensions/FoodExtension.kt new file mode 100644 index 0000000000..e2624775a7 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/utils/extensions/FoodExtension.kt @@ -0,0 +1,40 @@ +package info.nightscout.androidaps.utils.extensions + +import info.nightscout.androidaps.database.entities.Food +import info.nightscout.androidaps.plugins.general.nsclient.NSUpload +import info.nightscout.androidaps.utils.JsonHelper +import org.json.JSONObject + +fun foodFromJson(jsonObject: JSONObject): Food? { + if ("food" == JsonHelper.safeGetString(jsonObject, "type")) { + val name = JsonHelper.safeGetStringAllowNull(jsonObject, "name", null) ?: return null + val category = JsonHelper.safeGetStringAllowNull(jsonObject, "category", null) + val subCategory = JsonHelper.safeGetStringAllowNull(jsonObject, "subcategory", null) + val unit = JsonHelper.safeGetString(jsonObject, "unit", "") + val portion = JsonHelper.safeGetDoubleAllowNull(jsonObject, "portion") ?: return null + val carbs = JsonHelper.safeGetIntAllowNull(jsonObject, "carbs") ?: return null + val gi = JsonHelper.safeGetIntAllowNull(jsonObject, "gi") + val energy = JsonHelper.safeGetIntAllowNull(jsonObject, "energy") + val protein = JsonHelper.safeGetIntAllowNull(jsonObject, "protein") + val fat = JsonHelper.safeGetIntAllowNull(jsonObject, "fat") + val id = JsonHelper.safeGetStringAllowNull(jsonObject, "_id", null) ?: return null + val isValid = JsonHelper.safeGetBoolean(jsonObject, NSUpload.ISVALID, true) + + val food = Food( + name = name, + category = category, + subCategory = subCategory, + unit = unit, + portion = portion, + carbs = carbs, + gi = gi, + energy = energy, + protein = protein, + fat = fat, + isValid = isValid + ) + food.interfaceIDs.nightscoutId = id + return food + } + return null +} diff --git a/database/schemas/info.nightscout.androidaps.database.AppDatabase/7.json b/database/schemas/info.nightscout.androidaps.database.AppDatabase/7.json new file mode 100644 index 0000000000..cb6fc6e0bb --- /dev/null +++ b/database/schemas/info.nightscout.androidaps.database.AppDatabase/7.json @@ -0,0 +1,2924 @@ +{ + "formatVersion": 1, + "database": { + "version": 7, + "identityHash": "7a8795e82743748b627944dc589e8626", + "entities": [ + { + "tableName": "apsResults", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `algorithm` TEXT NOT NULL, `glucoseStatusJson` TEXT NOT NULL, `currentTempJson` TEXT NOT NULL, `iobDataJson` TEXT NOT NULL, `profileJson` TEXT NOT NULL, `autosensDataJson` TEXT, `mealDataJson` TEXT NOT NULL, `isMicroBolusAllowed` INTEGER, `resultJson` TEXT NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `apsResults`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "algorithm", + "columnName": "algorithm", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "glucoseStatusJson", + "columnName": "glucoseStatusJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currentTempJson", + "columnName": "currentTempJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "iobDataJson", + "columnName": "iobDataJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "profileJson", + "columnName": "profileJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "autosensDataJson", + "columnName": "autosensDataJson", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mealDataJson", + "columnName": "mealDataJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isMicroBolusAllowed", + "columnName": "isMicroBolusAllowed", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "resultJson", + "columnName": "resultJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_apsResults_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_apsResults_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_apsResults_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_apsResults_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "apsResults", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "boluses", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `amount` REAL NOT NULL, `type` TEXT NOT NULL, `isBasalInsulin` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, `insulinLabel` TEXT, `insulinEndTime` INTEGER, `peak` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `boluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isBasalInsulin", + "columnName": "isBasalInsulin", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "insulinConfiguration.insulinLabel", + "columnName": "insulinLabel", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "insulinConfiguration.insulinEndTime", + "columnName": "insulinEndTime", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "insulinConfiguration.peak", + "columnName": "peak", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_boluses_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_boluses_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_boluses_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_boluses_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "boluses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "bolusCalculatorResults", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `targetBGLow` REAL NOT NULL, `targetBGHigh` REAL NOT NULL, `isf` REAL NOT NULL, `ic` REAL NOT NULL, `bolusIOB` REAL NOT NULL, `wasBolusIOBUsed` INTEGER NOT NULL, `basalIOB` REAL NOT NULL, `wasBasalIOBUsed` INTEGER NOT NULL, `glucoseValue` REAL NOT NULL, `wasGlucoseUsed` INTEGER NOT NULL, `glucoseDifference` REAL NOT NULL, `glucoseInsulin` REAL NOT NULL, `glucoseTrend` REAL NOT NULL, `wasTrendUsed` INTEGER NOT NULL, `trendInsulin` REAL NOT NULL, `cob` REAL NOT NULL, `wasCOBUsed` INTEGER NOT NULL, `cobInsulin` REAL NOT NULL, `carbs` REAL NOT NULL, `wereCarbsUsed` INTEGER NOT NULL, `carbsInsulin` REAL NOT NULL, `otherCorrection` REAL NOT NULL, `wasSuperbolusUsed` INTEGER NOT NULL, `superbolusInsulin` REAL NOT NULL, `wasTempTargetUsed` INTEGER NOT NULL, `totalInsulin` REAL NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `bolusCalculatorResults`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "targetBGLow", + "columnName": "targetBGLow", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "targetBGHigh", + "columnName": "targetBGHigh", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "isf", + "columnName": "isf", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "ic", + "columnName": "ic", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "bolusIOB", + "columnName": "bolusIOB", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasBolusIOBUsed", + "columnName": "wasBolusIOBUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "basalIOB", + "columnName": "basalIOB", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasBasalIOBUsed", + "columnName": "wasBasalIOBUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "glucoseValue", + "columnName": "glucoseValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasGlucoseUsed", + "columnName": "wasGlucoseUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "glucoseDifference", + "columnName": "glucoseDifference", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "glucoseInsulin", + "columnName": "glucoseInsulin", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "glucoseTrend", + "columnName": "glucoseTrend", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasTrendUsed", + "columnName": "wasTrendUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "trendInsulin", + "columnName": "trendInsulin", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "cob", + "columnName": "cob", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasCOBUsed", + "columnName": "wasCOBUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "cobInsulin", + "columnName": "cobInsulin", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "carbs", + "columnName": "carbs", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wereCarbsUsed", + "columnName": "wereCarbsUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "carbsInsulin", + "columnName": "carbsInsulin", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "otherCorrection", + "columnName": "otherCorrection", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasSuperbolusUsed", + "columnName": "wasSuperbolusUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "superbolusInsulin", + "columnName": "superbolusInsulin", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "wasTempTargetUsed", + "columnName": "wasTempTargetUsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "totalInsulin", + "columnName": "totalInsulin", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_bolusCalculatorResults_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_bolusCalculatorResults_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_bolusCalculatorResults_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_bolusCalculatorResults_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "bolusCalculatorResults", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "carbs", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `amount` REAL NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `carbs`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_carbs_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_carbs_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_carbs_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_carbs_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "carbs", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "effectiveProfileSwitches", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `basalBlocks` TEXT NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `effectiveProfileSwitches`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "basalBlocks", + "columnName": "basalBlocks", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_effectiveProfileSwitches_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_effectiveProfileSwitches_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_effectiveProfileSwitches_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_effectiveProfileSwitches_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "effectiveProfileSwitches", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "extendedBoluses", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `amount` REAL NOT NULL, `isEmulatingTempBasal` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `extendedBoluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "isEmulatingTempBasal", + "columnName": "isEmulatingTempBasal", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_extendedBoluses_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_extendedBoluses_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_extendedBoluses_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_extendedBoluses_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "extendedBoluses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "glucoseValues", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `raw` REAL, `value` REAL NOT NULL, `trendArrow` TEXT NOT NULL, `noise` REAL, `sourceSensor` TEXT NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `glucoseValues`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "raw", + "columnName": "raw", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "trendArrow", + "columnName": "trendArrow", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "noise", + "columnName": "noise", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "sourceSensor", + "columnName": "sourceSensor", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_glucoseValues_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_glucoseValues_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_glucoseValues_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_glucoseValues_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "glucoseValues", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "profileSwitches", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `profileName` TEXT NOT NULL, `glucoseUnit` TEXT NOT NULL, `basalBlocks` TEXT NOT NULL, `isfBlocks` TEXT NOT NULL, `icBlocks` TEXT NOT NULL, `targetBlocks` TEXT NOT NULL, `timeshift` INTEGER NOT NULL, `percentage` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, `insulinLabel` TEXT NOT NULL, `insulinEndTime` INTEGER NOT NULL, `peak` INTEGER NOT NULL, FOREIGN KEY(`referenceId`) REFERENCES `profileSwitches`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "profileName", + "columnName": "profileName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "glucoseUnit", + "columnName": "glucoseUnit", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "basalBlocks", + "columnName": "basalBlocks", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isfBlocks", + "columnName": "isfBlocks", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "icBlocks", + "columnName": "icBlocks", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "targetBlocks", + "columnName": "targetBlocks", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timeshift", + "columnName": "timeshift", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "percentage", + "columnName": "percentage", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "insulinConfiguration.insulinLabel", + "columnName": "insulinLabel", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "insulinConfiguration.insulinEndTime", + "columnName": "insulinEndTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "insulinConfiguration.peak", + "columnName": "peak", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_profileSwitches_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_profileSwitches_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_profileSwitches_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_profileSwitches_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "profileSwitches", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "temporaryBasals", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `type` TEXT NOT NULL, `isAbsolute` INTEGER NOT NULL, `rate` REAL NOT NULL, `duration` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `temporaryBasals`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isAbsolute", + "columnName": "isAbsolute", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_temporaryBasals_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_temporaryBasals_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_temporaryBasals_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_temporaryBasals_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "temporaryBasals", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "temporaryTargets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `reason` TEXT NOT NULL, `highTarget` REAL NOT NULL, `lowTarget` REAL NOT NULL, `duration` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `temporaryTargets`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "reason", + "columnName": "reason", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "highTarget", + "columnName": "highTarget", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "lowTarget", + "columnName": "lowTarget", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_temporaryTargets_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_temporaryTargets_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_temporaryTargets_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_temporaryTargets_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "temporaryTargets", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "therapyEvents", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `type` TEXT NOT NULL, `note` TEXT, `enteredBy` TEXT, `glucose` REAL, `glucoseType` TEXT, `glucoseUnit` TEXT NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `therapyEvents`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "enteredBy", + "columnName": "enteredBy", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "glucose", + "columnName": "glucose", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "glucoseType", + "columnName": "glucoseType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "glucoseUnit", + "columnName": "glucoseUnit", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_therapyEvents_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_therapyEvents_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_therapyEvents_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_therapyEvents_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "therapyEvents", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "totalDailyDoses", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `basalAmount` REAL, `bolusAmount` REAL, `totalAmount` REAL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `totalDailyDoses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "basalAmount", + "columnName": "basalAmount", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "bolusAmount", + "columnName": "bolusAmount", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "totalAmount", + "columnName": "totalAmount", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_totalDailyDoses_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_totalDailyDoses_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_totalDailyDoses_timestamp", + "unique": false, + "columnNames": [ + "timestamp" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_totalDailyDoses_timestamp` ON `${TABLE_NAME}` (`timestamp`)" + } + ], + "foreignKeys": [ + { + "table": "totalDailyDoses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "apsResultLinks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `apsResultId` INTEGER NOT NULL, `smbId` INTEGER, `tbrId` INTEGER, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`apsResultId`) REFERENCES `apsResults`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`smbId`) REFERENCES `boluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`tbrId`) REFERENCES `temporaryBasals`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`referenceId`) REFERENCES `apsResultLinks`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "apsResultId", + "columnName": "apsResultId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "smbId", + "columnName": "smbId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "tbrId", + "columnName": "tbrId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_apsResultLinks_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_apsResultLinks_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_apsResultLinks_apsResultId", + "unique": false, + "columnNames": [ + "apsResultId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_apsResultLinks_apsResultId` ON `${TABLE_NAME}` (`apsResultId`)" + }, + { + "name": "index_apsResultLinks_smbId", + "unique": false, + "columnNames": [ + "smbId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_apsResultLinks_smbId` ON `${TABLE_NAME}` (`smbId`)" + }, + { + "name": "index_apsResultLinks_tbrId", + "unique": false, + "columnNames": [ + "tbrId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_apsResultLinks_tbrId` ON `${TABLE_NAME}` (`tbrId`)" + } + ], + "foreignKeys": [ + { + "table": "apsResults", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "apsResultId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "boluses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "smbId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "temporaryBasals", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "tbrId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "apsResultLinks", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "mealLinks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `bolusId` INTEGER, `carbsId` INTEGER, `bolusCalcResultId` INTEGER, `superbolusTempBasalId` INTEGER, `noteId` INTEGER, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`bolusId`) REFERENCES `boluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`carbsId`) REFERENCES `carbs`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`bolusCalcResultId`) REFERENCES `bolusCalculatorResults`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`superbolusTempBasalId`) REFERENCES `temporaryBasals`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`noteId`) REFERENCES `therapyEvents`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`referenceId`) REFERENCES `mealLinks`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bolusId", + "columnName": "bolusId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "carbsId", + "columnName": "carbsId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bolusCalcResultId", + "columnName": "bolusCalcResultId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "superbolusTempBasalId", + "columnName": "superbolusTempBasalId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "noteId", + "columnName": "noteId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_mealLinks_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_mealLinks_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_mealLinks_bolusId", + "unique": false, + "columnNames": [ + "bolusId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_mealLinks_bolusId` ON `${TABLE_NAME}` (`bolusId`)" + }, + { + "name": "index_mealLinks_carbsId", + "unique": false, + "columnNames": [ + "carbsId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_mealLinks_carbsId` ON `${TABLE_NAME}` (`carbsId`)" + }, + { + "name": "index_mealLinks_bolusCalcResultId", + "unique": false, + "columnNames": [ + "bolusCalcResultId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_mealLinks_bolusCalcResultId` ON `${TABLE_NAME}` (`bolusCalcResultId`)" + }, + { + "name": "index_mealLinks_superbolusTempBasalId", + "unique": false, + "columnNames": [ + "superbolusTempBasalId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_mealLinks_superbolusTempBasalId` ON `${TABLE_NAME}` (`superbolusTempBasalId`)" + }, + { + "name": "index_mealLinks_noteId", + "unique": false, + "columnNames": [ + "noteId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_mealLinks_noteId` ON `${TABLE_NAME}` (`noteId`)" + } + ], + "foreignKeys": [ + { + "table": "boluses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "bolusId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "carbs", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "carbsId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "bolusCalculatorResults", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "bolusCalcResultId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "temporaryBasals", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "superbolusTempBasalId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "therapyEvents", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "noteId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "mealLinks", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "multiwaveBolusLinks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `bolusId` INTEGER NOT NULL, `extendedBolusId` INTEGER NOT NULL, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`bolusId`) REFERENCES `boluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`extendedBolusId`) REFERENCES `extendedBoluses`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`referenceId`) REFERENCES `multiwaveBolusLinks`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bolusId", + "columnName": "bolusId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "extendedBolusId", + "columnName": "extendedBolusId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_multiwaveBolusLinks_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_multiwaveBolusLinks_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + }, + { + "name": "index_multiwaveBolusLinks_bolusId", + "unique": false, + "columnNames": [ + "bolusId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_multiwaveBolusLinks_bolusId` ON `${TABLE_NAME}` (`bolusId`)" + }, + { + "name": "index_multiwaveBolusLinks_extendedBolusId", + "unique": false, + "columnNames": [ + "extendedBolusId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_multiwaveBolusLinks_extendedBolusId` ON `${TABLE_NAME}` (`extendedBolusId`)" + } + ], + "foreignKeys": [ + { + "table": "boluses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "bolusId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "extendedBoluses", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "extendedBolusId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "multiwaveBolusLinks", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "preferenceChanges", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `key` TEXT NOT NULL, `value` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "versionChanges", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `versionCode` INTEGER NOT NULL, `versionName` TEXT NOT NULL, `gitRemote` TEXT, `commitHash` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "versionCode", + "columnName": "versionCode", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "versionName", + "columnName": "versionName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gitRemote", + "columnName": "gitRemote", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "commitHash", + "columnName": "commitHash", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "userEntry", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `action` TEXT NOT NULL, `s` TEXT NOT NULL, `values` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "utcOffset", + "columnName": "utcOffset", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "action", + "columnName": "action", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "s", + "columnName": "s", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "values", + "columnName": "values", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "foods", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `name` TEXT NOT NULL, `category` TEXT, `subCategory` TEXT, `portion` REAL NOT NULL, `carbs` INTEGER NOT NULL, `fat` INTEGER, `protein` INTEGER, `energy` INTEGER, `unit` TEXT NOT NULL, `gi` INTEGER, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `foods`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "version", + "columnName": "version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isValid", + "columnName": "isValid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "referenceId", + "columnName": "referenceId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "subCategory", + "columnName": "subCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "portion", + "columnName": "portion", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "carbs", + "columnName": "carbs", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "fat", + "columnName": "fat", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "protein", + "columnName": "protein", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "energy", + "columnName": "energy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "unit", + "columnName": "unit", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gi", + "columnName": "gi", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutSystemId", + "columnName": "nightscoutSystemId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.nightscoutId", + "columnName": "nightscoutId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpType", + "columnName": "pumpType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpSerial", + "columnName": "pumpSerial", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.pumpId", + "columnName": "pumpId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.startId", + "columnName": "startId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "interfaceIDs_backing.endId", + "columnName": "endId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_foods_referenceId", + "unique": false, + "columnNames": [ + "referenceId" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_foods_referenceId` ON `${TABLE_NAME}` (`referenceId`)" + } + ], + "foreignKeys": [ + { + "table": "foods", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "referenceId" + ], + "referencedColumns": [ + "id" + ] + } + ] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7a8795e82743748b627944dc589e8626')" + ] + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/AppDatabase.kt b/database/src/main/java/info/nightscout/androidaps/database/AppDatabase.kt index 3c12b1743e..43da5e939a 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/AppDatabase.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/AppDatabase.kt @@ -6,13 +6,14 @@ import androidx.room.TypeConverters import info.nightscout.androidaps.database.daos.* import info.nightscout.androidaps.database.entities.* -const val DATABASE_VERSION = 6 +const val DATABASE_VERSION = 7 @Database(version = DATABASE_VERSION, entities = [APSResult::class, Bolus::class, BolusCalculatorResult::class, Carbs::class, EffectiveProfileSwitch::class, ExtendedBolus::class, GlucoseValue::class, ProfileSwitch::class, TemporaryBasal::class, TemporaryTarget::class, TherapyEvent::class, TotalDailyDose::class, APSResultLink::class, - MealLink::class, MultiwaveBolusLink::class, PreferenceChange::class, VersionChange::class, UserEntry::class], + MealLink::class, MultiwaveBolusLink::class, PreferenceChange::class, VersionChange::class, UserEntry::class, + Food::class], exportSchema = true) @TypeConverters(Converters::class) internal abstract class AppDatabase : RoomDatabase() { @@ -53,4 +54,6 @@ internal abstract class AppDatabase : RoomDatabase() { abstract val preferenceChangeDao: PreferenceChangeDao + abstract val foodDao: FoodDao + } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt index 81240177cc..da47ce1d55 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.database +import info.nightscout.androidaps.database.entities.Food import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.TemporaryTarget import info.nightscout.androidaps.database.entities.TherapyEvent @@ -170,6 +171,14 @@ class AppRepository @Inject internal constructor( database.therapyEventDao.compatGetTherapyEventDataFromToTime(from, to) .subscribeOn(Schedulers.io()) + // FOOD + fun getFoodData(): Single> = + database.foodDao.getFoodData() + .subscribeOn(Schedulers.io()) + + fun deleteAllFoods() = + database.foodDao.deleteAllEntries() + } @Suppress("USELESS_CAST") diff --git a/database/src/main/java/info/nightscout/androidaps/database/DatabaseModule.kt b/database/src/main/java/info/nightscout/androidaps/database/DatabaseModule.kt index e2f0c3f9d4..39c508b07a 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/DatabaseModule.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/DatabaseModule.kt @@ -34,4 +34,10 @@ open class DatabaseModule { database.execSQL("CREATE TABLE userEntry (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `utcOffset` INTEGER NOT NULL, `action` TEXT NOT NULL, `s` TEXT NOT NULL, `values` TEXT NOT NULL)") } } + + private val migration6to7 = object : Migration(6, 7) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("CREATE TABLE IF NOT EXISTS foods (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `name` TEXT NOT NULL, `category` TEXT, `subCategory` TEXT, `portion` REAL NOT NULL, `carbs` INTEGER NOT NULL, `fat` INTEGER, `protein` INTEGER, `energy` INTEGER, `unit` TEXT NOT NULL, `gi` INTEGER, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER, FOREIGN KEY(`referenceId`) REFERENCES `foods`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )") + } + } } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt b/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt index b82cc6f379..f9058a1d51 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt @@ -24,5 +24,6 @@ internal class DelegatedAppDatabase(val changes: MutableList, val datab val versionChangeDao: VersionChangeDao = DelegatedVersionChangeDao(changes, database.versionChangeDao) val userEntryDao: UserEntryDao = DelegatedUserEntryDao(changes, database.userEntryDao) val preferenceChangeDao: PreferenceChangeDao = DelegatedPreferenceChangeDao(changes, database.preferenceChangeDao) + val foodDao: FoodDao = DelegatedFoodDao(changes, database.foodDao) fun clearAllTables() = database.clearAllTables() } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/TableNames.kt b/database/src/main/java/info/nightscout/androidaps/database/TableNames.kt index fe7e6c3337..9d3a06cc55 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/TableNames.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/TableNames.kt @@ -8,6 +8,7 @@ const val TABLE_CARBS = "carbs" const val TABLE_EFFECTIVE_PROFILE_SWITCHES = "effectiveProfileSwitches" const val TABLE_EXTENDED_BOLUSES = "extendedBoluses" const val TABLE_GLUCOSE_VALUES = "glucoseValues" +const val TABLE_FOODS = "foods" const val TABLE_MEAL_LINKS = "mealLinks" const val TABLE_MULTIWAVE_BOLUS_LINKS = "multiwaveBolusLinks" const val TABLE_PROFILE_SWITCHES = "profileSwitches" diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/FoodDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/FoodDao.kt new file mode 100644 index 0000000000..830a196f19 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/FoodDao.kt @@ -0,0 +1,25 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_FOODS +import info.nightscout.androidaps.database.entities.Food +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface FoodDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_FOODS WHERE id = :id") + override fun findById(id: Long): Food? + + @Query("DELETE FROM $TABLE_FOODS") + override fun deleteAllEntries() + + @Query("SELECT * FROM $TABLE_FOODS WHERE nightscoutId = :nsId AND referenceId IS NULL") + fun findByNSId(nsId: String): Food? + + @Query("SELECT * FROM $TABLE_FOODS WHERE isValid = 1 AND referenceId IS NULL ORDER BY id DESC") + fun getFoodData(): Single> + +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TraceableDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TraceableDao.kt index 7eed5e5528..b9f58db158 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/TraceableDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TraceableDao.kt @@ -4,7 +4,6 @@ import androidx.room.Insert import androidx.room.Update import info.nightscout.androidaps.database.daos.workaround.TraceableDaoWorkaround import info.nightscout.androidaps.database.interfaces.TraceableDBEntry -import io.reactivex.Single internal interface TraceableDao : TraceableDaoWorkaround { diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedFoodDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedFoodDao.kt new file mode 100644 index 0000000000..2d37a3e5be --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedFoodDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.FoodDao +import info.nightscout.androidaps.database.entities.Food +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedFoodDao(changes: MutableList, private val dao: FoodDao) : DelegatedDao(changes), FoodDao by dao { + + override fun insertNewEntry(food: Food): Long { + changes.add(food) + return dao.insertNewEntry(food) + } + + override fun updateExistingEntry(food: Food): Long { + changes.add(food) + return dao.updateExistingEntry(food) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/Food.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/Food.kt new file mode 100644 index 0000000000..9c4cfc9129 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/Food.kt @@ -0,0 +1,73 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.Embedded +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index +import androidx.room.PrimaryKey +import info.nightscout.androidaps.database.TABLE_FOODS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry + +@Entity(tableName = TABLE_FOODS, + foreignKeys = [ForeignKey( + entity = Food::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId")]) +data class Food( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = null, + var name: String, + var category: String? = null, + var subCategory: String? = null, + // Example: + // name="juice" portion=250 units="ml" carbs=12 + // means 250ml of juice has 12g of carbs + + var portion: Double, // common portion in "units" + var carbs: Int, // in grams + var fat: Int? = null, // in grams + var protein: Int? = null, // in grams + var energy: Int? = null, // in kJ + var unit: String = "g", + var gi: Int? = null // not used yet + +) : TraceableDBEntry { + + fun isEqual(other: Food): Boolean { + if (isValid != other.isValid) return false + if (portion != other.portion) return false + if (carbs != other.carbs) return false + if (fat != other.fat) return false + if (protein != other.protein) return false + if (energy != other.energy) return false + if (gi != other.gi) return false + if (name != other.name) return false + if (category != other.category) return false + if (subCategory != other.subCategory) return false + return unit == other.unit + } + + fun copyFrom(other: Food) { + isValid = other.isValid + name = other.name + category = other.category + subCategory = other.subCategory + portion = other.portion + carbs = other.carbs + fat = other.fat + protein = other.protein + energy = other.energy + unit = other.unit + gi = other.gi + interfaceIDs.nightscoutId = other.interfaceIDs.nightscoutId + } + +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/UserEntry.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/UserEntry.kt index 52b4086d73..ff990de675 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/entities/UserEntry.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/UserEntry.kt @@ -103,6 +103,7 @@ data class UserEntry( @SerializedName("TT_DELETED_FROM_NS") TT_DELETED_FROM_NS (ColorGroup.TT), @SerializedName("CAREPORTAL_DELETED_FROM_NS") CAREPORTAL_DELETED_FROM_NS (ColorGroup.Careportal), @SerializedName("CAREPORTAL_FROM_NS") CAREPORTAL_FROM_NS (ColorGroup.Careportal), + @SerializedName("FOOD_FROM_NS") FOOD_FROM_NS (ColorGroup.Careportal), @SerializedName("TT_FROM_NS") TT_FROM_NS (ColorGroup.TT), @SerializedName("TT_CANCELED_FROM_NS") TT_CANCELED_FROM_NS (ColorGroup.TT), @SerializedName("EXPORT_CSV") EXPORT_CSV (ColorGroup.Aaps), diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateFoodTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateFoodTransaction.kt new file mode 100644 index 0000000000..7de6457542 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertOrUpdateFoodTransaction.kt @@ -0,0 +1,28 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.Food + +/** + * Inserts or updates the Food + */ +class InsertOrUpdateFoodTransaction(private val food: Food) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + val current = database.foodDao.findById(food.id) + if (current == null) { + database.foodDao.insertNewEntry(food) + result.inserted.add(food) + } else { + database.foodDao.updateExistingEntry(food) + result.updated.add(food) + } + return result + } + + class TransactionResult { + + val inserted = mutableListOf() + val updated = mutableListOf() + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateFoodTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateFoodTransaction.kt new file mode 100644 index 0000000000..a1f7b545e9 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateFoodTransaction.kt @@ -0,0 +1,11 @@ +package info.nightscout.androidaps.database.transactions + +class InvalidateFoodTransaction(val id: Long) : Transaction() { + + override fun run() { + val food = database.foodDao.findById(id) + ?: throw IllegalArgumentException("There is no such Food with the specified ID.") + food.isValid = false + database.foodDao.updateExistingEntry(food) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncFoodTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncFoodTransaction.kt new file mode 100644 index 0000000000..bd2ab7b3cf --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/SyncFoodTransaction.kt @@ -0,0 +1,42 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.Food + +/** + * Sync the TherapyEvents from NS + */ +class SyncFoodTransaction(private val food: Food) : Transaction() { + + override fun run(): TransactionResult { + val result = TransactionResult() + + val current: Food? = + food.interfaceIDs.nightscoutId?.let { + database.foodDao.findByNSId(it) + } + + if (current != null) { + // nsId exists, update if different + if (!current.isEqual(food)) { + current.copyFrom(food) + database.foodDao.updateExistingEntry(current) + if (food.isValid && current.isValid) result.updated.add(current) + else if (!food.isValid && current.isValid) result.invalidated.add(current) + } + return result + } + + // not known nsId, add + database.foodDao.insertNewEntry(food) + result.inserted.add(food) + return result + + } + + class TransactionResult { + + val updated = mutableListOf() + val inserted = mutableListOf() + val invalidated = mutableListOf() + } +} \ No newline at end of file From 8be3ccc9895252604b610231d2a58ce8c304292d Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Fri, 19 Mar 2021 22:41:19 +0100 Subject: [PATCH 2/9] return proper result from Worker --- .../plugins/general/food/FoodPlugin.kt | 39 +++++++------- .../androidaps/plugins/source/DexcomPlugin.kt | 10 ++-- .../plugins/source/EversensePlugin.kt | 54 ++++++++++--------- .../androidaps/plugins/source/GlimpPlugin.kt | 34 ++++++------ .../androidaps/plugins/source/MM640gPlugin.kt | 27 +++++----- .../plugins/source/NSClientSourcePlugin.kt | 44 ++++++++------- .../plugins/source/PoctechPlugin.kt | 36 ++++++------- .../plugins/source/RandomBgPlugin.kt | 1 + .../androidaps/plugins/source/TomatoPlugin.kt | 35 ++++++------ .../androidaps/plugins/source/XdripPlugin.kt | 35 ++++++------ 10 files changed, 158 insertions(+), 157 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt index 6b5125eb0a..f6f5accf18 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt @@ -19,8 +19,6 @@ import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.extensions.foodFromJson import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.plusAssign import org.json.JSONArray import org.json.JSONObject import javax.inject.Inject @@ -41,8 +39,6 @@ class FoodPlugin @Inject constructor( aapsLogger, resourceHelper, injector ) { - private val disposable = CompositeDisposable() - // cannot be inner class because of needed injection class FoodWorker( context: Context, @@ -54,7 +50,6 @@ class FoodPlugin @Inject constructor( @Inject lateinit var repository: AppRepository @Inject lateinit var sp: SP @Inject lateinit var bundleStore: BundleStore - @Inject lateinit var foodPlugin: FoodPlugin init { (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) @@ -83,25 +78,31 @@ class FoodPlugin @Inject constructor( isValid = false ).also { it.interfaceIDs.nightscoutId = JsonHelper.safeGetString(jsonFood, "_id") } - foodPlugin.disposable += repository.runTransactionForResult(SyncFoodTransaction(delFood)).subscribe({ result -> - result.invalidated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Invalidated food ${it.interfaceIDs.nightscoutId}") } - }, { - aapsLogger.error(LTag.DATAFOOD, "Error while removing food", it) - ret = Result.failure() - }) + repository.runTransactionForResult(SyncFoodTransaction(delFood)) + .doOnError { + aapsLogger.error(LTag.DATAFOOD, "Error while removing food", it) + ret = Result.failure() + } + .blockingGet() + .also { + it.invalidated.forEach { f -> aapsLogger.debug(LTag.DATAFOOD, "Invalidated food ${f.interfaceIDs.nightscoutId}") } + } } else -> { val food = foodFromJson(jsonFood) if (food != null) { - foodPlugin.disposable += repository.runTransactionForResult(SyncFoodTransaction(food)).subscribe({ result -> - result.inserted.forEach { aapsLogger.debug(LTag.DATAFOOD, "Inserted food $it") } - result.updated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Updated food $it") } - result.invalidated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Invalidated food $it") } - }, { - aapsLogger.error(LTag.DATAFOOD, "Error while adding/updating food", it) - ret = Result.failure() - }) + repository.runTransactionForResult(SyncFoodTransaction(food)) + .doOnError { + aapsLogger.error(LTag.DATAFOOD, "Error while adding/updating food", it) + ret = Result.failure() + } + .blockingGet() + .also { result -> + result.inserted.forEach { aapsLogger.debug(LTag.DATAFOOD, "Inserted food $it") } + result.updated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Updated food $it") } + result.invalidated.forEach { aapsLogger.debug(LTag.DATAFOOD, "Invalidated food $it") } + } } else { aapsLogger.error(LTag.DATAFOOD, "Error parsing food", jsonFood.toString()) ret = Result.failure() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt index a7bbe19aa0..6d46974392 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt @@ -93,6 +93,8 @@ class DexcomPlugin @Inject constructor( } override fun doWork(): Result { + var ret = Result.success() + if (!dexcomPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1)) ?: return Result.failure() @@ -142,23 +144,25 @@ class DexcomPlugin @Inject constructor( broadcastToXDrip(it) if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { nsUpload.uploadBg(it, sourceSensor.text) - //aapsLogger.debug("XXXXX: dbAdd $it") } + aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") } result.updated.forEach { broadcastToXDrip(it) if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { nsUpload.updateBg(it, sourceSensor.text) - //aapsLogger.debug("XXXXX: dpUpdate $it") } + aapsLogger.debug(LTag.BGSOURCE, "Updated bg $it") } }, { aapsLogger.error("Error while saving values from Dexcom App", it) + ret = Result.failure() }) } catch (e: Exception) { aapsLogger.error("Error while processing intent from Dexcom App", e) + ret = Result.failure() } - return Result.success() + return ret } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt index 178f459c7a..b876361cad 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt @@ -4,7 +4,6 @@ import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters 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.GlucoseValue @@ -24,8 +23,6 @@ import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.plusAssign import java.util.* import javax.inject.Inject import javax.inject.Singleton @@ -48,13 +45,6 @@ class EversensePlugin @Inject constructor( override var sensorBatteryLevel = -1 - private val disposable = CompositeDisposable() - - override fun onStop() { - disposable.clear() - super.onStop() - } - // cannot be inner class because of needed injection class EversenseWorker( context: Context, @@ -76,6 +66,8 @@ class EversensePlugin @Inject constructor( } override fun doWork(): Result { + var ret = Result.success() + if (!eversensePlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1)) ?: return Result.failure() @@ -116,15 +108,20 @@ class EversensePlugin @Inject constructor( trendArrow = GlucoseValue.TrendArrow.NONE, sourceSensor = GlucoseValue.SourceSensor.EVERSENSE ) - eversensePlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues -> - savedValues.inserted.forEach { - broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) - nsUpload.uploadBg(it, GlucoseValue.SourceSensor.EVERSENSE.text) + repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) + .doOnError { + aapsLogger.error("Error while saving values from Eversense App", it) + ret = Result.failure() + } + .blockingGet() + .also { savedValues -> + savedValues.inserted.forEach { + broadcastToXDrip(it) + if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) + nsUpload.uploadBg(it, GlucoseValue.SourceSensor.EVERSENSE.text) + aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + } } - }, { - aapsLogger.error("Error while saving values from Eversense App", it) - }) } } if (bundle.containsKey("calibrationGlucoseLevels")) { @@ -136,22 +133,29 @@ class EversensePlugin @Inject constructor( aapsLogger.debug(LTag.BGSOURCE, "calibrationTimestamps" + Arrays.toString(calibrationTimestamps)) aapsLogger.debug(LTag.BGSOURCE, "calibrationRecordNumbers" + Arrays.toString(calibrationRecordNumbers)) for (i in calibrationGlucoseLevels.indices) { - eversensePlugin.disposable += repository.runTransactionForResult(InsertTherapyEventIfNewTransaction( + repository.runTransactionForResult(InsertTherapyEventIfNewTransaction( timestamp = calibrationTimestamps[i], type = TherapyEvent.Type.FINGER_STICK_BG_VALUE, glucose = calibrationGlucoseLevels[i].toDouble(), glucoseType = TherapyEvent.MeterType.FINGER, glucoseUnit = TherapyEvent.GlucoseUnit.MGDL, enteredBy = "AndroidAPS-Eversense" - )).subscribe({ result -> - result.inserted.forEach { nsUpload.uploadEvent(it) } - }, { - aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it) - }) + )) + .doOnError { + aapsLogger.error(LTag.BGSOURCE, "Error while saving therapy event", it) + ret = Result.failure() + } + .blockingGet() + .also { result -> + result.inserted.forEach { + nsUpload.uploadEvent(it) + aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + } + } } } } - return Result.success() + return ret } } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt index f1b9c6d29e..c61e2a4065 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt @@ -18,8 +18,6 @@ import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.plusAssign import javax.inject.Inject import javax.inject.Singleton @@ -38,13 +36,6 @@ class GlimpPlugin @Inject constructor( aapsLogger, resourceHelper, injector ), BgSourceInterface { - private val disposable = CompositeDisposable() - - override fun onStop() { - disposable.clear() - super.onStop() - } - // cannot be inner class because of needed injection class GlimpWorker( context: Context, @@ -64,6 +55,8 @@ class GlimpPlugin @Inject constructor( } override fun doWork(): Result { + var ret = Result.success() + if (!glimpPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() aapsLogger.debug(LTag.BGSOURCE, "Received Glimp Data: $inputData}") val glucoseValues = mutableListOf() @@ -75,16 +68,21 @@ class GlimpPlugin @Inject constructor( trendArrow = GlucoseValue.TrendArrow.fromString(inputData.getString("myTrend")), sourceSensor = GlucoseValue.SourceSensor.GLIMP ) - glimpPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues -> - savedValues.inserted.forEach { - broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) - nsUpload.uploadBg(it, GlucoseValue.SourceSensor.GLIMP.text) + repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) + .doOnError { + aapsLogger.error("Error while saving values from Glimp App", it) + ret = Result.failure() } - }, { - aapsLogger.error("Error while saving values from Glimp App", it) - }) - return Result.success() + .blockingGet() + .also { savedValues -> + savedValues.inserted.forEach { + broadcastToXDrip(it) + if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) + nsUpload.uploadBg(it, GlucoseValue.SourceSensor.GLIMP.text) + aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + } + } + return ret } } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt index b2e66f2e38..99b757545a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt @@ -20,8 +20,6 @@ import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.plusAssign import org.json.JSONArray import org.json.JSONException import javax.inject.Inject @@ -41,13 +39,6 @@ class MM640gPlugin @Inject constructor( aapsLogger, resourceHelper, injector ), BgSourceInterface { - private val disposable = CompositeDisposable() - - override fun onStop() { - disposable.clear() - super.onStop() - } - // cannot be inner class because of needed injection class MM640gWorker( context: Context, @@ -69,6 +60,8 @@ class MM640gPlugin @Inject constructor( } override fun doWork(): Result { + var ret = Result.success() + if (!mM640gPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() val collection = inputData.getString("collection") ?: return Result.failure() if (collection == "entries") { @@ -93,21 +86,27 @@ class MM640gPlugin @Inject constructor( else -> aapsLogger.debug(LTag.BGSOURCE, "Unknown entries type: $type") } } - mM640gPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues -> + repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) + .doOnError { + aapsLogger.error("Error while saving values from Eversense App", it) + ret = Result.failure() + } + .blockingGet() + .also { savedValues -> savedValues.all().forEach { broadcastToXDrip(it) if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) nsUpload.uploadBg(it, GlucoseValue.SourceSensor.MM_600_SERIES.text) + aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") } - }, { - aapsLogger.error("Error while saving values from Eversense App", it) - }) + } } catch (e: JSONException) { aapsLogger.error("Exception: ", e) + ret = Result.failure() } } } - return Result.success() + return ret } } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt index 35e2be8f7c..89de2b425f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt @@ -22,8 +22,6 @@ import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.plusAssign import org.json.JSONArray import org.json.JSONObject import javax.inject.Inject @@ -55,13 +53,6 @@ class NSClientSourcePlugin @Inject constructor( } } - private val disposable = CompositeDisposable() - - override fun onStop() { - disposable.clear() - super.onStop() - } - override fun advancedFilteringSupported(): Boolean { return isAdvancedFilteringEnabled } @@ -113,7 +104,10 @@ class NSClientSourcePlugin @Inject constructor( ) } + @Suppress("SpellCheckingInspection") override fun doWork(): Result { + var ret = Result.success() + if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_autobackfill, true) && !dexcomPlugin.isEnabled()) return Result.failure() try { val glucoseValues = mutableListOf() @@ -127,27 +121,31 @@ class NSClientSourcePlugin @Inject constructor( for (i in 0 until jsonArray.length()) glucoseValues += toGv(jsonArray.getJSONObject(i)) } - nsClientSourcePlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null, !nsClientSourcePlugin.isEnabled())).subscribe({ result -> - result.updated.forEach { - //aapsLogger.debug("XXXXX: Updated $it") - broadcastToXDrip(it) - nsClientSourcePlugin.detectSource(it) + repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null, !nsClientSourcePlugin.isEnabled())) + .doOnError { + aapsLogger.error("Error while saving values from NSClient App", it) + ret = Result.failure() } - result.inserted.forEach { - //aapsLogger.debug("XXXXX: Inserted $it") - broadcastToXDrip(it) - nsClientSourcePlugin.detectSource(it) + .blockingGet() + .also { result -> + result.updated.forEach { + broadcastToXDrip(it) + nsClientSourcePlugin.detectSource(it) + aapsLogger.debug(LTag.BGSOURCE, "Updated bg $it") + } + result.inserted.forEach { + broadcastToXDrip(it) + nsClientSourcePlugin.detectSource(it) + aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + } } - }, { - aapsLogger.error("Error while saving values from NSClient App", it) - }) } catch (e: Exception) { aapsLogger.error("Unhandled exception", e) - return Result.failure() + ret = Result.failure() } // Objectives 0 sp.putBoolean(R.string.key_ObjectivesbgIsAvailableInNS, true) - return Result.success() + return ret } } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt index 3e00ea8690..09c5204309 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt @@ -20,8 +20,6 @@ import info.nightscout.androidaps.utils.JsonHelper.safeGetString import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.plusAssign import org.json.JSONArray import org.json.JSONException import javax.inject.Inject @@ -42,13 +40,6 @@ class PoctechPlugin @Inject constructor( aapsLogger, resourceHelper, injector ), BgSourceInterface { - private val disposable = CompositeDisposable() - - override fun onStop() { - disposable.clear() - super.onStop() - } - // cannot be inner class because of needed injection class PoctechWorker( context: Context, @@ -68,6 +59,8 @@ class PoctechPlugin @Inject constructor( } override fun doWork(): Result { + var ret = Result.success() + if (!poctechPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() aapsLogger.debug(LTag.BGSOURCE, "Received Poctech Data $inputData") try { @@ -86,20 +79,25 @@ class PoctechPlugin @Inject constructor( sourceSensor = GlucoseValue.SourceSensor.POCTECH_NATIVE ) } - poctechPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues -> - savedValues.inserted.forEach { - broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) - nsUpload.uploadBg(it, GlucoseValue.SourceSensor.POCTECH_NATIVE.text) + repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) + .doOnError { + aapsLogger.error("Error while saving values from Poctech App", it) + ret = Result.failure() + } + .blockingGet() + .also { savedValues -> + savedValues.inserted.forEach { + broadcastToXDrip(it) + if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) + nsUpload.uploadBg(it, GlucoseValue.SourceSensor.POCTECH_NATIVE.text) + aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + } } - }, { - aapsLogger.error("Error while saving values from Poctech App", it) - }) } catch (e: JSONException) { aapsLogger.error("Exception: ", e) - return Result.failure() + ret = Result.failure() } - return Result.success() + return ret } } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt index f0d78816a9..aa776557ae 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt @@ -112,6 +112,7 @@ class RandomBgPlugin @Inject constructor( xDripBroadcast(it) if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) nsUpload.uploadBg(it, GlucoseValue.SourceSensor.RANDOM.text) + aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") } }, { aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Random plugin", it) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt index fb99ac1d68..db1710d6e2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt @@ -18,8 +18,6 @@ import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.plusAssign import javax.inject.Inject import javax.inject.Singleton @@ -39,13 +37,6 @@ class TomatoPlugin @Inject constructor( aapsLogger, resourceHelper, injector ), BgSourceInterface { - private val disposable = CompositeDisposable() - - override fun onStop() { - disposable.clear() - super.onStop() - } - // cannot be inner class because of needed injection class TomatoWorker( context: Context, @@ -64,7 +55,10 @@ class TomatoPlugin @Inject constructor( (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) } + @Suppress("SpellCheckingInspection") override fun doWork(): Result { + var ret = Result.success() + if (!tomatoPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() val glucoseValues = mutableListOf() glucoseValues += CgmSourceTransaction.TransactionGlucoseValue( @@ -75,16 +69,21 @@ class TomatoPlugin @Inject constructor( trendArrow = GlucoseValue.TrendArrow.NONE, sourceSensor = GlucoseValue.SourceSensor.LIBRE_1_TOMATO ) - tomatoPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues -> - savedValues.inserted.forEach { - broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) - nsUpload.uploadBg(it, GlucoseValue.SourceSensor.LIBRE_1_TOMATO.text) + repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) + .doOnError { + aapsLogger.error("Error while saving values from Tomato App", it) + ret = Result.failure() } - }, { - aapsLogger.error("Error while saving values from Tomato App", it) - }) - return Result.success() + .blockingGet() + .also { savedValues -> + savedValues.inserted.forEach { + broadcastToXDrip(it) + if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) + nsUpload.uploadBg(it, GlucoseValue.SourceSensor.LIBRE_1_TOMATO.text) + aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + } + } + return ret } } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt index d0b03ef57e..94abeea54e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt @@ -18,8 +18,6 @@ import info.nightscout.androidaps.receivers.BundleStore import info.nightscout.androidaps.receivers.DataReceiver import info.nightscout.androidaps.services.Intents import info.nightscout.androidaps.utils.resources.ResourceHelper -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.plusAssign import javax.inject.Inject import javax.inject.Singleton @@ -55,19 +53,13 @@ class XdripPlugin @Inject constructor( ).any { it == glucoseValue.sourceSensor } } - private val disposable = CompositeDisposable() - - override fun onStop() { - disposable.clear() - super.onStop() - } - // cannot be inner class because of needed injection class XdripWorker( context: Context, params: WorkerParameters ) : Worker(context, params) { + @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var xdripPlugin: XdripPlugin @Inject lateinit var repository: AppRepository @Inject lateinit var bundleStore: BundleStore @@ -77,11 +69,13 @@ class XdripPlugin @Inject constructor( } override fun doWork(): Result { + var ret = Result.success() + if (!xdripPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1)) ?: return Result.failure() - - xdripPlugin.aapsLogger.debug(LTag.BGSOURCE, "Received xDrip data: $bundle") + + aapsLogger.debug(LTag.BGSOURCE, "Received xDrip data: $bundle") val glucoseValues = mutableListOf() glucoseValues += CgmSourceTransaction.TransactionGlucoseValue( timestamp = bundle.getLong(Intents.EXTRA_TIMESTAMP, 0), @@ -92,15 +86,20 @@ class XdripPlugin @Inject constructor( sourceSensor = GlucoseValue.SourceSensor.fromString(bundle.getString(Intents.XDRIP_DATA_SOURCE_DESCRIPTION) ?: "") ) - xdripPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues -> - savedValues.all().forEach { - xdripPlugin.detectSource(it) + repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) + .doOnError { + aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Eversense App", it) + ret = Result.failure() + } + .blockingGet() + .also { savedValues -> + savedValues.all().forEach { + xdripPlugin.detectSource(it) + aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + } } - }, { - xdripPlugin.aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Eversense App", it) - }) xdripPlugin.sensorBatteryLevel = bundle.getInt(Intents.EXTRA_SENSOR_BATTERY, -1) - return Result.success() + return ret } } } From e53c91fc582396e41efd432b81ea995367891b7c Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Sat, 20 Mar 2021 12:30:57 +0100 Subject: [PATCH 3/9] DataWorker, NSDeviceStatus -> kt --- .../info/nightscout/androidaps/MainApp.kt | 3 - .../dataBroadcaster/DataBroadcastPlugin.kt | 2 +- .../plugins/general/food/FoodPlugin.kt | 11 +- .../general/nsclient/NSClientPlugin.java | 6 +- .../general/nsclient/NSClientWorker.java | 11 +- .../general/nsclient/data/NSDeviceStatus.java | 481 ------------------ .../general/nsclient/data/NSDeviceStatus.kt | 396 ++++++++++++++ .../nsclient/services/NSClientService.java | 168 +++--- .../general/overview/OverviewFragment.kt | 2 +- .../smsCommunicator/SmsCommunicatorPlugin.kt | 28 +- .../wearintegration/WatchUpdaterService.java | 2 +- .../plugins/profile/ns/NSProfilePlugin.kt | 24 +- .../androidaps/plugins/source/DexcomPlugin.kt | 7 +- .../plugins/source/EversensePlugin.kt | 7 +- .../androidaps/plugins/source/MM640gPlugin.kt | 4 +- .../plugins/source/NSClientSourcePlugin.kt | 34 +- .../androidaps/plugins/source/XdripPlugin.kt | 7 +- .../androidaps/receivers/BundleStore.kt | 24 - .../androidaps/receivers/DataReceiver.kt | 45 +- .../androidaps/receivers/DataWorker.kt | 70 +++ .../nightscout/androidaps/services/Intents.kt | 5 +- .../nightscout/androidaps/logging/LTag.kt | 2 +- 22 files changed, 617 insertions(+), 722 deletions(-) delete mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSDeviceStatus.kt delete mode 100644 app/src/main/java/info/nightscout/androidaps/receivers/BundleStore.kt create mode 100644 app/src/main/java/info/nightscout/androidaps/receivers/DataWorker.kt diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.kt b/app/src/main/java/info/nightscout/androidaps/MainApp.kt index 420f27427d..40f03c6a69 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.kt @@ -105,11 +105,8 @@ class MainApp : DaggerApplication() { filter.addAction(Intents.ACTION_NEW_TREATMENT) filter.addAction(Intents.ACTION_CHANGED_TREATMENT) filter.addAction(Intents.ACTION_REMOVED_TREATMENT) - filter.addAction(Intents.ACTION_NEW_SGV) - filter.addAction(Intents.ACTION_NEW_PROFILE) filter.addAction(Intents.ACTION_NEW_MBG) filter.addAction(Intents.ACTION_NEW_CAL) - filter.addAction(Intents.ACTION_FOOD) LocalBroadcastManager.getInstance(this).registerReceiver(DataReceiver(), filter) filter = IntentFilter() filter.addAction(Intent.ACTION_TIME_CHANGED) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt index 1f23c29588..4ff7ce4d14 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt @@ -163,7 +163,7 @@ class DataBroadcastPlugin @Inject constructor( bundle.putString("enacted", loopPlugin.lastRun?.request?.json().toString()) } } else { //NSClient or remote - val data = NSDeviceStatus.deviceStatusOpenAPSData + val data = nsDeviceStatus.deviceStatusOpenAPSData if (data.clockSuggested != 0L && data.suggested != null) { bundle.putLong("suggestedTimeStamp", data.clockSuggested) bundle.putString("suggested", data.suggested.toString()) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt index f6f5accf18..f0f78a8577 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/food/FoodPlugin.kt @@ -13,8 +13,7 @@ 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.receivers.BundleStore -import info.nightscout.androidaps.receivers.DataReceiver +import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.extensions.foodFromJson import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -49,21 +48,19 @@ class FoodPlugin @Inject constructor( @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var repository: AppRepository @Inject lateinit var sp: SP - @Inject lateinit var bundleStore: BundleStore + @Inject lateinit var dataWorker: DataWorker init { (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) } override fun doWork(): Result { - aapsLogger.debug(LTag.DATAFOOD, "Received Food Data: $inputData}") - val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1)) + val foods = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) ?: return Result.failure() + aapsLogger.debug(LTag.DATAFOOD, "Received Food Data: $foods") var ret = Result.success() - val foodsString = bundle.getString("foods") ?: return Result.failure() - val foods = JSONArray(foodsString) for (index in 0 until foods.length()) { val jsonFood: JSONObject = foods.getJSONObject(index) 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 66aa97f51a..e5221da1f2 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 @@ -433,7 +433,7 @@ public class NSClientPlugin extends PluginBase { // room Therapy Event TherapyEvent therapyEvent = therapyEventFromNsIdForInvalidating(_id); disposable.add(repository.runTransactionForResult(new SyncTherapyEventTransaction(therapyEvent)).subscribe( - result -> result.getInvalidated().forEach(record -> uel.log(Action.CAREPORTAL_DELETED_FROM_NS, record.getNote() , new ValueWithUnit(record.getTimestamp(), Units.Timestamp, true), new ValueWithUnit(record.getType().getText(), Units.TherapyEvent))), + result -> result.getInvalidated().forEach(record -> uel.log(Action.CAREPORTAL_DELETED_FROM_NS, record.getNote() != null ? record.getNote() : "" , new ValueWithUnit(record.getTimestamp(), Units.Timestamp, true), new ValueWithUnit(record.getType().getText(), Units.TherapyEvent))), error -> aapsLogger.error(LTag.DATABASE, "Error while removing therapy event", error))); // new DB model EventNsTreatment evtTreatment = new EventNsTreatment(EventNsTreatment.Companion.getREMOVE(), json); @@ -493,8 +493,8 @@ public class NSClientPlugin extends PluginBase { disposable.add(repository.runTransactionForResult(new SyncTherapyEventTransaction(therapyEvent)) .subscribe( result -> { - result.getInserted().forEach(record -> uel.log(Action.CAREPORTAL_FROM_NS, record.getNote() , new ValueWithUnit(record.getTimestamp(), Units.Timestamp, true), new ValueWithUnit(record.getType().getText(), Units.TherapyEvent))); - result.getInvalidated().forEach(record -> uel.log(Action.CAREPORTAL_DELETED_FROM_NS, record.getNote() , new ValueWithUnit(record.getTimestamp(), Units.Timestamp, true), new ValueWithUnit(record.getType().getText(), Units.TherapyEvent))); + result.getInserted().forEach(record -> uel.log(Action.CAREPORTAL_FROM_NS, record.getNote() != null ? record.getNote() : "", new ValueWithUnit(record.getTimestamp(), Units.Timestamp, true), new ValueWithUnit(record.getType().getText(), Units.TherapyEvent))); + result.getInvalidated().forEach(record -> uel.log(Action.CAREPORTAL_DELETED_FROM_NS, record.getNote() != null ? record.getNote() : "" , new ValueWithUnit(record.getTimestamp(), Units.Timestamp, true), new ValueWithUnit(record.getType().getText(), Units.TherapyEvent))); }, error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error))); } else { 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 index a5d4fcd597..2eae20075b 100644 --- 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 @@ -7,13 +7,10 @@ import androidx.annotation.NonNull; import androidx.work.Worker; import androidx.work.WorkerParameters; -import androidx.annotation.NonNull; - import javax.inject.Inject; import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.receivers.BundleStore; -import info.nightscout.androidaps.receivers.DataReceiver; +import info.nightscout.androidaps.receivers.DataWorker; // cannot be inner class because of needed injection public class NSClientWorker extends Worker { @@ -26,14 +23,14 @@ public class NSClientWorker extends Worker { } @Inject NSClientPlugin nsClientPlugin; - @Inject BundleStore bundleStore; + @Inject DataWorker dataWorker; @NonNull @Override public Result doWork() { - Bundle bundle = bundleStore.pickup(getInputData().getLong(DataReceiver.STORE_KEY, -1)); + Bundle bundle = dataWorker.pickupBundle(getInputData().getLong(DataWorker.STORE_KEY, -1)); if (bundle == null) return Result.failure(); - String action = getInputData().getString(DataReceiver.ACTION_KEY); + String action = getInputData().getString(DataWorker.ACTION_KEY); nsClientPlugin.handleNewDataFromNSClient(action, bundle); return Result.success(); } 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..5657f1d48e --- /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.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.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: ConfigInterface, + 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")).time 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")).time 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")).time 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")).time + 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/services/NSClientService.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java index b4be8d61c7..3d4c3390cd 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 @@ -11,6 +11,7 @@ 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; @@ -41,6 +42,7 @@ import info.nightscout.androidaps.interfaces.ProfileStore; 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.NSClientPlugin; import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue; import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAddAck; @@ -60,6 +62,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,6 +95,7 @@ public class NSClientService extends DaggerService { @Inject Config config; @Inject DateUtil dateUtil; @Inject UploadQueue uploadQueue; + @Inject DataWorker dataWorker; private final CompositeDisposable disposable = new CompositeDisposable(); @@ -534,16 +540,6 @@ 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); @@ -558,30 +554,48 @@ public class NSClientService extends DaggerService { } 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 - } - */ + /* 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 + } + */ } 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")) { @@ -635,8 +649,12 @@ public class NSClientService extends DaggerService { } if (data.has("food")) { JSONArray foods = data.getJSONArray("food"); - if (foods.length() > 0) rxBus.send(new EventNSClientNewLog("DATA", "received " + foods.length() + " foods")); - handleFood(foods, isDelta); + if (foods.length() > 0) + rxBus.send(new EventNSClientNewLog("DATA", "received " + foods.length() + " foods")); + dataWorker.enqueue( + new OneTimeWorkRequest.Builder(FoodPlugin.FoodWorker.class) + .setInputData(dataWorker.storeInputData(foods, null)) + .build()); } if (data.has("mbgs")) { JSONArray mbgs = data.getJSONArray("mbgs"); @@ -664,24 +682,23 @@ public class NSClientService extends DaggerService { 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.NS_ALARM)); - rxBus.send(new EventDismissNotification(Notification.NS_URGENT_ALARM)); - } - handleNewSgv(sgvs, isDelta); } rxBus.send(new EventNSClientNewLog("LAST", dateUtil.dateAndTimeString(latestDateInReceivedData))); } catch (JSONException e) { @@ -849,16 +866,6 @@ public class NSClientService extends DaggerService { } } - public void handleFood(JSONArray foods, boolean isDelta) { - Bundle bundle = new Bundle(); - bundle.putString("foods", foods.toString()); - bundle.putBoolean("delta", isDelta); - Intent intent = new Intent(Intents.ACTION_FOOD); - intent.putExtras(bundle); - intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); - LocalBroadcastManager.getInstance(this).sendBroadcast(intent); - } - public void handleNewCal(JSONArray cals, boolean isDelta) { Bundle bundle = new Bundle(); bundle.putString("cals", cals.toString()); @@ -879,51 +886,6 @@ public class NSClientService extends DaggerService { 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) { 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 b6bdbe4f04..1f8228d5d8 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 @@ -839,7 +839,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) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt index be4eeb41a2..e8e490bcf5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/smsCommunicator/SmsCommunicatorPlugin.kt @@ -36,11 +36,10 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotifi import info.nightscout.androidaps.plugins.general.overview.notifications.Notification import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin import info.nightscout.androidaps.queue.Callback -import info.nightscout.androidaps.receivers.BundleStore +import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.receivers.DataReceiver import info.nightscout.androidaps.utils.* import info.nightscout.androidaps.utils.extensions.valueToUnitsString @@ -176,7 +175,7 @@ class SmsCommunicatorPlugin @Inject constructor( ) : Worker(context, params) { @Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin - @Inject lateinit var bundleStore: BundleStore + @Inject lateinit var dataWorker: DataWorker init { (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) @@ -184,7 +183,7 @@ class SmsCommunicatorPlugin @Inject constructor( @Suppress("SpellCheckingInspection") override fun doWork(): Result { - val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1)) + val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1)) ?: return Result.failure() val format = bundle.getString("format") ?: return Result.failure() val pdus = bundle["pdus"] as Array<*> @@ -731,7 +730,7 @@ class SmsCommunicatorPlugin @Inject constructor( var replyText = resourceHelper.gs(R.string.smscommunicator_extendedcancelfailed) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMS(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true),ValueWithUnit(R.string.smscommunicator_extendedcanceled, Units.R_String)) + uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_extendedcanceled, Units.R_String)) } } }) @@ -758,14 +757,16 @@ class SmsCommunicatorPlugin @Inject constructor( replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) if (config.APS) - uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_extendedset, 2), ValueWithUnit(aDouble ?:0.0, Units.U), ValueWithUnit(duration, Units.M), ValueWithUnit(R.string.loopsuspended, Units.R_String)) - else - uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_extendedset, 2), ValueWithUnit(aDouble ?:0.0, Units.U), ValueWithUnit(duration, Units.M)) + uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_extendedset, 2), ValueWithUnit(aDouble + ?: 0.0, Units.U), ValueWithUnit(duration, Units.M), ValueWithUnit(R.string.loopsuspended, Units.R_String)) + else + uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_extendedset, 2), ValueWithUnit(aDouble + ?: 0.0, Units.U), ValueWithUnit(duration, Units.M)) } else { var replyText = resourceHelper.gs(R.string.smscommunicator_extendedfailed) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMS(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true),ValueWithUnit(R.string.smscommunicator_extendedfailed, Units.R_String)) + uel.log(Action.SMS_EXTENDED_BOLUS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_extendedfailed, Units.R_String)) } } }) @@ -883,12 +884,14 @@ class SmsCommunicatorPlugin @Inject constructor( var replyText = String.format(resourceHelper.gs(R.string.smscommunicator_carbsset), anInteger) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_CARBS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_carbsset, 1), ValueWithUnit(anInteger ?:0,Units.G)) + uel.log(Action.SMS_CARBS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_carbsset, 1), ValueWithUnit(anInteger + ?: 0, Units.G)) } else { var replyText = resourceHelper.gs(R.string.smscommunicator_carbsfailed, anInteger) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMS(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_CARBS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_carbsfailed, 1), ValueWithUnit(anInteger ?:0,Units.G)) + uel.log(Action.SMS_CARBS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_carbsfailed, 1), ValueWithUnit(anInteger + ?: 0, Units.G)) } } }) @@ -897,7 +900,8 @@ class SmsCommunicatorPlugin @Inject constructor( var replyText = String.format(resourceHelper.gs(R.string.smscommunicator_carbsset), anInteger) replyText += "\n" + activePlugin.activePump.shortStatus(true) sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText)) - uel.log(Action.SMS_CARBS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_carbsset, 1), ValueWithUnit(anInteger ?:0,Units.G)) + uel.log(Action.SMS_CARBS, activePlugin.activePump.shortStatus(true), ValueWithUnit(R.string.smscommunicator_carbsset, 1), ValueWithUnit(anInteger + ?: 0, Units.G)) } } }) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java index 8fa51862c9..db97d25b17 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/WatchUpdaterService.java @@ -715,7 +715,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog openApsStatus = loopPlugin.getLastRun() != null && loopPlugin.getLastRun().getLastTBREnact() != 0 ? loopPlugin.getLastRun().getLastTBREnact() : -1; } else { //NSClient or remote - openApsStatus = NSDeviceStatus.getOpenApsTimestamp(); + openApsStatus = nsDeviceStatus.getOpenApsTimestamp(); } PutDataMapRequest dataMapRequest = PutDataMapRequest.create(NEW_STATUS_PATH); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.kt index 5109f6811c..e2c3c56608 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/profile/ns/NSProfilePlugin.kt @@ -17,8 +17,7 @@ import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart import info.nightscout.androidaps.plugins.profile.ns.events.EventNSProfileUpdateGUI -import info.nightscout.androidaps.receivers.BundleStore -import info.nightscout.androidaps.receivers.DataReceiver +import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import org.json.JSONObject @@ -89,26 +88,23 @@ class NSProfilePlugin @Inject constructor( @Inject lateinit var nsProfilePlugin: NSProfilePlugin @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var rxBus: RxBusWrapper - @Inject lateinit var bundleStore: BundleStore + @Inject lateinit var dataWorker: DataWorker init { (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) } override fun doWork(): Result { - val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1)) + val profileString = dataWorker.pickupJSONObject(inputData.getLong(DataWorker.STORE_KEY, -1)) ?: return Result.failure() - bundle.getString("profile")?.let { profileString -> - nsProfilePlugin.profile = ProfileStore(injector, JSONObject(profileString)) - nsProfilePlugin.storeNSProfile() - if (nsProfilePlugin.isEnabled()) { - rxBus.send(EventProfileStoreChanged()) - rxBus.send(EventNSProfileUpdateGUI()) - } - aapsLogger.debug(LTag.PROFILE, "Received profileStore: ${nsProfilePlugin.profile}") - return Result.success() + nsProfilePlugin.profile = ProfileStore(injector, profileString) + nsProfilePlugin.storeNSProfile() + if (nsProfilePlugin.isEnabled()) { + rxBus.send(EventProfileStoreChanged()) + rxBus.send(EventNSProfileUpdateGUI()) } - return Result.failure() + aapsLogger.debug(LTag.PROFILE, "Received profileStore: ${nsProfilePlugin.profile}") + return Result.success() } } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt index 6d46974392..8a45930cda 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt @@ -21,8 +21,7 @@ import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.general.nsclient.NSUpload -import info.nightscout.androidaps.receivers.BundleStore -import info.nightscout.androidaps.receivers.DataReceiver +import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.XDripBroadcast @@ -84,7 +83,7 @@ class DexcomPlugin @Inject constructor( @Inject lateinit var dexcomPlugin: DexcomPlugin @Inject lateinit var nsUpload: NSUpload @Inject lateinit var sp: SP - @Inject lateinit var bundleStore: BundleStore + @Inject lateinit var dataWorker: DataWorker @Inject lateinit var broadcastToXDrip: XDripBroadcast @Inject lateinit var repository: AppRepository @@ -96,7 +95,7 @@ class DexcomPlugin @Inject constructor( var ret = Result.success() if (!dexcomPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() - val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1)) + val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1)) ?: return Result.failure() try { val sourceSensor = when (bundle.getString("sensorType") ?: "") { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt index b876361cad..f585fbfff5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt @@ -17,8 +17,7 @@ import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.general.nsclient.NSUpload -import info.nightscout.androidaps.receivers.BundleStore -import info.nightscout.androidaps.receivers.DataReceiver +import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -57,7 +56,7 @@ class EversensePlugin @Inject constructor( @Inject lateinit var sp: SP @Inject lateinit var nsUpload: NSUpload @Inject lateinit var dateUtil: DateUtil - @Inject lateinit var bundleStore: BundleStore + @Inject lateinit var dataWorker: DataWorker @Inject lateinit var repository: AppRepository @Inject lateinit var broadcastToXDrip: XDripBroadcast @@ -69,7 +68,7 @@ class EversensePlugin @Inject constructor( var ret = Result.success() if (!eversensePlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() - val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1)) + val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1)) ?: return Result.failure() if (bundle.containsKey("currentCalibrationPhase")) aapsLogger.debug(LTag.BGSOURCE, "currentCalibrationPhase: " + bundle.getString("currentCalibrationPhase")) if (bundle.containsKey("placementModeInProgress")) aapsLogger.debug(LTag.BGSOURCE, "placementModeInProgress: " + bundle.getBoolean("placementModeInProgress")) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt index 99b757545a..1bb431e59b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt @@ -15,7 +15,7 @@ import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.general.nsclient.NSUpload -import info.nightscout.androidaps.receivers.BundleStore +import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -51,7 +51,7 @@ class MM640gPlugin @Inject constructor( @Inject lateinit var sp: SP @Inject lateinit var nsUpload: NSUpload @Inject lateinit var dateUtil: DateUtil - @Inject lateinit var bundleStore: BundleStore + @Inject lateinit var dataWorker: DataWorker @Inject lateinit var repository: AppRepository @Inject lateinit var broadcastToXDrip: XDripBroadcast diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt index 89de2b425f..ca6b3513d4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt @@ -15,10 +15,14 @@ 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.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv -import info.nightscout.androidaps.receivers.BundleStore +import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification +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.T import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -80,9 +84,10 @@ class NSClientSourcePlugin @Inject constructor( @Inject lateinit var injector: HasAndroidInjector @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var sp: SP + @Inject lateinit var rxBus: RxBusWrapper @Inject lateinit var nsUpload: NSUpload @Inject lateinit var dateUtil: DateUtil - @Inject lateinit var bundleStore: BundleStore + @Inject lateinit var dataWorker: DataWorker @Inject lateinit var repository: AppRepository @Inject lateinit var broadcastToXDrip: XDripBroadcast @Inject lateinit var dexcomPlugin: DexcomPlugin @@ -109,18 +114,27 @@ class NSClientSourcePlugin @Inject constructor( var ret = Result.success() if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_autobackfill, true) && !dexcomPlugin.isEnabled()) return Result.failure() + + val sgvs = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) + ?: return Result.failure() + try { + var latestDateInReceivedData: Long = 0 + + aapsLogger.debug(LTag.BGSOURCE, "Received NS Data: $sgvs") val glucoseValues = mutableListOf() - inputData.getString("sgv")?.let { sgvString -> - aapsLogger.debug(LTag.BGSOURCE, "Received NS Data: $sgvString") - glucoseValues += toGv(JSONObject(sgvString)) + for (i in 0 until sgvs.length()) { + val sgv = toGv(sgvs.getJSONObject(i)) + if (sgv.timestamp < dateUtil._now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp + glucoseValues += sgv + } - inputData.getString("sgvs")?.let { sgvString -> - aapsLogger.debug(LTag.BGSOURCE, "Received NS Data: $sgvString") - val jsonArray = JSONArray(sgvString) - for (i in 0 until jsonArray.length()) - glucoseValues += toGv(jsonArray.getJSONObject(i)) + // Was that sgv more less 5 mins ago ? + if (T.msecs(dateUtil._now() - latestDateInReceivedData).mins() < 5L) { + rxBus.send(EventDismissNotification(Notification.NS_ALARM)) + rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM)) } + repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null, !nsClientSourcePlugin.isEnabled())) .doOnError { aapsLogger.error("Error while saving values from NSClient App", it) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt index 94abeea54e..3862e9f6d5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt @@ -14,8 +14,7 @@ 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.receivers.BundleStore -import info.nightscout.androidaps.receivers.DataReceiver +import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.services.Intents import info.nightscout.androidaps.utils.resources.ResourceHelper import javax.inject.Inject @@ -62,7 +61,7 @@ class XdripPlugin @Inject constructor( @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var xdripPlugin: XdripPlugin @Inject lateinit var repository: AppRepository - @Inject lateinit var bundleStore: BundleStore + @Inject lateinit var dataWorker: DataWorker init { (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) @@ -72,7 +71,7 @@ class XdripPlugin @Inject constructor( var ret = Result.success() if (!xdripPlugin.isEnabled(PluginType.BGSOURCE)) return Result.failure() - val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1)) + val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1)) ?: return Result.failure() aapsLogger.debug(LTag.BGSOURCE, "Received xDrip data: $bundle") diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/BundleStore.kt b/app/src/main/java/info/nightscout/androidaps/receivers/BundleStore.kt deleted file mode 100644 index 36e7e7bf7e..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/receivers/BundleStore.kt +++ /dev/null @@ -1,24 +0,0 @@ -package info.nightscout.androidaps.receivers - -import android.os.Bundle -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class BundleStore @Inject constructor() { - private val store = HashMap() - private var counter = 0L - - @Synchronized - fun store(bundle: Bundle) : Long { - store.put(counter, bundle) - return counter++ - } - - @Synchronized - fun pickup(key: Long) : Bundle? { - val bundle = store[key] - store.remove(key) - return bundle - } -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt index 862d470dfd..81b929b4f9 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt +++ b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt @@ -2,20 +2,15 @@ package info.nightscout.androidaps.receivers import android.content.Context import android.content.Intent -import android.os.Bundle import android.provider.Telephony import androidx.work.Data -import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequest -import androidx.work.WorkManager import dagger.android.DaggerBroadcastReceiver import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.BundleLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.general.food.FoodPlugin import info.nightscout.androidaps.plugins.general.nsclient.NSClientWorker import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin -import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin import info.nightscout.androidaps.plugins.source.* import info.nightscout.androidaps.services.Intents import info.nightscout.androidaps.utils.extensions.copyDouble @@ -27,9 +22,7 @@ import javax.inject.Inject open class DataReceiver : DaggerBroadcastReceiver() { @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var bundleStore: BundleStore - - private val jobGroupName = "data" + @Inject lateinit var dataWorker: DataWorker override fun onReceive(context: Context, intent: Intent) { super.onReceive(context, intent) @@ -40,7 +33,7 @@ open class DataReceiver : DaggerBroadcastReceiver() { when (intent.action) { Intents.ACTION_NEW_BG_ESTIMATE -> OneTimeWorkRequest.Builder(XdripPlugin.XdripWorker::class.java) - .setInputData(bundleInputData(bundle, intent)).build() + .setInputData(dataWorker.storeInputData(bundle, intent)).build() Intents.POCTECH_BG -> OneTimeWorkRequest.Builder(PoctechPlugin.PoctechWorker::class.java) .setInputData(Data.Builder().also { @@ -54,20 +47,12 @@ open class DataReceiver : DaggerBroadcastReceiver() { it.copyLong("myTimestamp", bundle) }.build()).build() Intents.TOMATO_BG -> + @Suppress("SpellCheckingInspection") OneTimeWorkRequest.Builder(TomatoPlugin.TomatoWorker::class.java) .setInputData(Data.Builder().also { it.copyDouble("com.fanqies.tomatofn.Extras.BgEstimate", bundle) it.copyLong("com.fanqies.tomatofn.Extras.Time", bundle) }.build()).build() - Intents.ACTION_NEW_PROFILE -> - OneTimeWorkRequest.Builder(NSProfilePlugin.NSProfileWorker::class.java) - .setInputData(bundleInputData(bundle, intent)).build() - Intents.ACTION_NEW_SGV -> - OneTimeWorkRequest.Builder(NSClientSourcePlugin.NSClientSourceWorker::class.java) - .setInputData(Data.Builder().also { - it.copyString("sgv", bundle, null) - it.copyString("sgvs", bundle, null) - }.build()).build() Intents.NS_EMULATOR -> OneTimeWorkRequest.Builder(MM640gPlugin.MM640gWorker::class.java) .setInputData(Data.Builder().also { @@ -80,36 +65,22 @@ open class DataReceiver : DaggerBroadcastReceiver() { }.build()).build() Telephony.Sms.Intents.SMS_RECEIVED_ACTION -> OneTimeWorkRequest.Builder(SmsCommunicatorPlugin.SmsCommunicatorWorker::class.java) - .setInputData(bundleInputData(bundle, intent)).build() + .setInputData(dataWorker.storeInputData(bundle, intent)).build() Intents.EVERSENSE_BG -> OneTimeWorkRequest.Builder(EversensePlugin.EversenseWorker::class.java) - .setInputData(bundleInputData(bundle, intent)).build() + .setInputData(dataWorker.storeInputData(bundle, intent)).build() Intents.DEXCOM_BG -> OneTimeWorkRequest.Builder(DexcomPlugin.DexcomWorker::class.java) - .setInputData(bundleInputData(bundle, intent)).build() - Intents.ACTION_FOOD -> - OneTimeWorkRequest.Builder(FoodPlugin.FoodWorker::class.java) - .setInputData(bundleInputData(bundle, intent)).build() + .setInputData(dataWorker.storeInputData(bundle, intent)).build() Intents.ACTION_NEW_TREATMENT, Intents.ACTION_CHANGED_TREATMENT, Intents.ACTION_REMOVED_TREATMENT, Intents.ACTION_NEW_CAL, Intents.ACTION_NEW_MBG -> OneTimeWorkRequest.Builder(NSClientWorker::class.java) - .setInputData(bundleInputData(bundle, intent)).build() + .setInputData(dataWorker.storeInputData(bundle, intent)).build() else -> null - }?.let { request -> - WorkManager.getInstance(context) - .enqueueUniqueWork(jobGroupName, ExistingWorkPolicy.APPEND_OR_REPLACE, request) - } + }?.let { request -> dataWorker.enqueue(request) } } - private fun bundleInputData(bundle: Bundle, intent: Intent) = - Data.Builder().putLong(STORE_KEY, bundleStore.store(bundle)).putString(ACTION_KEY, intent.action).build() - - companion object { - - const val STORE_KEY = "storeKey" - const val ACTION_KEY = "action" - } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/DataWorker.kt b/app/src/main/java/info/nightscout/androidaps/receivers/DataWorker.kt new file mode 100644 index 0000000000..d46491b15e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/receivers/DataWorker.kt @@ -0,0 +1,70 @@ +package info.nightscout.androidaps.receivers + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.work.Data +import androidx.work.ExistingWorkPolicy +import androidx.work.OneTimeWorkRequest +import androidx.work.WorkManager +import org.json.JSONArray +import org.json.JSONObject +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class DataWorker @Inject constructor( + private val context: Context +) { + + private val store = HashMap() + private var counter = 0L + private val jobGroupName = "data" + + @Synchronized private fun store(value: Any): Long { + store[counter] = value + return counter++ + } + + @Synchronized fun pickupBundle(key: Long): Bundle? { + val value = store[key] + store.remove(key) + return value as Bundle? + } + + @Synchronized fun pickupString(key: Long): String? { + val value = store[key] + store.remove(key) + return value as String? + } + + @Synchronized fun pickupJSONArray(key: Long): JSONArray? { + val value = store[key] + store.remove(key) + return value as JSONArray? + } + + @Synchronized fun pickupJSONObject(key: Long): JSONObject? { + val value = store[key] + store.remove(key) + return value as JSONObject? + } + + fun storeInputData(value: Any, intent: Intent? = null) = + Data.Builder() + .putLong(STORE_KEY, store(value)) + .putString(ACTION_KEY, intent?.action).build() + + fun enqueue(request: OneTimeWorkRequest) { + WorkManager.getInstance(context) + .enqueueUniqueWork(jobGroupName, ExistingWorkPolicy.APPEND_OR_REPLACE, request) + + } + + companion object { + + const val STORE_KEY = "storeKey" + const val ACTION_KEY = "action" + } + +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/services/Intents.kt b/app/src/main/java/info/nightscout/androidaps/services/Intents.kt index 7255548a03..c52c68e4c6 100644 --- a/app/src/main/java/info/nightscout/androidaps/services/Intents.kt +++ b/app/src/main/java/info/nightscout/androidaps/services/Intents.kt @@ -5,7 +5,7 @@ interface Intents { companion object { - // NSClient -> App + // AAPS -> Xdrip const val ACTION_NEW_TREATMENT = "info.nightscout.client.NEW_TREATMENT" const val ACTION_CHANGED_TREATMENT = "info.nightscout.client.CHANGED_TREATMENT" const val ACTION_REMOVED_TREATMENT = "info.nightscout.client.REMOVED_TREATMENT" @@ -13,9 +13,8 @@ interface Intents { const val ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV" const val ACTION_NEW_MBG = "info.nightscout.client.NEW_MBG" const val ACTION_NEW_CAL = "info.nightscout.client.NEW_CAL" - const val ACTION_FOOD = "info.nightscout.client.FOOD" - // xDrip -> App + // xDrip -> AAPS const val ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate" const val EXTRA_BG_ESTIMATE = "com.eveningoutpost.dexdrip.Extras.BgEstimate" const val EXTRA_BG_SLOPE = "com.eveningoutpost.dexdrip.Extras.BgSlope" diff --git a/core/src/main/java/info/nightscout/androidaps/logging/LTag.kt b/core/src/main/java/info/nightscout/androidaps/logging/LTag.kt index b62d9e45a5..3e67466663 100644 --- a/core/src/main/java/info/nightscout/androidaps/logging/LTag.kt +++ b/core/src/main/java/info/nightscout/androidaps/logging/LTag.kt @@ -13,7 +13,7 @@ enum class LTag(val tag: String, val defaultValue : Boolean = true, val requires DATASERVICE("DATASERVICE"), DATATREATMENTS("DATATREATMENTS"), EVENTS("EVENTS", defaultValue = false, requiresRestart = true), - GLUCOSE("GLUCOSE"), + GLUCOSE("GLUCOSE", defaultValue = false), LOCATION("LOCATION"), NOTIFICATION("NOTIFICATION"), NSCLIENT("NSCLIENT"), From 98c75083839445a710d927f26733c624b66f0809 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Sat, 20 Mar 2021 14:51:10 +0100 Subject: [PATCH 4/9] NSClientMbgWorker --- .../nightscout/androidaps/MainActivity.kt | 2 +- .../info/nightscout/androidaps/MainApp.kt | 2 - .../dependencyInjection/WorkersModule.kt | 2 + .../general/maintenance/MaintenancePlugin.kt | 2 +- .../general/nsclient/NSClientMbgWorker.kt | 49 +++++++++++ .../general/nsclient/NSClientPlugin.java | 37 +------- .../general/nsclient/NSClientWorker.java | 1 - .../general/nsclient/data/NSSettingsStatus.kt | 54 +++++++----- .../nsclient/services/NSClientService.java | 88 +++---------------- .../androidaps/plugins/source/DexcomPlugin.kt | 12 +++ .../androidaps/receivers/DataReceiver.kt | 4 +- .../plugins/general/nsclient/data/NSMbg.java | 41 --------- .../plugins/general/nsclient/data/NSMbg.kt | 18 ++++ .../transactions/CgmSourceTransaction.kt | 23 +++-- 14 files changed, 147 insertions(+), 188 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt delete mode 100644 core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSMbg.java create mode 100644 core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSMbg.kt diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt index 072e621cdc..bccdbbcb1a 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.kt @@ -295,7 +295,7 @@ class MainActivity : NoSplashAppCompatActivity() { R.id.nav_about -> { var message = "Build: ${BuildConfig.BUILDVERSION}\n" message += "Flavor: ${BuildConfig.FLAVOR}${BuildConfig.BUILD_TYPE}\n" - message += "${resourceHelper.gs(R.string.configbuilder_nightscoutversion_label)} ${nsSettingsStatus.nightscoutVersionName}" + message += "${resourceHelper.gs(R.string.configbuilder_nightscoutversion_label)} ${nsSettingsStatus.getVersion()}" if (buildHelper.isEngineeringMode()) message += "\n${resourceHelper.gs(R.string.engineering_mode_enabled)}" if (!fabricPrivacy.fabricEnabled()) message += "\n${resourceHelper.gs(R.string.fabric_upload_disabled)}" message += resourceHelper.gs(R.string.about_link_urls) diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.kt b/app/src/main/java/info/nightscout/androidaps/MainApp.kt index 40f03c6a69..0c30ec765b 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.kt @@ -105,8 +105,6 @@ class MainApp : DaggerApplication() { filter.addAction(Intents.ACTION_NEW_TREATMENT) filter.addAction(Intents.ACTION_CHANGED_TREATMENT) filter.addAction(Intents.ACTION_REMOVED_TREATMENT) - filter.addAction(Intents.ACTION_NEW_MBG) - filter.addAction(Intents.ACTION_NEW_CAL) LocalBroadcastManager.getInstance(this).registerReceiver(DataReceiver(), filter) filter = IntentFilter() filter.addAction(Intent.ACTION_TIME_CHANGED) diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt index a82965d391..272ba15d03 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt @@ -3,6 +3,7 @@ package info.nightscout.androidaps.dependencyInjection import dagger.Module import dagger.android.ContributesAndroidInjector import info.nightscout.androidaps.plugins.general.food.FoodPlugin +import info.nightscout.androidaps.plugins.general.nsclient.NSClientMbgWorker import info.nightscout.androidaps.plugins.general.nsclient.NSClientWorker import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin @@ -23,5 +24,6 @@ abstract class WorkersModule { @ContributesAndroidInjector abstract fun contributesNSProfileWorker(): NSProfilePlugin.NSProfileWorker @ContributesAndroidInjector abstract fun contributesSmsCommunicatorWorker(): SmsCommunicatorPlugin.SmsCommunicatorWorker @ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientWorker + @ContributesAndroidInjector abstract fun contributesNSClientMbgWorker(): NSClientMbgWorker @ContributesAndroidInjector abstract fun contributesFoodWorker(): FoodPlugin.FoodWorker } \ No newline at end of file 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..a193b73030 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 @@ -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/NSClientMbgWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt new file mode 100644 index 0000000000..de25ce9320 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt @@ -0,0 +1,49 @@ +package info.nightscout.androidaps.plugins.general.nsclient + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.transactions.SyncTherapyEventTransaction +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.extensions.therapyEventFromNsMbg +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 + + override fun doWork(): Result { + var ret = Result.success() + + val mbgArray = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) + ?: return Result.failure() + for (i in 0 until mbgArray.length()) { + val nsMbg = NSMbg(mbgArray.getJSONObject(i)) + if (!nsMbg.isValid()) continue + repository.runTransactionForResult(SyncTherapyEventTransaction(therapyEventFromNsMbg(nsMbg))) + .doOnError { + aapsLogger.error("Error while saving therapy event", it) + ret = Result.failure() + } + .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 e5221da1f2..e8806efb12 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 @@ -31,7 +31,9 @@ import info.nightscout.androidaps.R; import info.nightscout.androidaps.database.AppRepository; import info.nightscout.androidaps.database.entities.TemporaryTarget; import info.nightscout.androidaps.database.entities.TherapyEvent; -import info.nightscout.androidaps.database.entities.UserEntry.*; +import info.nightscout.androidaps.database.entities.UserEntry.Action; +import info.nightscout.androidaps.database.entities.UserEntry.Units; +import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit; import info.nightscout.androidaps.database.transactions.SyncTemporaryTargetTransaction; import info.nightscout.androidaps.database.transactions.SyncTherapyEventTransaction; import info.nightscout.androidaps.events.EventAppExit; @@ -50,7 +52,6 @@ import info.nightscout.androidaps.logging.UserEntryLogger; 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; @@ -73,7 +74,6 @@ import static info.nightscout.androidaps.utils.extensions.TemporaryTargetExtensi import static info.nightscout.androidaps.utils.extensions.TemporaryTargetExtensionKt.temporaryTargetFromNsIdForInvalidating; import static info.nightscout.androidaps.utils.extensions.TherapyEventExtensionKt.therapyEventFromJson; import static info.nightscout.androidaps.utils.extensions.TherapyEventExtensionKt.therapyEventFromNsIdForInvalidating; -import static info.nightscout.androidaps.utils.extensions.TherapyEventExtensionKt.therapyEventFromNsMbg; @Singleton public class NSClientPlugin extends PluginBase { @@ -257,7 +257,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()); @@ -400,26 +400,6 @@ public class NSClientPlugin extends PluginBase { } } - 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) { @@ -518,13 +498,4 @@ public class NSClientPlugin extends PluginBase { } } - private void storeMbg(JSONObject mbgJson) { - NSMbg nsMbg = new NSMbg(getInjector(), mbgJson); - if (nsMbg.mbg != 0.0 && nsMbg.date != 0) - disposable.add(repository.runTransactionForResult(new SyncTherapyEventTransaction(therapyEventFromNsMbg(nsMbg))) - .subscribe( - result -> aapsLogger.debug(LTag.DATABASE, "Saved therapy event" + result), - error -> aapsLogger.error("Error while saving therapy event", error)) - ); - } } 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 index 2eae20075b..3c97e00d95 100644 --- 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 @@ -12,7 +12,6 @@ import javax.inject.Inject; import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.receivers.DataWorker; -// cannot be inner class because of needed injection public class NSClientWorker extends Worker { public NSClientWorker( 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 70d55c2dcc..e6aafce3c1 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 @@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.general.nsclient.data import android.content.Context import info.nightscout.androidaps.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 @@ -111,6 +111,7 @@ import javax.inject.Singleton "activeProfile": "2016 +30%" } */ +@Suppress("SpellCheckingInspection") @Singleton class NSSettingsStatus @Inject constructor( private val aapsLogger: AAPSLogger, @@ -122,15 +123,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 { @@ -145,13 +161,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() = @@ -162,13 +175,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 } } @@ -176,7 +189,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) } @@ -215,9 +228,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", "") 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 3d4c3390cd..a4720d4e76 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 @@ -43,6 +43,7 @@ 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.NSClientMbgWorker; import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin; import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue; import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAddAck; @@ -52,7 +53,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; @@ -102,8 +102,6 @@ public class NSClientService extends DaggerService { static public PowerManager.WakeLock mWakeLock; private final IBinder mBinder = new NSClientService.LocalBinder(); - static ProfileStore profileStore; - static public Handler handler; public static Socket mSocket; @@ -113,9 +111,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 = ""; @@ -542,39 +537,11 @@ public class NSClientService extends DaggerService { 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 (data.has("profiles")) { JSONArray profiles = data.getJSONArray("profiles"); if (profiles.length() > 0) { @@ -638,12 +605,7 @@ public class NSClientService extends DaggerService { 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); } } @@ -656,27 +618,21 @@ public class NSClientService extends DaggerService { .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"); @@ -866,26 +822,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 handleNewTreatment(JSONArray treatments, boolean isDelta) { List splitted = splitArray(treatments); for (JSONArray part : splitted) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt index 8a45930cda..71a2a0ce65 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt @@ -153,6 +153,18 @@ class DexcomPlugin @Inject constructor( } aapsLogger.debug(LTag.BGSOURCE, "Updated bg $it") } + result.sensorInsertionsInserted.forEach { + if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { + nsUpload.uploadEvent(it) + } + aapsLogger.debug(LTag.BGSOURCE, "Inserted sensor insertion $it") + } + result.calibrationsInserted.forEach { + if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { + nsUpload.uploadEvent(it) + } + aapsLogger.debug(LTag.BGSOURCE, "Inserted calibration $it") + } }, { aapsLogger.error("Error while saving values from Dexcom App", it) ret = Result.failure() diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt index 81b929b4f9..df07f5a91a 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt +++ b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt @@ -74,9 +74,7 @@ open class DataReceiver : DaggerBroadcastReceiver() { .setInputData(dataWorker.storeInputData(bundle, intent)).build() Intents.ACTION_NEW_TREATMENT, Intents.ACTION_CHANGED_TREATMENT, - Intents.ACTION_REMOVED_TREATMENT, - Intents.ACTION_NEW_CAL, - Intents.ACTION_NEW_MBG -> + Intents.ACTION_REMOVED_TREATMENT -> OneTimeWorkRequest.Builder(NSClientWorker::class.java) .setInputData(dataWorker.storeInputData(bundle, intent)).build() else -> null diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSMbg.java b/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSMbg.java deleted file mode 100644 index 13cfb1e89d..0000000000 --- a/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSMbg.java +++ /dev/null @@ -1,41 +0,0 @@ -package info.nightscout.androidaps.plugins.general.nsclient.data; - -import org.json.JSONException; -import org.json.JSONObject; - -import javax.inject.Inject; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.logging.AAPSLogger; - -public class NSMbg { - @Inject public AAPSLogger aapsLogger; - - public long date; - public double mbg; - public String json; - - public NSMbg(HasAndroidInjector injector) { - injector.androidInjector().inject(this); - } - - public NSMbg(HasAndroidInjector injector, JSONObject json) { - this(injector); - try { - date = json.getLong("mills"); - mbg = json.getDouble("mgdl"); - this.json = json.toString(); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - aapsLogger.error("Data: " + json.toString()); - } - } - - public String id() { - try { - return new JSONObject(json).getString("_id"); - } catch (JSONException e) { - return null; - } - } -} diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSMbg.kt b/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSMbg.kt new file mode 100644 index 0000000000..c89aa23610 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSMbg.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.plugins.general.nsclient.data + +import info.nightscout.androidaps.utils.JsonHelper +import org.json.JSONObject + +class NSMbg(val json: JSONObject) { + + var date: Long = 0 + var mbg: Double = 0.0 + + init { + date = JsonHelper.safeGetLong(json, "mills") + mbg = JsonHelper.safeGetDouble(json, "mgdl") + } + + fun id(): String? = JsonHelper.safeGetStringAllowNull(json, "_id", null) + fun isValid(): Boolean = date != 0L && mbg != 0.0 +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/CgmSourceTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/CgmSourceTransaction.kt index d4eebb3f18..0aebab6c6a 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/transactions/CgmSourceTransaction.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/CgmSourceTransaction.kt @@ -54,21 +54,25 @@ class CgmSourceTransaction( } calibrations.forEach { if (database.therapyEventDao.findByTimestamp(TherapyEvent.Type.FINGER_STICK_BG_VALUE, it.timestamp) == null) { - database.therapyEventDao.insertNewEntry(TherapyEvent( - timestamp = it.timestamp, - type = TherapyEvent.Type.FINGER_STICK_BG_VALUE, - glucose = it.value, - glucoseUnit = it.glucoseUnit - )) + val therapyEvent = TherapyEvent( + timestamp = it.timestamp, + type = TherapyEvent.Type.FINGER_STICK_BG_VALUE, + glucose = it.value, + glucoseUnit = it.glucoseUnit + ) + database.therapyEventDao.insertNewEntry(therapyEvent) + result.calibrationsInserted.add(therapyEvent) } } sensorInsertionTime?.let { if (database.therapyEventDao.findByTimestamp(TherapyEvent.Type.SENSOR_CHANGE, it) == null) { - database.therapyEventDao.insertNewEntry(TherapyEvent( + val therapyEvent = TherapyEvent( timestamp = it, type = TherapyEvent.Type.SENSOR_CHANGE, glucoseUnit = TherapyEvent.GlucoseUnit.MGDL - )) + ) + database.therapyEventDao.insertNewEntry(therapyEvent) + result.sensorInsertionsInserted.add(therapyEvent) } } return result @@ -95,6 +99,9 @@ class CgmSourceTransaction( val inserted = mutableListOf() val updated = mutableListOf() + val calibrationsInserted = mutableListOf() + val sensorInsertionsInserted = mutableListOf() + fun all(): MutableList = mutableListOf().also { result -> result.addAll(inserted) From 415729f2433895aaecab3fe0cd2a73b2931a4143 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Sat, 20 Mar 2021 20:31:44 +0100 Subject: [PATCH 5/9] bypass Intents on NS received data --- .../info/nightscout/androidaps/MainApp.kt | 8 - .../androidaps/db/DatabaseHelper.java | 6 +- .../androidaps/db/DatabaseHelperProvider.java | 6 +- .../dependencyInjection/WorkersModule.kt | 6 +- .../nsclient/NSClientAddUpdateWorker.kt | 178 ++++++++++++++++++ .../general/nsclient/NSClientMbgWorker.kt | 10 + .../general/nsclient/NSClientPlugin.java | 147 +-------------- .../general/nsclient/NSClientRemoveWorker.kt | 111 +++++++++++ .../general/nsclient/NSClientWorker.java | 37 ---- .../general/nsclient/data/NSTreatment.java | 127 ------------- .../nsclient/services/NSClientService.java | 116 +++++------- .../plugins/source/NSClientSourcePlugin.kt | 5 +- .../androidaps/receivers/DataReceiver.kt | 6 - .../interfaces/DatabaseHelperInterface.kt | 3 +- .../nightscout/androidaps/utils/JsonHelper.kt | 3 +- 15 files changed, 361 insertions(+), 408 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddUpdateWorker.kt create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientRemoveWorker.kt delete mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientWorker.java delete mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/data/NSTreatment.java diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.kt b/app/src/main/java/info/nightscout/androidaps/MainApp.kt index 0c30ec765b..4851452333 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.kt @@ -5,7 +5,6 @@ import android.content.Intent import android.content.IntentFilter import android.net.ConnectivityManager import android.net.wifi.WifiManager -import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.j256.ormlite.android.apptools.OpenHelperManager import dagger.android.AndroidInjector import dagger.android.DaggerApplication @@ -24,11 +23,9 @@ import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionChec import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.receivers.BTReceiver import info.nightscout.androidaps.receivers.ChargingStateReceiver -import info.nightscout.androidaps.receivers.DataReceiver import info.nightscout.androidaps.receivers.KeepAliveReceiver.KeepAliveManager import info.nightscout.androidaps.receivers.NetworkChangeReceiver import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver -import info.nightscout.androidaps.services.Intents import info.nightscout.androidaps.utils.ActivityMonitor import info.nightscout.androidaps.utils.locale.LocaleHelper.update import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -102,11 +99,6 @@ class MainApp : DaggerApplication() { private fun registerLocalBroadcastReceiver() { var filter = IntentFilter() - filter.addAction(Intents.ACTION_NEW_TREATMENT) - filter.addAction(Intents.ACTION_CHANGED_TREATMENT) - filter.addAction(Intents.ACTION_REMOVED_TREATMENT) - LocalBroadcastManager.getInstance(this).registerReceiver(DataReceiver(), filter) - filter = IntentFilter() filter.addAction(Intent.ACTION_TIME_CHANGED) filter.addAction(Intent.ACTION_TIMEZONE_CHANGED) registerReceiver(TimeDateOrTZChangeReceiver(), filter) diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java index c041297f57..3e4f21c330 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -67,6 +67,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { @Inject RxBusWrapper rxBus; @Inject VirtualPumpPlugin virtualPumpPlugin; @Inject OpenHumansUploader openHumansUploader; + @Inject ActivePluginProvider activePlugin; + @Inject NSUpload nsUpload; public static final String DATABASE_NAME = "AndroidAPSDb"; public static final String DATABASE_EXTENDEDBOLUSES = "ExtendedBoluses"; @@ -1216,7 +1218,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { } */ - public void createProfileSwitchFromJsonIfNotExists(ActivePluginProvider activePluginProvider, NSUpload nsUpload, JSONObject trJson) { + public void createProfileSwitchFromJsonIfNotExists(JSONObject trJson) { try { ProfileSwitch profileSwitch = new ProfileSwitch(StaticInjector.Companion.getInstance()); profileSwitch.date = trJson.getLong("mills"); @@ -1233,7 +1235,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { if (trJson.has("profileJson")) profileSwitch.profileJson = trJson.getString("profileJson"); else { - ProfileInterface profileInterface = activePluginProvider.getActiveProfileInterface(); + ProfileInterface profileInterface = activePlugin.getActiveProfileInterface(); ProfileStore store = profileInterface.getProfile(); if (store != null) { Profile profile = store.getSpecificProfile(profileSwitch.profileName); diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java index 845772ab98..6587fb6371 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelperProvider.java @@ -14,9 +14,7 @@ import javax.inject.Inject; import javax.inject.Singleton; import info.nightscout.androidaps.MainApp; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; @Singleton public class DatabaseHelperProvider implements DatabaseHelperInterface { @@ -172,8 +170,8 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface { MainApp.Companion.getDbHelper().createExtendedBolusFromJsonIfNotExists(json); } - @Override public void createProfileSwitchFromJsonIfNotExists(@NonNull ActivePluginProvider activePluginProvider, @NonNull NSUpload nsUpload, @NonNull JSONObject trJson) { - MainApp.Companion.getDbHelper().createProfileSwitchFromJsonIfNotExists(activePluginProvider, nsUpload, trJson); + @Override public void createProfileSwitchFromJsonIfNotExists(@NonNull JSONObject trJson) { + MainApp.Companion.getDbHelper().createProfileSwitchFromJsonIfNotExists(trJson); } @Override public void resetDatabases() { diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt index 272ba15d03..a46b6b5264 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/WorkersModule.kt @@ -3,8 +3,9 @@ package info.nightscout.androidaps.dependencyInjection import dagger.Module import dagger.android.ContributesAndroidInjector import info.nightscout.androidaps.plugins.general.food.FoodPlugin +import info.nightscout.androidaps.plugins.general.nsclient.NSClientAddUpdateWorker import info.nightscout.androidaps.plugins.general.nsclient.NSClientMbgWorker -import info.nightscout.androidaps.plugins.general.nsclient.NSClientWorker +import info.nightscout.androidaps.plugins.general.nsclient.NSClientRemoveWorker import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin import info.nightscout.androidaps.plugins.source.* @@ -23,7 +24,8 @@ abstract class WorkersModule { @ContributesAndroidInjector abstract fun contributesNSClientSourceWorker(): NSClientSourcePlugin.NSClientSourceWorker @ContributesAndroidInjector abstract fun contributesNSProfileWorker(): NSProfilePlugin.NSProfileWorker @ContributesAndroidInjector abstract fun contributesSmsCommunicatorWorker(): SmsCommunicatorPlugin.SmsCommunicatorWorker - @ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientWorker + @ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientAddUpdateWorker + @ContributesAndroidInjector abstract fun contributesNSClientRemoveWorker(): NSClientRemoveWorker @ContributesAndroidInjector abstract fun contributesNSClientMbgWorker(): NSClientMbgWorker @ContributesAndroidInjector abstract fun contributesFoodWorker(): FoodPlugin.FoodWorker } \ 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..868993ddc8 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientAddUpdateWorker.kt @@ -0,0 +1,178 @@ +package info.nightscout.androidaps.plugins.general.nsclient + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import dagger.android.HasAndroidInjector +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 +import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit +import info.nightscout.androidaps.database.transactions.SyncTemporaryTargetTransaction +import info.nightscout.androidaps.database.transactions.SyncTherapyEventTransaction +import info.nightscout.androidaps.events.EventNsTreatment +import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.interfaces.DatabaseHelperInterface +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.extensions.temporaryTargetFromJson +import info.nightscout.androidaps.utils.extensions.therapyEventFromJson +import info.nightscout.androidaps.utils.sharedPreferences.SP +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: ConfigInterface + @Inject lateinit var repository: AppRepository + @Inject lateinit var databaseHelper: DatabaseHelperInterface + @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.failure() + + val treatments = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) + ?: return Result.failure() + + var ret = Result.success() + var latestDateInReceivedData = 0L + + for (i in 0 until treatments.length()) { + val 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.DATASERVICE, "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 + + when { + insulin > 0 || carbs > 0 -> + rxBus.send(EventNsTreatment(EventNsTreatment.ADD, json)) + eventType == TherapyEvent.Type.TEMPORARY_TARGET.text -> + temporaryTargetFromJson(json)?.let { temporaryTarget -> + repository.runTransactionForResult(SyncTemporaryTargetTransaction(temporaryTarget)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) + ret = Result.failure() + } + .blockingGet() + .also { result -> + result.inserted.forEach { + uel.log(UserEntry.Action.TT_FROM_NS, + ValueWithUnit(it.reason.text, UserEntry.Units.TherapyEvent), + ValueWithUnit(it.lowTarget, UserEntry.Units.Mg_Dl, true), + ValueWithUnit(it.highTarget, UserEntry.Units.Mg_Dl, it.lowTarget != it.highTarget), + ValueWithUnit(it.duration.toInt() / 60000, UserEntry.Units.M, true) + ) + } + result.invalidated.forEach { + uel.log(UserEntry.Action.TT_DELETED_FROM_NS, + ValueWithUnit(it.reason.text, UserEntry.Units.TherapyEvent), + ValueWithUnit(it.lowTarget, UserEntry.Units.Mg_Dl, true), + ValueWithUnit(it.highTarget, UserEntry.Units.Mg_Dl, it.lowTarget != it.highTarget), + ValueWithUnit(it.duration.toInt() / 60000, UserEntry.Units.M, true) + ) + } + result.ended.forEach { + uel.log(UserEntry.Action.TT_CANCELED_FROM_NS, + ValueWithUnit(it.reason.text, UserEntry.Units.TherapyEvent), + ValueWithUnit(it.lowTarget, UserEntry.Units.Mg_Dl, true), + ValueWithUnit(it.highTarget, UserEntry.Units.Mg_Dl, it.lowTarget != it.highTarget), + ValueWithUnit(it.duration.toInt() / 60000, UserEntry.Units.M, true) + ) + } + } + } ?: 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.NOTE.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(SyncTherapyEventTransaction(therapyEvent)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) + ret = Result.failure() + } + .blockingGet() + .also { result -> + result.inserted.forEach { + uel.log(UserEntry.Action.CAREPORTAL_FROM_NS, + it.note ?: "", + ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), + ValueWithUnit(it.type.text, UserEntry.Units.TherapyEvent) + ) + } + result.invalidated.forEach { + uel.log(UserEntry.Action.CAREPORTAL_DELETED_FROM_NS, + it.note ?: "", + ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), + ValueWithUnit(it.type.text, UserEntry.Units.TherapyEvent) + ) + } + } + } ?: aapsLogger.error("Error parsing TherapyEvent json $json") + eventType == TherapyEvent.Type.TEMPORARY_BASAL.text -> + databaseHelper.createTempBasalFromJsonIfNotExists(json) + eventType == TherapyEvent.Type.COMBO_BOLUS.text -> + databaseHelper.createExtendedBolusFromJsonIfNotExists(json) + eventType == TherapyEvent.Type.PROFILE_SWITCH.text -> + databaseHelper.createProfileSwitchFromJsonIfNotExists(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/NSClientMbgWorker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientMbgWorker.kt index de25ce9320..7c05af0fc8 100644 --- 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 @@ -4,13 +4,17 @@ import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.transactions.SyncTherapyEventTransaction +import info.nightscout.androidaps.interfaces.ConfigInterface 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.utils.extensions.therapyEventFromNsMbg +import info.nightscout.androidaps.utils.sharedPreferences.SP import javax.inject.Inject class NSClientMbgWorker( @@ -21,10 +25,16 @@ class NSClientMbgWorker( @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: ConfigInterface 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() for (i in 0 until mbgArray.length()) { 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 e8806efb12..48257ee342 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 @@ -353,149 +353,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); - } - } - + public void updateLatestDateReceivedIfNewer(long latestReceived) { + if (latestReceived > nsClientService.latestDateInReceivedData) + nsClientService.latestDateInReceivedData = latestReceived; } - - private void handleRemovedTreatmentFromNS(JSONObject json) { - String _id = JsonHelper.safeGetString(json, "_id"); - if (_id == null) return; - // room Temporary target - TemporaryTarget temporaryTarget = temporaryTargetFromNsIdForInvalidating(_id); - disposable.add(repository.runTransactionForResult(new SyncTemporaryTargetTransaction(temporaryTarget)).subscribe( - result -> result.getInvalidated().forEach(record -> uel.log(Action.TT_DELETED_FROM_NS, new ValueWithUnit(record.getReason().getText(), Units.TherapyEvent), new ValueWithUnit(record.getLowTarget(), Units.Mg_Dl, true), new ValueWithUnit(record.getHighTarget(), Units.Mg_Dl, record.getLowTarget() != record.getHighTarget()), new ValueWithUnit((int) record.getDuration()/60000, Units.M, record.getDuration() != 0))), - error -> aapsLogger.error(LTag.DATABASE, "Error while removing temporary target", error))); - // room Therapy Event - TherapyEvent therapyEvent = therapyEventFromNsIdForInvalidating(_id); - disposable.add(repository.runTransactionForResult(new SyncTherapyEventTransaction(therapyEvent)).subscribe( - result -> result.getInvalidated().forEach(record -> uel.log(Action.CAREPORTAL_DELETED_FROM_NS, record.getNote() != null ? record.getNote() : "" , new ValueWithUnit(record.getTimestamp(), Units.Timestamp, true), new ValueWithUnit(record.getType().getText(), Units.TherapyEvent))), - error -> aapsLogger.error(LTag.DATABASE, "Error while removing therapy event", error))); - // new DB model - EventNsTreatment evtTreatment = new EventNsTreatment(EventNsTreatment.Companion.getREMOVE(), json); - rxBus.send(evtTreatment); - // old DB model - databaseHelper.deleteTempBasalById(_id); - databaseHelper.deleteExtendedBolusById(_id); - databaseHelper.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(TherapyEvent.Type.TEMPORARY_TARGET.getText())) { - TemporaryTarget temporaryTarget = temporaryTargetFromJson(json); - if (temporaryTarget != null) { - disposable.add(repository.runTransactionForResult(new SyncTemporaryTargetTransaction(temporaryTarget)) - .subscribe( - result -> { - result.getInserted().forEach(record -> uel.log(Action.TT_FROM_NS, new ValueWithUnit(record.getReason().getText(), Units.TherapyEvent), new ValueWithUnit(record.getLowTarget(), Units.Mg_Dl, true), new ValueWithUnit(record.getHighTarget(), Units.Mg_Dl, record.getLowTarget() != record.getHighTarget()), new ValueWithUnit((int) record.getDuration()/60000, Units.M, true))); - result.getInvalidated().forEach(record -> uel.log(Action.TT_DELETED_FROM_NS, new ValueWithUnit(record.getReason().getText(), Units.TherapyEvent), new ValueWithUnit(record.getLowTarget(), Units.Mg_Dl, true), new ValueWithUnit(record.getHighTarget(), Units.Mg_Dl, record.getLowTarget() != record.getHighTarget()), new ValueWithUnit((int) record.getDuration()/60000, Units.M, true))); - result.getEnded().forEach(record -> uel.log(Action.TT_CANCELED_FROM_NS, new ValueWithUnit(record.getReason().getText(), Units.TherapyEvent), new ValueWithUnit(record.getLowTarget(), Units.Mg_Dl, true), new ValueWithUnit(record.getHighTarget(), Units.Mg_Dl, record.getLowTarget() != record.getHighTarget()), new ValueWithUnit((int) record.getDuration()/60000, Units.M, true))); - }, - error -> aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", error))); - } else { - aapsLogger.error("Error parsing TT json " + json.toString()); - } - } else if (eventType.equals(TherapyEvent.Type.TEMPORARY_BASAL.getText())) { - databaseHelper.createTempBasalFromJsonIfNotExists(json); - } else if (eventType.equals(TherapyEvent.Type.COMBO_BOLUS.getText())) { - databaseHelper.createExtendedBolusFromJsonIfNotExists(json); - } else if (eventType.equals(TherapyEvent.Type.PROFILE_SWITCH.getText())) { - databaseHelper.createProfileSwitchFromJsonIfNotExists(activePlugin, nsUpload, json); - } else if (eventType.equals(TherapyEvent.Type.CANNULA_CHANGE.getText()) || - eventType.equals(TherapyEvent.Type.INSULIN_CHANGE.getText()) || - eventType.equals(TherapyEvent.Type.SENSOR_CHANGE.getText()) || - eventType.equals(TherapyEvent.Type.FINGER_STICK_BG_VALUE.getText()) || - eventType.equals(TherapyEvent.Type.NOTE.getText()) || - eventType.equals(TherapyEvent.Type.NONE.getText()) || - eventType.equals(TherapyEvent.Type.ANNOUNCEMENT.getText()) || - eventType.equals(TherapyEvent.Type.QUESTION.getText()) || - eventType.equals(TherapyEvent.Type.EXERCISE.getText()) || - eventType.equals(TherapyEvent.Type.APS_OFFLINE.getText()) || - eventType.equals(TherapyEvent.Type.PUMP_BATTERY_CHANGE.getText())) { - TherapyEvent therapyEvent = therapyEventFromJson(json); - if (therapyEvent != null) { - disposable.add(repository.runTransactionForResult(new SyncTherapyEventTransaction(therapyEvent)) - .subscribe( - result -> { - result.getInserted().forEach(record -> uel.log(Action.CAREPORTAL_FROM_NS, record.getNote() != null ? record.getNote() : "", new ValueWithUnit(record.getTimestamp(), Units.Timestamp, true), new ValueWithUnit(record.getType().getText(), Units.TherapyEvent))); - result.getInvalidated().forEach(record -> uel.log(Action.CAREPORTAL_DELETED_FROM_NS, record.getNote() != null ? record.getNote() : "" , new ValueWithUnit(record.getTimestamp(), Units.Timestamp, true), new ValueWithUnit(record.getType().getText(), Units.TherapyEvent))); - }, - error -> aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", error))); - } else { - aapsLogger.error("Error parsing TherapyEvent json " + json.toString()); - } - } - - if (eventType.equals(TherapyEvent.Type.ANNOUNCEMENT.getText())) { - 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.NS_ANNOUNCEMENT, notes, Notification.ANNOUNCEMENT, 60); - rxBus.send(new EventNewNotification(announcement)); - } - } - } - } - } 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..a80c71c803 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientRemoveWorker.kt @@ -0,0 +1,111 @@ +package info.nightscout.androidaps.plugins.general.nsclient + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.R +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.database.entities.UserEntry.ValueWithUnit +import info.nightscout.androidaps.database.transactions.SyncTemporaryTargetTransaction +import info.nightscout.androidaps.database.transactions.SyncTherapyEventTransaction +import info.nightscout.androidaps.events.EventNsTreatment +import info.nightscout.androidaps.events.EventNsTreatment.Companion.REMOVE +import info.nightscout.androidaps.interfaces.ConfigInterface +import info.nightscout.androidaps.interfaces.DatabaseHelperInterface +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.extensions.temporaryTargetFromNsIdForInvalidating +import info.nightscout.androidaps.utils.extensions.therapyEventFromNsIdForInvalidating +import info.nightscout.androidaps.utils.sharedPreferences.SP +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: ConfigInterface + @Inject lateinit var repository: AppRepository + @Inject lateinit var databaseHelper: DatabaseHelperInterface + @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.failure() + + var ret = Result.success() + + val treatments = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1)) + ?: return Result.failure() + + 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(SyncTemporaryTargetTransaction(temporaryTarget)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while removing temporary target", it) + ret = Result.failure() + } + .blockingGet() + .also { result -> + result.invalidated.forEach { + uel.log( + UserEntry.Action.TT_DELETED_FROM_NS, + ValueWithUnit(it.reason.text, UserEntry.Units.TherapyEvent), + ValueWithUnit(it.lowTarget, UserEntry.Units.Mg_Dl, true), + ValueWithUnit(it.highTarget, UserEntry.Units.Mg_Dl, it.lowTarget != it.highTarget), + ValueWithUnit(it.duration.toInt() / 60000, UserEntry.Units.M, it.duration != 0L) + ) + } + } + + // room Therapy Event + val therapyEvent = therapyEventFromNsIdForInvalidating(nsId) + repository.runTransactionForResult(SyncTherapyEventTransaction(therapyEvent)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while removing therapy event", it) + ret = Result.failure() + } + .blockingGet() + .also { result -> + result.invalidated.forEach { + uel.log( + UserEntry.Action.CAREPORTAL_DELETED_FROM_NS, (it.note ?: ""), + ValueWithUnit(it.timestamp, UserEntry.Units.Timestamp, true), + ValueWithUnit(it.type.text, UserEntry.Units.TherapyEvent)) + } + } + + // Insulin, carbs + rxBus.send(EventNsTreatment(REMOVE, json)) + // old DB model + databaseHelper.deleteTempBasalById(nsId) + databaseHelper.deleteExtendedBolusById(nsId) + databaseHelper.deleteProfileSwitchById(nsId) + } + + 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 3c97e00d95..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientWorker.java +++ /dev/null @@ -1,37 +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 javax.inject.Inject; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.receivers.DataWorker; - -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 DataWorker dataWorker; - - @NonNull - @Override - public Result doWork() { - Bundle bundle = dataWorker.pickupBundle(getInputData().getLong(DataWorker.STORE_KEY, -1)); - if (bundle == null) return Result.failure(); - String action = getInputData().getString(DataWorker.ACTION_KEY); - nsClientPlugin.handleNewDataFromNSClient(action, bundle); - return Result.success(); - } -} - 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 a4720d4e76..c873f25f1f 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 @@ -38,13 +38,14 @@ import info.nightscout.androidaps.events.EventConfigBuilderChange; import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.interfaces.DatabaseHelperInterface; import info.nightscout.androidaps.interfaces.PluginType; -import info.nightscout.androidaps.interfaces.ProfileStore; 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.NSClientAddUpdateWorker; import info.nightscout.androidaps.plugins.general.nsclient.NSClientMbgWorker; import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin; +import info.nightscout.androidaps.plugins.general.nsclient.NSClientRemoveWorker; import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue; import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAddAck; import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAuthAck; @@ -53,7 +54,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.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; @@ -568,38 +568,54 @@ public class NSClientService extends DaggerService { 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")) { @@ -848,54 +864,6 @@ public class NSClientService extends DaggerService { } } - 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/source/NSClientSourcePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt index ca6b3513d4..8b5fd45ed4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt @@ -16,6 +16,7 @@ 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.general.nsclient.NSClientPlugin import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification @@ -26,7 +27,6 @@ import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP -import org.json.JSONArray import org.json.JSONObject import javax.inject.Inject import javax.inject.Singleton @@ -91,6 +91,7 @@ class NSClientSourcePlugin @Inject constructor( @Inject lateinit var repository: AppRepository @Inject lateinit var broadcastToXDrip: XDripBroadcast @Inject lateinit var dexcomPlugin: DexcomPlugin + @Inject lateinit var nsClientPlugin: NSClientPlugin init { (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) @@ -135,6 +136,8 @@ class NSClientSourcePlugin @Inject constructor( rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM)) } + nsClientPlugin.updateLatestDateReceivedIfNewer(latestDateInReceivedData) + repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null, !nsClientSourcePlugin.isEnabled())) .doOnError { aapsLogger.error("Error while saving values from NSClient App", it) diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt index df07f5a91a..89a869837f 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt +++ b/app/src/main/java/info/nightscout/androidaps/receivers/DataReceiver.kt @@ -9,7 +9,6 @@ import dagger.android.DaggerBroadcastReceiver import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.BundleLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.general.nsclient.NSClientWorker import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.androidaps.plugins.source.* import info.nightscout.androidaps.services.Intents @@ -72,11 +71,6 @@ open class DataReceiver : DaggerBroadcastReceiver() { Intents.DEXCOM_BG -> OneTimeWorkRequest.Builder(DexcomPlugin.DexcomWorker::class.java) .setInputData(dataWorker.storeInputData(bundle, intent)).build() - Intents.ACTION_NEW_TREATMENT, - Intents.ACTION_CHANGED_TREATMENT, - Intents.ACTION_REMOVED_TREATMENT -> - OneTimeWorkRequest.Builder(NSClientWorker::class.java) - .setInputData(dataWorker.storeInputData(bundle, intent)).build() else -> null }?.let { request -> dataWorker.enqueue(request) } } diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt index f2bc1e4082..5864bd3754 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/DatabaseHelperInterface.kt @@ -2,7 +2,6 @@ package info.nightscout.androidaps.interfaces import com.j256.ormlite.dao.CloseableIterator import info.nightscout.androidaps.db.* -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import org.json.JSONObject interface DatabaseHelperInterface { @@ -54,7 +53,7 @@ interface DatabaseHelperInterface { fun deleteProfileSwitchById(_id: String) fun createTempBasalFromJsonIfNotExists(json: JSONObject) fun createExtendedBolusFromJsonIfNotExists(json: JSONObject) - fun createProfileSwitchFromJsonIfNotExists(activePluginProvider: ActivePluginProvider, nsUpload: NSUpload, trJson: JSONObject) + fun createProfileSwitchFromJsonIfNotExists(trJson: JSONObject) fun getInsightBolusID(pumpSerial: String, bolusID: Int, timestamp: Long): InsightBolusID? fun getInsightHistoryOffset(pumpSerial: String): InsightHistoryOffset? diff --git a/core/src/main/java/info/nightscout/androidaps/utils/JsonHelper.kt b/core/src/main/java/info/nightscout/androidaps/utils/JsonHelper.kt index f3105b755e..a7c78fa0bb 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/JsonHelper.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/JsonHelper.kt @@ -51,6 +51,7 @@ object JsonHelper { return result } + @JvmStatic fun safeGetStringAllowNull(json: JSONObject?, fieldName: String, defaultValue: String?): String? { var result = defaultValue if (json != null && json.has(fieldName)) { @@ -112,7 +113,7 @@ object JsonHelper { } fun safeGetIntAllowNull(json: JSONObject?, fieldName: String): Int? { - var result : Int? = null + var result: Int? = null if (json != null && json.has(fieldName)) { try { result = json.getInt(fieldName) From 69f8195bbe224f9f28cd301d876d1e4f3e6cc609 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Sat, 20 Mar 2021 23:17:05 +0100 Subject: [PATCH 6/9] 2.8.2.1-dev-e --- .idea/codeStyles/Project.xml | 16 ---------------- app/build.gradle | 2 +- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 3542887fac..ff53f4004f 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -2,22 +2,6 @@