commit
3d48636429
70 changed files with 4643 additions and 2057 deletions
|
@ -2,22 +2,6 @@
|
|||
<code_scheme name="Project" version="173">
|
||||
<option name="AUTODETECT_INDENTS" value="false" />
|
||||
<JetCodeStyleSettings>
|
||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||
<value>
|
||||
<package name="java.util" alias="false" withSubpackages="false" />
|
||||
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
||||
<package name="io.ktor" alias="false" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="PACKAGES_IMPORT_LAYOUT">
|
||||
<value>
|
||||
<package name="" alias="false" withSubpackages="true" />
|
||||
<package name="java" alias="false" withSubpackages="true" />
|
||||
<package name="javax" alias="false" withSubpackages="true" />
|
||||
<package name="kotlin" alias="false" withSubpackages="true" />
|
||||
<package name="" alias="true" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />
|
||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="6" />
|
||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="6" />
|
||||
|
|
|
@ -111,7 +111,7 @@ android {
|
|||
defaultConfig {
|
||||
multiDexEnabled true
|
||||
versionCode 1500
|
||||
version "2.8.2.1-dev-d"
|
||||
version "2.8.2.1-dev-e"
|
||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,15 +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)
|
||||
filter.addAction(Intents.ACTION_NEW_SGV)
|
||||
filter.addAction(Intents.ACTION_NEW_PROFILE)
|
||||
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)
|
||||
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED)
|
||||
registerReceiver(TimeDateOrTZChangeReceiver(), filter)
|
||||
|
|
|
@ -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<Food>().firstOrNull()?.let {
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventFoodDatabaseChanged")
|
||||
rxBus.send(EventFoodDatabaseChanged())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2,7 +2,10 @@ package info.nightscout.androidaps.dependencyInjection
|
|||
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientWorker
|
||||
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.NSClientRemoveWorker
|
||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
|
||||
import info.nightscout.androidaps.plugins.source.*
|
||||
|
@ -21,5 +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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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())
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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<CharSequence> = 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<CharSequence> = 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<Food>()
|
||||
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<Food>) : RecyclerView.Adapter<FoodsViewHolder>() {
|
||||
fun Int?.isNotZero(): Boolean = this != null && this != 0
|
||||
|
||||
inner class RecyclerViewAdapter internal constructor(private var foodList: List<Food>) : RecyclerView.Adapter<RecyclerViewAdapter.FoodsViewHolder>() {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,25 @@
|
|||
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.DataWorker
|
||||
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 org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -25,10 +38,76 @@ class FoodPlugin @Inject constructor(
|
|||
aapsLogger, resourceHelper, injector
|
||||
) {
|
||||
|
||||
var service: FoodService? = null
|
||||
// cannot be inner class because of needed injection
|
||||
class FoodWorker(
|
||||
context: Context,
|
||||
params: WorkerParameters
|
||||
) : Worker(context, params) {
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
service = FoodService(injector)
|
||||
@Inject lateinit var injector: HasAndroidInjector
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var dataWorker: DataWorker
|
||||
|
||||
init {
|
||||
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
||||
}
|
||||
|
||||
override fun doWork(): Result {
|
||||
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()
|
||||
|
||||
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") }
|
||||
|
||||
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) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<DatabaseHelper> {
|
||||
@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.
|
||||
* <p>
|
||||
* 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<Food, Long> 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.
|
||||
* <p>
|
||||
* We do need to make sure, that ICallback is extended to be able to handle multiple
|
||||
* events, or handle a list of events.
|
||||
* <p>
|
||||
* 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<Food> 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.
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* 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<Food> 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;
|
||||
}
|
||||
}
|
|
@ -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<List<UserEntry>>) {
|
||||
val entries = listEntries.blockingGet()
|
||||
override fun exportUserEntriesCsv(activity: FragmentActivity, singleEntries: Single<List<UserEntry>>) {
|
||||
val entries = singleEntries.blockingGet()
|
||||
prefFileList.ensureExportDirExists()
|
||||
val newFile = prefFileList.newExportXmlFile()
|
||||
//log.debug("XXXXX " + classicPrefsFormat.UserEntriesToCsv(entries))
|
||||
|
||||
try {
|
||||
classicPrefsFormat.saveCsv(newFile, entries)
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
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.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(
|
||||
context: Context,
|
||||
params: WorkerParameters
|
||||
) : Worker(context, params) {
|
||||
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var dataWorker: DataWorker
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var buildHelper: BuildHelper
|
||||
@Inject lateinit var config: 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()) {
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
@ -353,178 +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);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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() , 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() , 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)));
|
||||
},
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
);
|
||||
public void updateLatestDateReceivedIfNewer(long latestReceived) {
|
||||
if (latestReceived > nsClientService.latestDateInReceivedData)
|
||||
nsClientService.latestDateInReceivedData = latestReceived;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.nsclient;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.HasAndroidInjector;
|
||||
import info.nightscout.androidaps.receivers.BundleStore;
|
||||
import info.nightscout.androidaps.receivers.DataReceiver;
|
||||
|
||||
// cannot be inner class because of needed injection
|
||||
public class NSClientWorker extends Worker {
|
||||
|
||||
public NSClientWorker(
|
||||
@NonNull Context context,
|
||||
@NonNull WorkerParameters params) {
|
||||
super(context, params);
|
||||
((HasAndroidInjector) context.getApplicationContext()).androidInjector().inject(this);
|
||||
}
|
||||
|
||||
@Inject NSClientPlugin nsClientPlugin;
|
||||
@Inject BundleStore bundleStore;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
Bundle bundle = bundleStore.pickup(getInputData().getLong(DataReceiver.STORE_KEY, -1));
|
||||
if (bundle == null) return Result.failure();
|
||||
String action = getInputData().getString(DataReceiver.ACTION_KEY);
|
||||
nsClientPlugin.handleNewDataFromNSClient(action, bundle);
|
||||
return Result.success();
|
||||
}
|
||||
}
|
||||
|
|
@ -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("<span style=\"color:" + resourceHelper.gcs(R.color.defaulttext) + "\">");
|
||||
string.append(resourceHelper.gs(R.string.pump));
|
||||
string.append(": </span>");
|
||||
|
||||
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("<span style=\"color:");
|
||||
if (level == Levels.INFO) string.append("white\">");
|
||||
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("</span>"); // 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("<b>").append(key).append(":</b> ").append(value).append("<br>");
|
||||
}
|
||||
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("<span style=\"color:" + resourceHelper.gcs(R.color.defaulttext) + "\">");
|
||||
string.append(resourceHelper.gs(R.string.openaps_short));
|
||||
string.append(": </span>");
|
||||
|
||||
// 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("<span style=\"color:");
|
||||
if (level == Levels.INFO) string.append("white\">");
|
||||
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("</span>"); // 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("<b>").append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockEnacted)).append("</b> ").append(deviceStatusOpenAPSData.enacted.getString("reason")).append("<br>");
|
||||
if (deviceStatusOpenAPSData.suggested != null)
|
||||
string.append("<b>").append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append("</b> ").append(deviceStatusOpenAPSData.suggested.getString("reason")).append("<br>");
|
||||
return HtmlHelper.INSTANCE.fromHtml(string.toString());
|
||||
} catch (JSONException e) {
|
||||
aapsLogger.error("Unhandled exception", e);
|
||||
}
|
||||
return HtmlHelper.INSTANCE.fromHtml("");
|
||||
}
|
||||
|
||||
// ********* Uploader data ***********
|
||||
|
||||
private static final HashMap<String, Uploader> 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("<span style=\"color:" + resourceHelper.gcs(R.color.defaulttext) + "\">");
|
||||
string.append(resourceHelper.gs(R.string.uploader_short));
|
||||
string.append(": </span>");
|
||||
|
||||
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("<b>").append(device).append(":</b> ").append(uploader.battery).append("%<br>");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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("<span style=\"color:${resourceHelper.gcs(R.color.defaulttext)}\">")
|
||||
.append(resourceHelper.gs(R.string.pump))
|
||||
.append(": </span>")
|
||||
|
||||
// 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("<span style=\"color:${level.toColor()}\">")
|
||||
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("</span>") // 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("<b>").append(key).append(":</b> ").append(value).append("<br>")
|
||||
}
|
||||
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("<span style=\"color:${resourceHelper.gcs(R.color.defaulttext)}\">")
|
||||
.append(resourceHelper.gs(R.string.openaps_short))
|
||||
.append(": </span>")
|
||||
|
||||
// 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("<span style=\"color:${level.toColor()}\">")
|
||||
if (deviceStatusOpenAPSData.clockSuggested != 0L) string.append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append(" ")
|
||||
string.append("</span>") // color
|
||||
return fromHtml(string.toString())
|
||||
}
|
||||
|
||||
val extendedOpenApsStatus: Spanned
|
||||
get() {
|
||||
val string = StringBuilder()
|
||||
try {
|
||||
if (deviceStatusOpenAPSData.enacted != null && deviceStatusOpenAPSData.clockEnacted != deviceStatusOpenAPSData.clockSuggested) string.append("<b>").append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockEnacted)).append("</b> ").append(deviceStatusOpenAPSData.enacted!!.getString("reason")).append("<br>")
|
||||
if (deviceStatusOpenAPSData.suggested != null) string.append("<b>").append(DateUtil.minAgo(resourceHelper, deviceStatusOpenAPSData.clockSuggested)).append("</b> ").append(deviceStatusOpenAPSData.suggested!!.getString("reason")).append("<br>")
|
||||
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("<span style=\"color:${resourceHelper.gcs(R.color.defaulttext)}\">")
|
||||
string.append(resourceHelper.gs(R.string.uploader_short))
|
||||
string.append(": </span>")
|
||||
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("<b>").append(device).append(":</b> ").append(uploader.battery).append("%<br>")
|
||||
}
|
||||
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<String, Uploader>()
|
||||
|
||||
fun getAPSResult(injector: HasAndroidInjector): APSResult {
|
||||
val result = APSResult(injector)
|
||||
result.json = deviceStatusOpenAPSData.suggested
|
||||
result.date = deviceStatusOpenAPSData.clockSuggested
|
||||
return result
|
||||
}
|
||||
}
|
|
@ -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", "")
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
@ -34,16 +35,18 @@ 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;
|
||||
import info.nightscout.androidaps.interfaces.ProfileStore;
|
||||
import info.nightscout.androidaps.interfaces.UploadQueueInterface;
|
||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||
import info.nightscout.androidaps.plugins.general.food.FoodPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.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.acks.NSAddAck;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSAuthAck;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.acks.NSUpdateAck;
|
||||
|
@ -51,8 +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.NSSgv;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSTreatment;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus;
|
||||
|
@ -61,6 +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;
|
||||
|
@ -91,14 +95,13 @@ public class NSClientService extends DaggerService {
|
|||
@Inject Config config;
|
||||
@Inject DateUtil dateUtil;
|
||||
@Inject UploadQueueInterface uploadQueue;
|
||||
@Inject DataWorker dataWorker;
|
||||
|
||||
private final CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
static public PowerManager.WakeLock mWakeLock;
|
||||
private final IBinder mBinder = new NSClientService.LocalBinder();
|
||||
|
||||
static ProfileStore profileStore;
|
||||
|
||||
static public Handler handler;
|
||||
|
||||
public static Socket mSocket;
|
||||
|
@ -108,9 +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 = "";
|
||||
|
@ -535,185 +535,142 @@ public class NSClientService extends DaggerService {
|
|||
boolean isFull = !isDelta;
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "Data packet #" + dataCounter++ + (isDelta ? " delta" : " full")));
|
||||
|
||||
if (data.has("profiles")) {
|
||||
JSONArray profiles = data.getJSONArray("profiles");
|
||||
if (profiles.length() > 0) {
|
||||
JSONObject profile = (JSONObject) profiles.get(profiles.length() - 1);
|
||||
profileStore = new ProfileStore(injector, profile);
|
||||
broadcastProfile = true;
|
||||
rxBus.send(new EventNSClientNewLog("PROFILE", "profile received"));
|
||||
}
|
||||
}
|
||||
|
||||
if (data.has("status")) {
|
||||
JSONObject status = data.getJSONObject("status");
|
||||
nsSettingsStatus.setData(status);
|
||||
|
||||
if (!status.has("versionNum")) {
|
||||
if (status.getInt("versionNum") < config.getSUPPORTEDNSVERSION()) {
|
||||
rxBus.send(new EventNSClientNewLog("ERROR", "Unsupported Nightscout version !!!!"));
|
||||
}
|
||||
} else {
|
||||
nightscoutVersionName = nsSettingsStatus.getVersion();
|
||||
nightscoutVersionCode = nsSettingsStatus.getVersionNum();
|
||||
}
|
||||
nsSettingsStatus.handleNewData(nightscoutVersionName, nightscoutVersionCode, status);
|
||||
|
||||
/* Other received data to 2016/02/10
|
||||
{
|
||||
status: 'ok'
|
||||
, name: env.name
|
||||
, version: env.version
|
||||
, versionNum: versionNum (for ver 1.2.3 contains 10203)
|
||||
, serverTime: new Date().toISOString()
|
||||
, apiEnabled: apiEnabled
|
||||
, careportalEnabled: apiEnabled && env.settings.enable.indexOf('careportal') > -1
|
||||
, boluscalcEnabled: apiEnabled && env.settings.enable.indexOf('boluscalc') > -1
|
||||
, head: env.head
|
||||
, settings: env.settings
|
||||
, extendedSettings: ctx.plugins && ctx.plugins.extendedClientSettings ? ctx.plugins.extendedClientSettings(env.extendedSettings) : {}
|
||||
, activeProfile ..... calculated from treatments or missing
|
||||
}
|
||||
*/
|
||||
nsSettingsStatus.handleNewData(status);
|
||||
} else if (!isDelta) {
|
||||
rxBus.send(new EventNSClientNewLog("ERROR", "Unsupported Nightscout version !!!!"));
|
||||
}
|
||||
|
||||
// If new profile received or change detected broadcast it
|
||||
if (broadcastProfile && profileStore != null) {
|
||||
handleNewProfile(profileStore, isDelta);
|
||||
rxBus.send(new EventNSClientNewLog("PROFILE", "broadcasting"));
|
||||
if (data.has("profiles")) {
|
||||
JSONArray profiles = data.getJSONArray("profiles");
|
||||
if (profiles.length() > 0) {
|
||||
// take the newest
|
||||
JSONObject profileStoreJson = (JSONObject) profiles.get(profiles.length() - 1);
|
||||
rxBus.send(new EventNSClientNewLog("PROFILE", "profile received"));
|
||||
dataWorker.enqueue(
|
||||
new OneTimeWorkRequest.Builder(NSProfilePlugin.NSProfileWorker.class)
|
||||
.setInputData(dataWorker.storeInputData(profileStoreJson, null))
|
||||
.build());
|
||||
|
||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("profile", profileStoreJson.toString());
|
||||
bundle.putBoolean("delta", isDelta);
|
||||
Intent intent = new Intent(Intents.ACTION_NEW_PROFILE);
|
||||
intent.putExtras(bundle);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.has("treatments")) {
|
||||
JSONArray treatments = data.getJSONArray("treatments");
|
||||
JSONArray removedTreatments = new JSONArray();
|
||||
JSONArray updatedTreatments = new JSONArray();
|
||||
JSONArray addedTreatments = new JSONArray();
|
||||
JSONArray addedOrUpdatedTreatments = new JSONArray();
|
||||
if (treatments.length() > 0)
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "received " + treatments.length() + " treatments"));
|
||||
for (Integer index = 0; index < treatments.length(); index++) {
|
||||
JSONObject jsonTreatment = treatments.getJSONObject(index);
|
||||
NSTreatment treatment = new NSTreatment(jsonTreatment);
|
||||
String action = JsonHelper.safeGetStringAllowNull(jsonTreatment, "action", null);
|
||||
long mills = JsonHelper.safeGetLong(jsonTreatment, "mills");
|
||||
|
||||
// remove from upload queue if Ack is failing
|
||||
uploadQueue.removeByNsClientIdIfExists(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
|
||||
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 (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<JSONArray> 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 (updatedTreatments.length() > 0) {
|
||||
handleChangedTreatment(updatedTreatments, isDelta);
|
||||
}
|
||||
if (addedTreatments.length() > 0) {
|
||||
handleNewTreatment(addedTreatments, isDelta);
|
||||
}
|
||||
}
|
||||
if (data.has("devicestatus")) {
|
||||
JSONArray devicestatuses = data.getJSONArray("devicestatus");
|
||||
if (devicestatuses.length() > 0) {
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "received " + devicestatuses.length() + " device statuses"));
|
||||
for (Integer index = 0; index < devicestatuses.length(); index++) {
|
||||
JSONObject jsonStatus = devicestatuses.getJSONObject(index);
|
||||
// remove from upload queue if Ack is failing
|
||||
uploadQueue.removeByNsClientIdIfExists(jsonStatus);
|
||||
}
|
||||
nsDeviceStatus.handleNewData(devicestatuses);
|
||||
}
|
||||
}
|
||||
if (data.has("food")) {
|
||||
JSONArray foods = data.getJSONArray("food");
|
||||
JSONArray removedFoods = new JSONArray();
|
||||
JSONArray updatedFoods = new JSONArray();
|
||||
JSONArray addedFoods = new JSONArray();
|
||||
if (foods.length() > 0)
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "received " + foods.length() + " foods"));
|
||||
for (Integer index = 0; index < foods.length(); index++) {
|
||||
JSONObject jsonFood = foods.getJSONObject(index);
|
||||
|
||||
// remove from upload queue if Ack is failing
|
||||
uploadQueue.removeByNsClientIdIfExists(jsonFood);
|
||||
|
||||
String action = JsonHelper.safeGetString(jsonFood, "action");
|
||||
|
||||
if (action == null) {
|
||||
addedFoods.put(jsonFood);
|
||||
} else if (action.equals("update")) {
|
||||
updatedFoods.put(jsonFood);
|
||||
} else if (action.equals("remove")) {
|
||||
removedFoods.put(jsonFood);
|
||||
}
|
||||
}
|
||||
if (removedFoods.length() > 0) {
|
||||
EventNsFood evt = new EventNsFood(EventNsFood.Companion.getREMOVE(), removedFoods);
|
||||
rxBus.send(evt);
|
||||
}
|
||||
if (updatedFoods.length() > 0) {
|
||||
EventNsFood evt = new EventNsFood(EventNsFood.Companion.getUPDATE(), updatedFoods);
|
||||
rxBus.send(evt);
|
||||
}
|
||||
if (addedFoods.length() > 0) {
|
||||
EventNsFood evt = new EventNsFood(EventNsFood.Companion.getADD(), addedFoods);
|
||||
rxBus.send(evt);
|
||||
}
|
||||
dataWorker.enqueue(
|
||||
new OneTimeWorkRequest.Builder(FoodPlugin.FoodWorker.class)
|
||||
.setInputData(dataWorker.storeInputData(foods, null))
|
||||
.build());
|
||||
}
|
||||
//noinspection SpellCheckingInspection
|
||||
if (data.has("mbgs")) {
|
||||
JSONArray mbgs = data.getJSONArray("mbgs");
|
||||
if (mbgs.length() > 0)
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "received " + mbgs.length() + " mbgs"));
|
||||
for (Integer index = 0; index < mbgs.length(); index++) {
|
||||
JSONObject jsonMbg = mbgs.getJSONObject(index);
|
||||
// remove from upload queue if Ack is failing
|
||||
uploadQueue.removeByNsClientIdIfExists(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.removeByNsClientIdIfExists(cals.optJSONObject(index));
|
||||
}
|
||||
handleNewCal(cals, isDelta);
|
||||
// Calibrations ignored
|
||||
}
|
||||
if (data.has("sgvs")) {
|
||||
JSONArray sgvs = data.getJSONArray("sgvs");
|
||||
if (sgvs.length() > 0)
|
||||
rxBus.send(new EventNSClientNewLog("DATA", "received " + sgvs.length() + " sgvs"));
|
||||
for (int index = 0; index < sgvs.length(); index++) {
|
||||
JSONObject jsonSgv = sgvs.getJSONObject(index);
|
||||
// rxBus.send(new EventNSClientNewLog("DATA", "svg " + sgvs.getJSONObject(index).toString());
|
||||
NSSgv sgv = new NSSgv(jsonSgv);
|
||||
// Handle new sgv here
|
||||
// remove from upload queue if Ack is failing
|
||||
uploadQueue.removeByNsClientIdIfExists(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<JSONArray> 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) {
|
||||
|
@ -881,71 +838,6 @@ public class NSClientService extends DaggerService {
|
|||
}
|
||||
}
|
||||
|
||||
public void handleNewCal(JSONArray cals, boolean isDelta) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("cals", cals.toString());
|
||||
bundle.putBoolean("delta", isDelta);
|
||||
Intent intent = new Intent(Intents.ACTION_NEW_CAL);
|
||||
intent.putExtras(bundle);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
|
||||
}
|
||||
|
||||
public void handleNewMbg(JSONArray mbgs, boolean isDelta) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("mbgs", mbgs.toString());
|
||||
bundle.putBoolean("delta", isDelta);
|
||||
Intent intent = new Intent(Intents.ACTION_NEW_MBG);
|
||||
intent.putExtras(bundle);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
|
||||
}
|
||||
|
||||
public void handleNewProfile(ProfileStore profile, boolean isDelta) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("profile", profile.getData().toString());
|
||||
bundle.putBoolean("delta", isDelta);
|
||||
Intent intent = new Intent(Intents.ACTION_NEW_PROFILE);
|
||||
intent.putExtras(bundle);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
|
||||
|
||||
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
|
||||
bundle = new Bundle();
|
||||
bundle.putString("profile", profile.getData().toString());
|
||||
bundle.putBoolean("delta", isDelta);
|
||||
intent = new Intent(Intents.ACTION_NEW_PROFILE);
|
||||
intent.putExtras(bundle);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
this.sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleNewSgv(JSONArray sgvs, boolean isDelta) {
|
||||
List<JSONArray> 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<JSONArray> splitted = splitArray(treatments);
|
||||
for (JSONArray part : splitted) {
|
||||
|
@ -972,54 +864,6 @@ public class NSClientService extends DaggerService {
|
|||
}
|
||||
}
|
||||
|
||||
public void handleChangedTreatment(JSONArray treatments, boolean isDelta) {
|
||||
List<JSONArray> 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<JSONArray> splitArray(JSONArray array) {
|
||||
List<JSONArray> ret = new ArrayList<>();
|
||||
try {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<*>
|
||||
|
@ -758,9 +757,11 @@ 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))
|
||||
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))
|
||||
} else {
|
||||
var replyText = resourceHelper.gs(R.string.smscommunicator_extendedfailed)
|
||||
replyText += "\n" + activePlugin.activePump.shortStatus(true)
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,17 +88,16 @@ 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.profile = ProfileStore(injector, profileString)
|
||||
nsProfilePlugin.storeNSProfile()
|
||||
if (nsProfilePlugin.isEnabled()) {
|
||||
rxBus.send(EventProfileStoreChanged())
|
||||
|
@ -108,7 +106,5 @@ class NSProfilePlugin @Inject constructor(
|
|||
aapsLogger.debug(LTag.PROFILE, "Received profileStore: ${nsProfilePlugin.profile}")
|
||||
return Result.success()
|
||||
}
|
||||
return Result.failure()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
|
@ -93,8 +92,10 @@ 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))
|
||||
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.STORE_KEY, -1))
|
||||
?: return Result.failure()
|
||||
try {
|
||||
val sourceSensor = when (bundle.getString("sensorType") ?: "") {
|
||||
|
@ -142,23 +143,37 @@ 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")
|
||||
}
|
||||
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()
|
||||
})
|
||||
} catch (e: Exception) {
|
||||
aapsLogger.error("Error while processing intent from Dexcom App", e)
|
||||
ret = Result.failure()
|
||||
}
|
||||
return Result.success()
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -18,14 +17,11 @@ 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
|
||||
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 +44,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,
|
||||
|
@ -67,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
|
||||
|
||||
|
@ -76,8 +65,10 @@ 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))
|
||||
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"))
|
||||
|
@ -116,15 +107,20 @@ class EversensePlugin @Inject constructor(
|
|||
trendArrow = GlucoseValue.TrendArrow.NONE,
|
||||
sourceSensor = GlucoseValue.SourceSensor.EVERSENSE
|
||||
)
|
||||
eversensePlugin.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.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 +132,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) }
|
||||
}, {
|
||||
))
|
||||
.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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<CgmSourceTransaction.TransactionGlucoseValue>()
|
||||
|
@ -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 ->
|
||||
repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null))
|
||||
.doOnError {
|
||||
aapsLogger.error("Error while saving values from Glimp 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.GLIMP.text)
|
||||
aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it")
|
||||
}
|
||||
}, {
|
||||
aapsLogger.error("Error while saving values from Glimp App", it)
|
||||
})
|
||||
return Result.success()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,13 +15,11 @@ 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
|
||||
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,
|
||||
|
@ -60,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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,16 +15,18 @@ 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.NSClientPlugin
|
||||
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
|
||||
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
|
||||
|
@ -55,13 +57,6 @@ class NSClientSourcePlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
override fun onStop() {
|
||||
disposable.clear()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun advancedFilteringSupported(): Boolean {
|
||||
return isAdvancedFilteringEnabled
|
||||
}
|
||||
|
@ -89,12 +84,14 @@ 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
|
||||
@Inject lateinit var nsClientPlugin: NSClientPlugin
|
||||
|
||||
init {
|
||||
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
||||
|
@ -113,41 +110,59 @@ 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()
|
||||
|
||||
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<CgmSourceTransaction.TransactionGlucoseValue>()
|
||||
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))
|
||||
}
|
||||
nsClientSourcePlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null, !nsClientSourcePlugin.isEnabled())).subscribe({ result ->
|
||||
|
||||
nsClientPlugin.updateLatestDateReceivedIfNewer(latestDateInReceivedData)
|
||||
|
||||
repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null, !nsClientSourcePlugin.isEnabled()))
|
||||
.doOnError {
|
||||
aapsLogger.error("Error while saving values from NSClient App", it)
|
||||
ret = Result.failure()
|
||||
}
|
||||
.blockingGet()
|
||||
.also { result ->
|
||||
result.updated.forEach {
|
||||
//aapsLogger.debug("XXXXX: Updated $it")
|
||||
broadcastToXDrip(it)
|
||||
nsClientSourcePlugin.detectSource(it)
|
||||
aapsLogger.debug(LTag.BGSOURCE, "Updated bg $it")
|
||||
}
|
||||
result.inserted.forEach {
|
||||
//aapsLogger.debug("XXXXX: Inserted $it")
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ->
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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<CgmSourceTransaction.TransactionGlucoseValue>()
|
||||
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 ->
|
||||
repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null))
|
||||
.doOnError {
|
||||
aapsLogger.error("Error while saving values from Tomato 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.LIBRE_1_TOMATO.text)
|
||||
aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it")
|
||||
}
|
||||
}, {
|
||||
aapsLogger.error("Error while saving values from Tomato App", it)
|
||||
})
|
||||
return Result.success()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,12 +14,9 @@ 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 io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -55,33 +52,29 @@ 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
|
||||
@Inject lateinit var dataWorker: DataWorker
|
||||
|
||||
init {
|
||||
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
||||
}
|
||||
|
||||
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))
|
||||
val bundle = dataWorker.pickupBundle(inputData.getLong(DataWorker.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<CgmSourceTransaction.TransactionGlucoseValue>()
|
||||
glucoseValues += CgmSourceTransaction.TransactionGlucoseValue(
|
||||
timestamp = bundle.getLong(Intents.EXTRA_TIMESTAMP, 0),
|
||||
|
@ -92,15 +85,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 ->
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Long, Bundle>()
|
||||
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
|
||||
}
|
||||
}
|
|
@ -2,34 +2,26 @@ 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.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
|
||||
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() {
|
||||
|
||||
@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 +32,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 +46,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,32 +64,15 @@ 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_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"
|
||||
}
|
||||
}
|
|
@ -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<Long, Any>()
|
||||
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"
|
||||
}
|
||||
|
||||
}
|
|
@ -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"
|
||||
|
@ -14,7 +14,7 @@ interface Intents {
|
|||
const val ACTION_NEW_MBG = "info.nightscout.client.NEW_MBG"
|
||||
const val ACTION_NEW_CAL = "info.nightscout.client.NEW_CAL"
|
||||
|
||||
// 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"
|
||||
|
|
|
@ -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">
|
||||
|
||||
<info.nightscout.androidaps.utils.ui.SingleClickButton
|
||||
android:id="@+id/refresh_from_nightscout"
|
||||
style="?android:attr/buttonStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:drawableStart="@drawable/ic_refresh"
|
||||
android:text="@string/refresheventsfromnightscout"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -48,6 +58,7 @@
|
|||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:text="@string/category" />
|
||||
|
||||
<Spinner
|
||||
|
@ -65,6 +76,7 @@
|
|||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:text="@string/subcategory" />
|
||||
|
||||
<Spinner
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
card_view:cardBackgroundColor="@color/cardColorBackground"
|
||||
card_view:cardCornerRadius="6dp"
|
||||
card_view:cardUseCompatPadding="true"
|
||||
card_view:contentPadding="6dp">
|
||||
card_view:cardBackgroundColor="?android:colorBackground">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -26,21 +24,24 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Name"
|
||||
android:textStyle="bold" />
|
||||
android:textStyle="bold"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/portion"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:text="Portion" />
|
||||
android:text="Portion"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/carbs"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:text="Carbs" />
|
||||
android:text="Carbs"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -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" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/protein"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:text="Protein" />
|
||||
android:text="Protein"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/energy"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:text="Energy" />
|
||||
android:text="Energy"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ns_sign"
|
||||
|
@ -79,7 +83,8 @@
|
|||
android:width="30dp"
|
||||
android:text="NS"
|
||||
android:textAlignment="viewEnd"
|
||||
android:textColor="@color/colorSetTempButton" />
|
||||
android:textColor="@color/colorSetTempButton"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/remove"
|
||||
|
@ -93,6 +98,15 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:background="@color/list_delimiter" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
|
|
@ -317,7 +317,7 @@
|
|||
<string name="openapsma_autosensdata_label">Autosens data</string>
|
||||
<string name="openapsma_scriptdebugdata_label">Script debug</string>
|
||||
<string name="openapsama_useautosens">Use Autosens feature</string>
|
||||
<string name="refresheventsfromnightscout">Refresh events from NS</string>
|
||||
<string name="refresheventsfromnightscout">Refresh from NS</string>
|
||||
<string name="deletefuturetreatments">Delete treatments in the future</string>
|
||||
<string name="actions_shortname">ACT</string>
|
||||
<string name="configbuilder_shortname">CONF</string>
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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<List<UserEntry>>)
|
||||
fun exportUserEntriesCsv(activity: FragmentActivity, singleEntries: Single<List<UserEntry>>)
|
||||
}
|
|
@ -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"),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)) {
|
||||
|
@ -77,7 +75,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 +86,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 +101,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 +112,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
|
||||
|
|
|
@ -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
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
||||
}
|
|
@ -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<List<Food>> =
|
||||
database.foodDao.getFoodData()
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
||||
fun deleteAllFoods() =
|
||||
database.foodDao.deleteAllEntries()
|
||||
|
||||
}
|
||||
|
||||
@Suppress("USELESS_CAST")
|
||||
|
|
|
@ -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 )")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,5 +24,6 @@ internal class DelegatedAppDatabase(val changes: MutableList<DBEntry>, 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()
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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<Food> {
|
||||
|
||||
@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<List<Food>>
|
||||
|
||||
}
|
|
@ -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<T : TraceableDBEntry> : TraceableDaoWorkaround<T> {
|
||||
|
||||
|
|
|
@ -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<DBEntry>, 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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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),
|
||||
|
|
|
@ -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(
|
||||
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<GlucoseValue>()
|
||||
val updated = mutableListOf<GlucoseValue>()
|
||||
|
||||
val calibrationsInserted = mutableListOf<TherapyEvent>()
|
||||
val sensorInsertionsInserted = mutableListOf<TherapyEvent>()
|
||||
|
||||
fun all(): MutableList<GlucoseValue> =
|
||||
mutableListOf<GlucoseValue>().also { result ->
|
||||
result.addAll(inserted)
|
||||
|
|
|
@ -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<InsertOrUpdateFoodTransaction.TransactionResult>() {
|
||||
|
||||
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<Food>()
|
||||
val updated = mutableListOf<Food>()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package info.nightscout.androidaps.database.transactions
|
||||
|
||||
class InvalidateFoodTransaction(val id: Long) : Transaction<Unit>() {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -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<SyncFoodTransaction.TransactionResult>() {
|
||||
|
||||
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<Food>()
|
||||
val inserted = mutableListOf<Food>()
|
||||
val invalidated = mutableListOf<Food>()
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue