diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt index 971799653c..88b1f2d717 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/DataSyncSelectorImplementation.kt @@ -1,11 +1,10 @@ package info.nightscout.androidaps.plugins.general.nsclient -import androidx.work.ListenableWorker import info.nightscout.androidaps.R import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.database.transactions.UpdateTemporaryTargetTransaction -import info.nightscout.androidaps.db.DbRequest +import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.DataSyncSelector import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.logging.AAPSLogger @@ -21,23 +20,13 @@ class DataSyncSelectorImplementation @Inject constructor( private val dateUtil: DateUtil, private val profileFunction: ProfileFunction, private val nsClientPlugin: NSClientPlugin, + private val activePlugin: ActivePluginProvider, private val appRepository: AppRepository ) : DataSyncSelector { - /* - val updateTempTargetNsId = Runnable { - interfaceIDs.nightscoutId = nsId - repository.runTransactionForResult(UpdateTemporaryTargetTransaction(this)) - .doOnError { - aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it) - ret = ListenableWorker.Result.failure() - } - .blockingGet() - } - */ - override fun resetToNextFullSync() { sp.remove(R.string.key_ns_temporary_target_last_sync) + sp.remove(R.string.key_ns_glucose_value_last_sync) } override fun confirmTempTargetsTimestamp(lastSynced: Long) { @@ -46,37 +35,80 @@ class DataSyncSelectorImplementation @Inject constructor( } override fun confirmTempTargetsTimestampIfGreater(lastSynced: Long) { - aapsLogger.debug(LTag.NSCLIENT, "Setting TT data sync from $lastSynced") - if (lastSynced > sp.getLong(R.string.key_ns_temporary_target_last_sync, 0)) { - aapsLogger.debug(LTag.NSCLIENT, ">>> Setting TT data sync from $lastSynced") - sp.putLong(R.string.key_ns_temporary_target_last_sync, lastSynced) - } + if (lastSynced > sp.getLong(R.string.key_ns_temporary_target_last_sync, 0)) + confirmTempTargetsTimestamp(lastSynced) } + // Prepared for v3 (returns all modified after) override fun changedTempTargets(): List { - val startTime = sp.getLong(R.string.key_ns_temporary_target_last_sync, 0) - return appRepository.getAllChangedTemporaryTargetsFromTime(startTime, 1).blockingGet().also { - aapsLogger.debug(LTag.NSCLIENT, "Loading TT data for sync from $startTime ${dateUtil.dateAndTimeAndSecondsString(startTime)}. Records ${it.size}") + val startId = sp.getLong(R.string.key_ns_temporary_target_last_sync, 0) + return appRepository.getModifiedTemporaryTargetsDataFromId(startId).blockingGet().also { + aapsLogger.debug(LTag.NSCLIENT, "Loading TT data for sync from $startId. Records ${it.size}") } } override fun processChangedTempTargetsCompat(): Boolean { - val changedTT = changedTempTargets() - changedTT.forEach { tt -> + val startId = sp.getLong(R.string.key_ns_temporary_target_last_sync, 0) + appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt -> + aapsLogger.info(LTag.DATABASE, "Loading TemporaryTarget data Start: $startId ID: ${tt.first.id} HistoryID: ${tt.second} ") when { // removed and not uploaded yet = ignore - !tt.isValid && tt.interfaceIDs.nightscoutId == null -> Any() + !tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> Any() // removed and already uploaded = send for removal - !tt.isValid && tt.interfaceIDs.nightscoutId != null -> - nsClientPlugin.nsClientService?.dbRemove("treatments", tt.interfaceIDs.nightscoutId, tt) + !tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbRemove("treatments", tt.first.interfaceIDs.nightscoutId, DataSyncSelector.PairTemporaryTarget(tt.first, tt.second)) // existing without nsId = create new - tt.isValid && tt.interfaceIDs.nightscoutId == null -> - nsClientPlugin.nsClientService?.dbAdd("treatments", tt.toJson(profileFunction.getUnits()), tt) + tt.first.isValid && tt.first.interfaceIDs.nightscoutId == null -> + nsClientPlugin.nsClientService?.dbAdd("treatments", tt.first.toJson(profileFunction.getUnits()), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second)) // existing with nsId = update - tt.isValid && tt.interfaceIDs.nightscoutId != null -> - nsClientPlugin.nsClientService?.dbUpdate("treatments", tt.interfaceIDs.nightscoutId, tt.toJson(profileFunction.getUnits()), tt) + tt.first.isValid && tt.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbUpdate("treatments", tt.first.interfaceIDs.nightscoutId, tt.first.toJson(profileFunction.getUnits()), DataSyncSelector.PairTemporaryTarget(tt.first, tt.second)) + } + return true + } + return false + } + + override fun confirmLastGlucoseValueId(lastSynced: Long) { + aapsLogger.debug(LTag.NSCLIENT, "Setting GlucoseValue data sync from $lastSynced") + sp.putLong(R.string.key_ns_glucose_value_last_sync, lastSynced) + } + + override fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) { + if (lastSynced > sp.getLong(R.string.key_ns_glucose_value_last_sync, 0)) + confirmLastGlucoseValueId(lastSynced) + } + + // Prepared for v3 (returns all modified after) + override fun changedGlucoseValues(): List { + val startId = sp.getLong(R.string.key_ns_glucose_value_last_sync, 0) + return appRepository.getModifiedBgReadingsDataFromId(startId).blockingGet().also { + aapsLogger.debug(LTag.NSCLIENT, "Loading GlucoseValue data for sync from $startId . Records ${it.size}") + } + } + + override fun processChangedGlucoseValuesCompat(): Boolean { + val startId = sp.getLong(R.string.key_ns_glucose_value_last_sync, 0) + appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv -> + aapsLogger.info(LTag.DATABASE, "Loading GlucoseValue data Start: $startId ID: ${gv.first.id} HistoryID: ${gv.second} ") + if (activePlugin.activeBgSource.uploadToNs(gv.first)) { + when { + // removed and not uploaded yet = ignore + !gv.first.isValid && gv.first.interfaceIDs.nightscoutId == null -> Any() + // removed and already uploaded = send for removal + !gv.first.isValid && gv.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbRemove("entries", gv.first.interfaceIDs.nightscoutId, DataSyncSelector.PairGlucoseValue(gv.first, gv.second)) + // existing without nsId = create new + gv.first.isValid && gv.first.interfaceIDs.nightscoutId == null -> + nsClientPlugin.nsClientService?.dbAdd("entries", gv.first.toJson(), DataSyncSelector.PairGlucoseValue(gv.first, gv.second)) + // existing with nsId = update + gv.first.isValid && gv.first.interfaceIDs.nightscoutId != null -> + nsClientPlugin.nsClientService?.dbUpdate("entries", gv.first.interfaceIDs.nightscoutId, gv.first.toJson(), DataSyncSelector.PairGlucoseValue(gv.first, gv.second)) + } + return true } } - return changedTT.isNotEmpty() + return false } -} \ No newline at end of file + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java deleted file mode 100644 index 333c510309..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.java +++ /dev/null @@ -1,171 +0,0 @@ -package info.nightscout.androidaps.plugins.general.nsclient; - - -import android.graphics.Paint; -import android.os.Bundle; -import android.text.Spanned; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.ScrollView; -import android.widget.TextView; - -import javax.inject.Inject; - -import dagger.android.support.DaggerFragment; -import info.nightscout.androidaps.R; -import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface; -import info.nightscout.androidaps.database.entities.UserEntry; -import info.nightscout.androidaps.database.entities.UserEntry.*; -import info.nightscout.androidaps.logging.UserEntryLogger; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog; -import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart; -import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI; -import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.utils.HtmlHelper; -import info.nightscout.androidaps.utils.alertDialogs.OKDialog; -import info.nightscout.androidaps.utils.resources.ResourceHelper; -import info.nightscout.androidaps.utils.rx.AapsSchedulers; -import info.nightscout.androidaps.utils.sharedPreferences.SP; -import io.reactivex.disposables.CompositeDisposable; - -public class NSClientFragment extends DaggerFragment implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { - @Inject NSClientPlugin nsClientPlugin; - @Inject SP sp; - @Inject ResourceHelper resourceHelper; - @Inject RxBusWrapper rxBus; - @Inject UploadQueueAdminInterface uploadQueue; - @Inject FabricPrivacy fabricPrivacy; - @Inject AapsSchedulers aapsSchedulers; - @Inject UserEntryLogger uel; - - private final CompositeDisposable disposable = new CompositeDisposable(); - - private TextView logTextView; - private TextView queueTextView; - private TextView urlTextView; - private TextView statusTextView; - private TextView clearlog; - private TextView restart; - private TextView delivernow; - private TextView clearqueue; - private TextView showqueue; - private ScrollView logScrollview; - private CheckBox autoscrollCheckbox; - private CheckBox pausedCheckbox; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.nsclientinternal_fragment, container, false); - - logScrollview = view.findViewById(R.id.nsclientinternal_logscrollview); - autoscrollCheckbox = view.findViewById(R.id.nsclientinternal_autoscroll); - autoscrollCheckbox.setChecked(nsClientPlugin.autoscroll); - autoscrollCheckbox.setOnCheckedChangeListener(this); - pausedCheckbox = view.findViewById(R.id.nsclientinternal_paused); - pausedCheckbox.setChecked(nsClientPlugin.paused); - pausedCheckbox.setOnCheckedChangeListener(this); - logTextView = view.findViewById(R.id.nsclientinternal_log); - queueTextView = view.findViewById(R.id.nsclientinternal_queue); - urlTextView = view.findViewById(R.id.nsclientinternal_url); - statusTextView = view.findViewById(R.id.nsclientinternal_status); - - clearlog = view.findViewById(R.id.nsclientinternal_clearlog); - clearlog.setOnClickListener(this); - clearlog.setPaintFlags(clearlog.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); - restart = view.findViewById(R.id.nsclientinternal_restart); - restart.setOnClickListener(this); - restart.setPaintFlags(restart.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); - delivernow = view.findViewById(R.id.nsclientinternal_delivernow); - delivernow.setOnClickListener(this); - delivernow.setPaintFlags(delivernow.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); - clearqueue = view.findViewById(R.id.nsclientinternal_clearqueue); - clearqueue.setOnClickListener(this); - clearqueue.setPaintFlags(clearqueue.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); - showqueue = view.findViewById(R.id.nsclientinternal_showqueue); - showqueue.setOnClickListener(this); - showqueue.setPaintFlags(showqueue.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); - - return view; - } - - @Override - public synchronized void onResume() { - super.onResume(); - disposable.add(rxBus - .toObservable(EventNSClientUpdateGUI.class) - .observeOn(aapsSchedulers.getMain()) - .subscribe(event -> updateGui(), fabricPrivacy::logException) - ); - updateGui(); - } - - @Override - public synchronized void onPause() { - super.onPause(); - disposable.clear(); - } - - @Override - public void onClick(View view) { - switch (view.getId()) { - case R.id.nsclientinternal_restart: - rxBus.send(new EventNSClientRestart()); - fabricPrivacy.logCustom("NSClientRestart"); - break; - case R.id.nsclientinternal_delivernow: - nsClientPlugin.resend("GUI"); - fabricPrivacy.logCustom("NSClientDeliverNow"); - break; - case R.id.nsclientinternal_clearlog: - nsClientPlugin.clearLog(); - break; - case R.id.nsclientinternal_clearqueue: - OKDialog.showConfirmation(getContext(), resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), () -> { - uel.log(Action.NS_QUEUE_CLEARED); - uploadQueue.clearQueue(); - updateGui(); - fabricPrivacy.logCustom("NSClientClearQueue"); - }); - break; - case R.id.nsclientinternal_showqueue: - rxBus.send(new EventNSClientNewLog("QUEUE", uploadQueue.textList())); - break; - } - } - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - switch (buttonView.getId()) { - case R.id.nsclientinternal_paused: - uel.log(isChecked ? Action.NS_PAUSED : Action.NS_RESUME); - nsClientPlugin.pause(isChecked); - updateGui(); - fabricPrivacy.logCustom("NSClientPause"); - break; - case R.id.nsclientinternal_autoscroll: - sp.putBoolean(R.string.key_nsclientinternal_autoscroll, isChecked); - nsClientPlugin.autoscroll = isChecked; - updateGui(); - break; - } - } - - protected void updateGui() { - nsClientPlugin.updateLog(); - pausedCheckbox.setChecked(sp.getBoolean(R.string.key_nsclientinternal_paused, false)); - logTextView.setText(nsClientPlugin.textLog); - if (nsClientPlugin.autoscroll) { - logScrollview.fullScroll(ScrollView.FOCUS_DOWN); - } - urlTextView.setText(nsClientPlugin.url()); - Spanned queuetext = HtmlHelper.INSTANCE.fromHtml(resourceHelper.gs(R.string.queue) + " " + uploadQueue.size() + ""); - queueTextView.setText(queuetext); - statusTextView.setText(nsClientPlugin.status); - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt new file mode 100644 index 0000000000..973a84d7c8 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSClientFragment.kt @@ -0,0 +1,121 @@ +package info.nightscout.androidaps.plugins.general.nsclient + +import android.graphics.Paint +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ScrollView +import dagger.android.support.DaggerFragment +import info.nightscout.androidaps.R +import info.nightscout.androidaps.database.entities.UserEntry +import info.nightscout.androidaps.databinding.NsClientFragmentBinding +import info.nightscout.androidaps.interfaces.DataSyncSelector +import info.nightscout.androidaps.interfaces.UploadQueueAdminInterface +import info.nightscout.androidaps.logging.UserEntryLogger +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog +import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart +import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.HtmlHelper.fromHtml +import info.nightscout.androidaps.utils.alertDialogs.OKDialog +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.androidaps.utils.sharedPreferences.SP +import io.reactivex.disposables.CompositeDisposable +import javax.inject.Inject + +class NSClientFragment : DaggerFragment() { + + @Inject lateinit var nsClientPlugin: NSClientPlugin + @Inject lateinit var sp: SP + @Inject lateinit var resourceHelper: ResourceHelper + @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var uploadQueue: UploadQueueAdminInterface + @Inject lateinit var fabricPrivacy: FabricPrivacy + @Inject lateinit var aapsSchedulers: AapsSchedulers + @Inject lateinit var dataSyncSelector: DataSyncSelector + @Inject lateinit var uel: UserEntryLogger + + private val disposable = CompositeDisposable() + + private var _binding: NsClientFragmentBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = + NsClientFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.autoscroll.isChecked = nsClientPlugin.autoscroll + binding.autoscroll.setOnCheckedChangeListener { _, isChecked -> + sp.putBoolean(R.string.key_nsclientinternal_autoscroll, isChecked) + nsClientPlugin.autoscroll = isChecked + updateGui() + } + + binding.paused.isChecked = nsClientPlugin.paused + binding.paused.setOnCheckedChangeListener { _, isChecked -> + uel.log(if (isChecked) UserEntry.Action.NS_PAUSED else UserEntry.Action.NS_RESUME) + nsClientPlugin.pause(isChecked) + updateGui() + } + binding.clearLog.setOnClickListener { nsClientPlugin.clearLog() } + binding.clearLog.paintFlags = binding.clearLog.paintFlags or Paint.UNDERLINE_TEXT_FLAG + binding.restart.setOnClickListener { rxBus.send(EventNSClientRestart()) } + binding.restart.paintFlags = binding.restart.paintFlags or Paint.UNDERLINE_TEXT_FLAG + binding.deliverNow.setOnClickListener { nsClientPlugin.resend("GUI") } + binding.deliverNow.paintFlags = binding.deliverNow.paintFlags or Paint.UNDERLINE_TEXT_FLAG + binding.clearQueue.setOnClickListener { + context?.let { context -> + OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.clearqueueconfirm), Runnable { + uel.log(UserEntry.Action.NS_QUEUE_CLEARED) + uploadQueue.clearQueue() + updateGui() + }) + } + } + binding.clearQueue.paintFlags = binding.clearQueue.paintFlags or Paint.UNDERLINE_TEXT_FLAG + binding.showQueue.setOnClickListener { rxBus.send(EventNSClientNewLog("QUEUE", uploadQueue.textList())) } + binding.showQueue.paintFlags = binding.showQueue.paintFlags or Paint.UNDERLINE_TEXT_FLAG + binding.fullSync.setOnClickListener { + context?.let { context -> + OKDialog.showConfirmation(context, resourceHelper.gs(R.string.nsclientinternal), resourceHelper.gs(R.string.full_sync), Runnable { + dataSyncSelector.resetToNextFullSync() + }) + } + } + binding.fullSync.paintFlags = binding.fullSync.paintFlags or Paint.UNDERLINE_TEXT_FLAG + } + + @Synchronized override fun onResume() { + super.onResume() + disposable.add(rxBus + .toObservable(EventNSClientUpdateGUI::class.java) + .observeOn(aapsSchedulers.main) + .subscribe({ updateGui() }, fabricPrivacy::logException) + ) + updateGui() + } + + @Synchronized override fun onPause() { + super.onPause() + disposable.clear() + } + + private fun updateGui() { + if (_binding == null) return + nsClientPlugin.updateLog() + binding.paused.isChecked = sp.getBoolean(R.string.key_nsclientinternal_paused, false) + binding.log.text = nsClientPlugin.textLog + if (nsClientPlugin.autoscroll) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN) + binding.url.text = nsClientPlugin.url() + binding.queue.text = fromHtml(resourceHelper.gs(R.string.queue) + " " + uploadQueue.size() + "") + binding.status.text = nsClientPlugin.status + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java index de9d721c61..be99727db1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/services/NSClientService.java @@ -32,7 +32,7 @@ import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.Config; import info.nightscout.androidaps.R; import info.nightscout.androidaps.database.AppRepository; -import info.nightscout.androidaps.database.entities.TemporaryTarget; +import info.nightscout.androidaps.database.transactions.UpdateNsIdGlucoseValueTransaction; import info.nightscout.androidaps.database.transactions.UpdateNsIdTemporaryTargetTransaction; import info.nightscout.androidaps.db.DbRequest; import info.nightscout.androidaps.events.EventAppExit; @@ -123,6 +123,7 @@ public class NSClientService extends DaggerService { private final Integer nsHours = 48; public long lastResendTime = 0; + public long lastAckTime = 0; public long latestDateInReceivedData = 0; @@ -218,19 +219,38 @@ public class NSClientService extends DaggerService { } public void processAddAck(NSAddAck ack) { + lastAckTime = dateUtil._now(); // new room way - if (ack.getOriginalObject() instanceof TemporaryTarget) { - ((TemporaryTarget) ack.getOriginalObject()).getInterfaceIDs().setNightscoutId(ack.getId()); + if (ack.getOriginalObject() instanceof DataSyncSelector.PairTemporaryTarget) { + DataSyncSelector.PairTemporaryTarget pair = (DataSyncSelector.PairTemporaryTarget) ack.getOriginalObject(); + pair.getValue().getInterfaceIDs().setNightscoutId(ack.getId()); - disposable.add(repository.runTransactionForResult(new UpdateNsIdTemporaryTargetTransaction((TemporaryTarget) ack.getOriginalObject())) + disposable.add(repository.runTransactionForResult(new UpdateNsIdTemporaryTargetTransaction((pair.getValue()))) .observeOn(aapsSchedulers.getIo()) .subscribe( - result -> aapsLogger.debug(LTag.DATABASE, "Updated ns id of temporary target $originalObject"), + result -> aapsLogger.debug(LTag.DATABASE, "Updated ns id of temporary target " + pair.getValue()), error -> aapsLogger.error(LTag.DATABASE, "Updated ns id of temporary target failed") )); - dataSyncSelector.confirmTempTargetsTimestampIfGreater(((TemporaryTarget) ack.getOriginalObject()).getDateCreated()); - rxBus.send(new EventNSClientNewLog("DBADD", "Acked " + ack.nsClientID)); - resend("AddAck"); + dataSyncSelector.confirmTempTargetsTimestampIfGreater(pair.getUpdateRecordId()); + rxBus.send(new EventNSClientNewLog("DBADD", "Acked " + pair.getValue().getInterfaceIDs().getNightscoutId())); + // Send new if waiting + dataSyncSelector.processChangedTempTargetsCompat(); + return; + } + if (ack.getOriginalObject() instanceof DataSyncSelector.PairGlucoseValue) { + DataSyncSelector.PairGlucoseValue pair = (DataSyncSelector.PairGlucoseValue) ack.getOriginalObject(); + pair.getValue().getInterfaceIDs().setNightscoutId(ack.getId()); + + disposable.add(repository.runTransactionForResult(new UpdateNsIdGlucoseValueTransaction(pair.getValue())) + .observeOn(aapsSchedulers.getIo()) + .subscribe( + result -> aapsLogger.debug(LTag.DATABASE, "Updated ns id of glucose value " + pair.getValue()), + error -> aapsLogger.error(LTag.DATABASE, "Updated ns id of glucose value failed", error) + )); + dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.getUpdateRecordId()); + rxBus.send(new EventNSClientNewLog("DBADD", "Acked " + pair.getValue().getInterfaceIDs().getNightscoutId())); + // Send new if waiting + dataSyncSelector.processChangedGlucoseValuesCompat(); return; } // old way @@ -243,11 +263,22 @@ public class NSClientService extends DaggerService { } public void processUpdateAck(NSUpdateAck ack) { + lastAckTime = dateUtil._now(); // new room way - if (ack.getOriginalObject() instanceof TemporaryTarget) { - dataSyncSelector.confirmTempTargetsTimestampIfGreater(((TemporaryTarget) ack.getOriginalObject()).getDateCreated()); + if (ack.getOriginalObject() instanceof DataSyncSelector.PairTemporaryTarget) { + DataSyncSelector.PairTemporaryTarget pair = (DataSyncSelector.PairTemporaryTarget) ack.getOriginalObject(); + dataSyncSelector.confirmTempTargetsTimestampIfGreater(pair.getUpdateRecordId()); rxBus.send(new EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked " + ack.get_id())); - resend("UpdateAck"); + // Send new if waiting + dataSyncSelector.processChangedTempTargetsCompat(); + return; + } + if (ack.getOriginalObject() instanceof DataSyncSelector.PairGlucoseValue) { + DataSyncSelector.PairGlucoseValue pair = (DataSyncSelector.PairGlucoseValue) ack.getOriginalObject(); + dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.getUpdateRecordId()); + rxBus.send(new EventNSClientNewLog("DBUPDATE/DBREMOVE", "Acked " + ack.get_id())); + // Send new if waiting + dataSyncSelector.processChangedGlucoseValuesCompat(); return; } // old way @@ -736,7 +767,7 @@ public class NSClientService extends DaggerService { message.put("_id", _id); message.put("data", data); mSocket.emit("dbUpdate", message, new NSUpdateAck("dbUpdate", _id, aapsLogger, rxBus, originalObject)); - rxBus.send(new EventNSClientNewLog("DBUPDATE " + collection, "Sent " + originalObject.toString())); + rxBus.send(new EventNSClientNewLog("DBUPDATE " + collection, "Sent " + _id)); } catch (JSONException e) { aapsLogger.error("Unhandled exception", e); } @@ -788,7 +819,7 @@ public class NSClientService extends DaggerService { message.put("collection", collection); message.put("data", data); mSocket.emit("dbAdd", message, new NSAddAck(aapsLogger, rxBus, originalObject)); - rxBus.send(new EventNSClientNewLog("DBADD " + collection, "Sent " + originalObject.toString())); + rxBus.send(new EventNSClientNewLog("DBADD " + collection, "Sent " + data)); } catch (JSONException e) { aapsLogger.error("Unhandled exception", e); } @@ -806,20 +837,24 @@ public class NSClientService extends DaggerService { handler.post(() -> { if (mSocket == null || !mSocket.connected()) return; -// for room db I send record by record . this would make the process slow -// if (lastResendTime > System.currentTimeMillis() - 10 * 1000L) { -// aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastResendTime: " + ((System.currentTimeMillis() - lastResendTime) / 1000L) + " sec"); -// return; -// } - lastResendTime = System.currentTimeMillis(); - rxBus.send(new EventNSClientNewLog("QUEUE", "Resend started: " + reason)); + if (lastAckTime > System.currentTimeMillis() - 10 * 1000L) { + aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastAckTime: " + ((System.currentTimeMillis() - lastAckTime) / 1000L) + " sec"); + return; + } + if (dataSyncSelector.processChangedGlucoseValuesCompat()) return; if (dataSyncSelector.processChangedTempTargetsCompat()) return; if (uploadQueue.size() == 0) return; + if (lastResendTime > System.currentTimeMillis() - 10 * 1000L) { + aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastResendTime: " + ((System.currentTimeMillis() - lastResendTime) / 1000L) + " sec"); + return; + } + lastResendTime = System.currentTimeMillis(); + CloseableIterator iterator; int maxcount = 30; try { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt index 71a2a0ce65..98b1bad39c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/DexcomPlugin.kt @@ -37,6 +37,7 @@ class DexcomPlugin @Inject constructor( injector: HasAndroidInjector, resourceHelper: ResourceHelper, aapsLogger: AAPSLogger, + private val sp: SP, private val dexcomMediator: DexcomMediator, config: Config ) : PluginBase(PluginDescription() @@ -50,8 +51,6 @@ class DexcomPlugin @Inject constructor( aapsLogger, resourceHelper, injector ), BgSourceInterface { - private val disposable = CompositeDisposable() - init { if (!config.NSCLIENT) { pluginDescription.setDefault() @@ -62,13 +61,18 @@ class DexcomPlugin @Inject constructor( return true } + override fun uploadToNs(glucoseValue: GlucoseValue): Boolean = + (glucoseValue.sourceSensor == GlucoseValue.SourceSensor.DEXCOM_G6_NATIVE || + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.DEXCOM_G5_NATIVE || + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.DEXCOM_NATIVE_UNKNOWN) + && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + override fun onStart() { super.onStart() dexcomMediator.requestPermissionIfNeeded() } override fun onStop() { - disposable.clear() super.onStop() } @@ -138,37 +142,34 @@ class DexcomPlugin @Inject constructor( } else { null } - dexcomPlugin.disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, calibrations, sensorStartTime)).subscribe({ result -> - result.inserted.forEach { - broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { - nsUpload.uploadBg(it, sourceSensor.text) - } - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, calibrations, sensorStartTime)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while saving values from Dexcom App", it) + ret = Result.failure() } - result.updated.forEach { - broadcastToXDrip(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { - nsUpload.updateBg(it, sourceSensor.text) + .blockingGet() + .also { result -> + result.inserted.forEach { + broadcastToXDrip(it) + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") } - aapsLogger.debug(LTag.BGSOURCE, "Updated bg $it") - } - result.sensorInsertionsInserted.forEach { - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { - nsUpload.uploadEvent(it) + result.updated.forEach { + broadcastToXDrip(it) + aapsLogger.debug(LTag.DATABASE, "Updated bg $it") } - aapsLogger.debug(LTag.BGSOURCE, "Inserted sensor insertion $it") - } - result.calibrationsInserted.forEach { - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { - nsUpload.uploadEvent(it) + result.sensorInsertionsInserted.forEach { + if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { + nsUpload.uploadEvent(it) + } + aapsLogger.debug(LTag.DATABASE, "Inserted sensor insertion $it") + } + result.calibrationsInserted.forEach { + if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) { + nsUpload.uploadEvent(it) + } + aapsLogger.debug(LTag.DATABASE, "Inserted calibration $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() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt index 86c4460c00..987629e4cd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/EversensePlugin.kt @@ -30,7 +30,8 @@ import javax.inject.Singleton class EversensePlugin @Inject constructor( injector: HasAndroidInjector, resourceHelper: ResourceHelper, - aapsLogger: AAPSLogger + aapsLogger: AAPSLogger, + private val sp: SP ) : PluginBase(PluginDescription() .mainType(PluginType.BGSOURCE) .fragmentClass(BGSourceFragment::class.java.name) @@ -44,6 +45,9 @@ class EversensePlugin @Inject constructor( override var sensorBatteryLevel = -1 + override fun uploadToNs(glucoseValue: GlucoseValue): Boolean = + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.EVERSENSE && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + // cannot be inner class because of needed injection class EversenseWorker( context: Context, @@ -53,9 +57,8 @@ class EversensePlugin @Inject constructor( @Inject lateinit var injector: HasAndroidInjector @Inject lateinit var eversensePlugin: EversensePlugin @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var sp: SP - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var dateUtil: DateUtil + @Inject lateinit var nsUpload: NSUpload @Inject lateinit var dataWorker: DataWorker @Inject lateinit var repository: AppRepository @Inject lateinit var broadcastToXDrip: XDripBroadcast @@ -109,16 +112,14 @@ class EversensePlugin @Inject constructor( ) repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { - aapsLogger.error("Error while saving values from Eversense App", it) + aapsLogger.error(LTag.DATABASE, "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.debug(LTag.DATABASE, "Inserted bg $it") } } } @@ -148,7 +149,7 @@ class EversensePlugin @Inject constructor( .also { result -> result.inserted.forEach { nsUpload.uploadEvent(it) - aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") + aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt index c61e2a4065..8d5bcaa0ea 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/GlimpPlugin.kt @@ -14,7 +14,6 @@ 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.general.nsclient.NSUpload import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP @@ -25,7 +24,8 @@ import javax.inject.Singleton class GlimpPlugin @Inject constructor( injector: HasAndroidInjector, resourceHelper: ResourceHelper, - aapsLogger: AAPSLogger + aapsLogger: AAPSLogger, + private val sp: SP ) : PluginBase(PluginDescription() .mainType(PluginType.BGSOURCE) .fragmentClass(BGSourceFragment::class.java.name) @@ -47,8 +47,6 @@ class GlimpPlugin @Inject constructor( @Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var repository: AppRepository @Inject lateinit var broadcastToXDrip: XDripBroadcast - @Inject lateinit var sp: SP - @Inject lateinit var nsUpload: NSUpload init { (context.applicationContext as HasAndroidInjector).androidInjector().inject(this) @@ -70,19 +68,21 @@ class GlimpPlugin @Inject constructor( ) repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { - aapsLogger.error("Error while saving values from Glimp App", it) + aapsLogger.error(LTag.DATABASE, "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.debug(LTag.DATABASE, "Inserted bg $it") } } return ret } } + + override fun uploadToNs(glucoseValue: GlucoseValue): Boolean = + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.GLIMP && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt index 1bb431e59b..0ecd4cde17 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/MM640gPlugin.kt @@ -14,7 +14,6 @@ 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.general.nsclient.NSUpload import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.XDripBroadcast @@ -29,7 +28,8 @@ import javax.inject.Singleton class MM640gPlugin @Inject constructor( injector: HasAndroidInjector, resourceHelper: ResourceHelper, - aapsLogger: AAPSLogger + aapsLogger: AAPSLogger, + private val sp: SP ) : PluginBase(PluginDescription() .mainType(PluginType.BGSOURCE) .fragmentClass(BGSourceFragment::class.java.name) @@ -48,8 +48,6 @@ class MM640gPlugin @Inject constructor( @Inject lateinit var mM640gPlugin: MM640gPlugin @Inject lateinit var injector: HasAndroidInjector @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var sp: SP - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var dateUtil: DateUtil @Inject lateinit var dataWorker: DataWorker @Inject lateinit var repository: AppRepository @@ -88,18 +86,16 @@ class MM640gPlugin @Inject constructor( } repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { - aapsLogger.error("Error while saving values from Eversense App", it) + aapsLogger.error(LTag.DATABASE, "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") + savedValues.all().forEach { + broadcastToXDrip(it) + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") + } } - } } catch (e: JSONException) { aapsLogger.error("Exception: ", e) ret = Result.failure() @@ -109,4 +105,8 @@ class MM640gPlugin @Inject constructor( return ret } } + + override fun uploadToNs(glucoseValue: GlucoseValue): Boolean = + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.MM_600_SERIES && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt index b885e3b545..70aa2e73cd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/NSClientSourcePlugin.kt @@ -17,7 +17,6 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin -import info.nightscout.androidaps.plugins.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.general.nsclient.data.NSSgv import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification import info.nightscout.androidaps.plugins.general.overview.notifications.Notification @@ -61,6 +60,8 @@ class NSClientSourcePlugin @Inject constructor( return isAdvancedFilteringEnabled } + override fun uploadToNs(glucoseValue: GlucoseValue): Boolean = false + private fun detectSource(glucoseValue: GlucoseValue) { if (glucoseValue.timestamp > lastBGTimeStamp) { isAdvancedFilteringEnabled = arrayOf( @@ -85,7 +86,6 @@ class NSClientSourcePlugin @Inject constructor( @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 dataWorker: DataWorker @Inject lateinit var repository: AppRepository @@ -103,7 +103,7 @@ class NSClientSourcePlugin @Inject constructor( timestamp = sgv.mills ?: return null, value = sgv.mgdl?.toDouble() ?: return null, noise = null, - raw = sgv.filtered?.toDouble() ?: sgv.mgdl?.toDouble(), + raw = sgv.filtered?.toDouble() ?: sgv.mgdl?.toDouble(), trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction), nightscoutId = sgv.id, sourceSensor = GlucoseValue.SourceSensor.fromString(sgv.device) @@ -140,7 +140,7 @@ class NSClientSourcePlugin @Inject constructor( repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null, !nsClientSourcePlugin.isEnabled())) .doOnError { - aapsLogger.error("Error while saving values from NSClient App", it) + aapsLogger.error(LTag.DATABASE, "Error while saving values from NSClient App", it) ret = Result.failure() } .blockingGet() @@ -148,12 +148,12 @@ class NSClientSourcePlugin @Inject constructor( result.updated.forEach { broadcastToXDrip(it) nsClientSourcePlugin.detectSource(it) - aapsLogger.debug(LTag.BGSOURCE, "Updated bg $it") + aapsLogger.debug(LTag.DATABASE, "Updated bg $it") } result.inserted.forEach { broadcastToXDrip(it) nsClientSourcePlugin.detectSource(it) - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") } } } catch (e: Exception) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt index 09c5204309..9ada30986c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/PoctechPlugin.kt @@ -15,7 +15,6 @@ 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.general.nsclient.NSUpload import info.nightscout.androidaps.utils.JsonHelper.safeGetString import info.nightscout.androidaps.utils.XDripBroadcast import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -29,7 +28,8 @@ import javax.inject.Singleton class PoctechPlugin @Inject constructor( injector: HasAndroidInjector, resourceHelper: ResourceHelper, - aapsLogger: AAPSLogger + aapsLogger: AAPSLogger, + private val sp: SP ) : PluginBase(PluginDescription() .mainType(PluginType.BGSOURCE) .fragmentClass(BGSourceFragment::class.java.name) @@ -49,8 +49,6 @@ class PoctechPlugin @Inject constructor( @Inject lateinit var injector: HasAndroidInjector @Inject lateinit var poctechPlugin: PoctechPlugin @Inject lateinit var aapsLogger: AAPSLogger - @Inject lateinit var sp: SP - @Inject lateinit var nsUpload: NSUpload @Inject lateinit var repository: AppRepository @Inject lateinit var broadcastToXDrip: XDripBroadcast @@ -81,16 +79,14 @@ class PoctechPlugin @Inject constructor( } repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { - aapsLogger.error("Error while saving values from Poctech App", it) + aapsLogger.error(LTag.DATABASE, "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.debug(LTag.DATABASE, "Inserted bg $it") } } } catch (e: JSONException) { @@ -100,4 +96,8 @@ class PoctechPlugin @Inject constructor( return ret } } + + override fun uploadToNs(glucoseValue: GlucoseValue): Boolean = + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.POCTECH_NATIVE && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt index 03e1782660..f09d15d1de 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/RandomBgPlugin.kt @@ -13,7 +13,6 @@ 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.general.nsclient.NSUpload import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.T @@ -38,7 +37,6 @@ class RandomBgPlugin @Inject constructor( private val virtualPumpPlugin: VirtualPumpPlugin, private val buildHelper: BuildHelper, private val sp: SP, - private val nsUpload: NSUpload, private val dateUtil: DateUtil, private val repository: AppRepository, private val xDripBroadcast: XDripBroadcast @@ -74,6 +72,9 @@ class RandomBgPlugin @Inject constructor( return true } + override fun uploadToNs(glucoseValue: GlucoseValue): Boolean = + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.RANDOM && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + override fun onStart() { super.onStart() loopHandler.postDelayed(refreshLoop, T.mins(interval).msecs()) @@ -107,16 +108,13 @@ class RandomBgPlugin @Inject constructor( trendArrow = GlucoseValue.TrendArrow.NONE, sourceSensor = GlucoseValue.SourceSensor.RANDOM ) - disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)).subscribe({ savedValues -> - savedValues.inserted.forEach { - xDripBroadcast(it) - if (sp.getBoolean(R.string.key_dexcomg5_nsupload, false)) - nsUpload.uploadBg(it, GlucoseValue.SourceSensor.RANDOM.text) - aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") - } - }, { - aapsLogger.error(LTag.DATABASE, "Error while saving values from Random plugin", it) - }) - aapsLogger.debug(LTag.DATABASE, "Generated BG: $bgMgdl ${Date()}") + disposable += repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) + .subscribe({ savedValues -> + savedValues.inserted.forEach { + xDripBroadcast(it) + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") + } + }, { aapsLogger.error(LTag.DATABASE, "Error while saving values from Random plugin", it) } + ) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt index db1710d6e2..ce38a5e97e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/TomatoPlugin.kt @@ -25,7 +25,8 @@ import javax.inject.Singleton class TomatoPlugin @Inject constructor( injector: HasAndroidInjector, resourceHelper: ResourceHelper, - aapsLogger: AAPSLogger + aapsLogger: AAPSLogger, + private val sp: SP ) : PluginBase(PluginDescription() .mainType(PluginType.BGSOURCE) .fragmentClass(BGSourceFragment::class.java.name) @@ -71,19 +72,21 @@ class TomatoPlugin @Inject constructor( ) repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { - aapsLogger.error("Error while saving values from Tomato App", it) + aapsLogger.error(LTag.DATABASE, "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.debug(LTag.DATABASE, "Inserted bg $it") } } return ret } } + + override fun uploadToNs(glucoseValue: GlucoseValue): Boolean = + glucoseValue.sourceSensor == GlucoseValue.SourceSensor.LIBRE_1_TOMATO && sp.getBoolean(R.string.key_dexcomg5_nsupload, false) + } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt index 5d48cb6845..f07d64b876 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/XdripPlugin.kt @@ -37,6 +37,8 @@ class XdripPlugin @Inject constructor( private var advancedFiltering = false override var sensorBatteryLevel = -1 + override fun uploadToNs(glucoseValue: GlucoseValue): Boolean = false + override fun advancedFilteringSupported(): Boolean { return advancedFiltering } @@ -87,14 +89,14 @@ class XdripPlugin @Inject constructor( ) repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, emptyList(), null)) .doOnError { - aapsLogger.error(LTag.DATABASE, "Error while saving values from Eversense App", it) + aapsLogger.error(LTag.DATABASE, "Error while saving values from Xdrip", it) ret = Result.failure() } .blockingGet() .also { savedValues -> savedValues.all().forEach { xdripPlugin.detectSource(it) - aapsLogger.debug(LTag.BGSOURCE, "Inserted bg $it") + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") } } xdripPlugin.sensorBatteryLevel = bundle.getInt(Intents.EXTRA_SENSOR_BATTERY, -1) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java index 9b24b800d1..8229320666 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java @@ -626,7 +626,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface Treatment treatment = new Treatment(); treatment.date = detailedBolusInfo.timestamp; treatment.source = (detailedBolusInfo.getPumpType() == PumpType.USER) ? Source.USER : Source.PUMP; - treatment.pumpId = detailedBolusInfo.getBolusPumpId(); + treatment.pumpId = detailedBolusInfo.getBolusPumpId() != null ? detailedBolusInfo.getBolusPumpId() : 0; treatment.insulin = detailedBolusInfo.insulin; treatment.isValid = detailedBolusInfo.getBolusType() != DetailedBolusInfo.BolusType.PRIMING; treatment.isSMB = detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB; @@ -650,7 +650,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface Treatment carbsTreatment = new Treatment(); carbsTreatment.source = (detailedBolusInfo.getPumpType() == PumpType.USER) ? Source.USER : Source.PUMP; - carbsTreatment.pumpId = detailedBolusInfo.getCarbsPumpId(); // but this should never happen + carbsTreatment.pumpId = detailedBolusInfo.getCarbsPumpId() != null ? detailedBolusInfo.getCarbsPumpId() : 0; // but this should never happen carbsTreatment.date = detailedBolusInfo.timestamp + detailedBolusInfo.carbTime * 60 * 1000L + 1000L; // add 1 sec to make them different records carbsTreatment.carbs = detailedBolusInfo.carbs; diff --git a/app/src/main/res/layout/nsclientinternal_fragment.xml b/app/src/main/res/layout/ns_client_fragment.xml similarity index 78% rename from app/src/main/res/layout/nsclientinternal_fragment.xml rename to app/src/main/res/layout/ns_client_fragment.xml index 5ea1c046c9..a4b625d2a7 100644 --- a/app/src/main/res/layout/nsclientinternal_fragment.xml +++ b/app/src/main/res/layout/ns_client_fragment.xml @@ -1,14 +1,10 @@ - - - + android:autoLink="web" + tools:ignore="RtlHardcoded" /> @@ -42,18 +39,19 @@ android:gravity="center_horizontal"> + android:text="@string/nsclientinternal_autoscroll" + tools:ignore="RtlHardcoded" /> @@ -68,21 +66,23 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="5dp" - android:text="@string/status" /> + android:text="@string/status" + tools:ignore="RtlHardcoded" /> + android:textAlignment="viewEnd" + tools:ignore="RtlHardcoded" /> @@ -96,7 +96,7 @@ android:layout_marginTop="10dp"> + + - - - - + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index baa74b6dc1..6aee3ec401 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -34,6 +34,7 @@ absorption_category_settings insulin_oref_peak_settings ns_temporary_target_last_sync + ns_glucose_value_last_sync Treatments safety Max allowed bolus [U] @@ -1127,6 +1128,7 @@ Maximal profile basal value Current basal value Profile carbs ratio value + Full sync diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/BgSourceInterface.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/BgSourceInterface.kt index 200b68102d..0543004913 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/BgSourceInterface.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/BgSourceInterface.kt @@ -1,5 +1,7 @@ package info.nightscout.androidaps.interfaces +import info.nightscout.androidaps.database.entities.GlucoseValue + /** * Created by mike on 20.06.2016. */ @@ -8,4 +10,5 @@ interface BgSourceInterface { fun advancedFilteringSupported(): Boolean = false val sensorBatteryLevel: Int get() = -1 + fun uploadToNs(glucoseValue: GlucoseValue) : Boolean } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/interfaces/DataSyncSelector.kt b/core/src/main/java/info/nightscout/androidaps/interfaces/DataSyncSelector.kt index 434d6d67b7..118552dd84 100644 --- a/core/src/main/java/info/nightscout/androidaps/interfaces/DataSyncSelector.kt +++ b/core/src/main/java/info/nightscout/androidaps/interfaces/DataSyncSelector.kt @@ -1,16 +1,24 @@ package info.nightscout.androidaps.interfaces +import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.TemporaryTarget -import info.nightscout.androidaps.db.DbRequest interface DataSyncSelector { + data class PairTemporaryTarget(val value: TemporaryTarget, val updateRecordId: Long) + data class PairGlucoseValue(val value: GlucoseValue, val updateRecordId: Long) + fun resetToNextFullSync() fun confirmTempTargetsTimestamp(lastSynced: Long) fun confirmTempTargetsTimestampIfGreater(lastSynced: Long) fun changedTempTargets() : List - // Until NS v3 fun processChangedTempTargetsCompat(): Boolean + + fun confirmLastGlucoseValueId(lastSynced: Long) + fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) + fun changedGlucoseValues() : List + // Until NS v3 + fun processChangedGlucoseValuesCompat(): Boolean } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java b/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java index 43f83757e0..ec4fba7e9b 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java +++ b/core/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java @@ -434,38 +434,6 @@ public class NSUpload { uploadQueue.add(new DbRequest("dbAdd", "treatments", data, date.getTime())); } - public void uploadBg(GlucoseValue reading, String source) { - JSONObject data = new JSONObject(); - try { - data.put("device", source); - data.put("date", reading.getTimestamp()); - data.put("dateString", DateUtil.toISOString(reading.getTimestamp())); - data.put("sgv", reading.getValue()); - data.put("direction", reading.getTrendArrow().getText()); - data.put("type", "sgv"); - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - uploadQueue.add(new DbRequest("dbAdd", "entries", data, reading.getTimestamp())); - } - - public void updateBg(GlucoseValue reading, String source) { - JSONObject data = new JSONObject(); - try { - data.put("device", source); - data.put("date", reading.getTimestamp()); - data.put("dateString", DateUtil.toISOString(reading.getTimestamp())); - data.put("sgv", reading.getValue()); - data.put("direction", reading.getTrendArrow().getText()); - data.put("type", "sgv"); - if (reading.getInterfaceIDs().getNightscoutId() != null) { - uploadQueue.add(new DbRequest("dbUpdate", "entries", reading.getInterfaceIDs().getNightscoutId(), data, System.currentTimeMillis())); - } - } catch (JSONException e) { - aapsLogger.error("Unhandled exception", e); - } - } - public void uploadAppStart() { if (sp.getBoolean(R.string.key_ns_logappstartedevent, true)) { JSONObject data = new JSONObject(); diff --git a/core/src/main/java/info/nightscout/androidaps/utils/extensions/GlucoseValueExtension.kt b/core/src/main/java/info/nightscout/androidaps/utils/extensions/GlucoseValueExtension.kt new file mode 100644 index 0000000000..a143744f94 --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/utils/extensions/GlucoseValueExtension.kt @@ -0,0 +1,15 @@ +package info.nightscout.androidaps.utils.extensions + +import info.nightscout.androidaps.database.entities.GlucoseValue +import info.nightscout.androidaps.utils.DateUtil +import org.json.JSONObject + +fun GlucoseValue.toJson() : JSONObject = + JSONObject() + .put("device", sourceSensor.text) + .put("date", timestamp) + .put("dateString", DateUtil.toISOString(timestamp)) + .put("sgv", value) + .put("direction", trendArrow.text) + .put("type", "sgv") + .put("NSCLIENT_ID", System.currentTimeMillis()) // Fake to be accepted by WS diff --git a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt index c835f0fe30..1c4fe04ac4 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt @@ -75,6 +75,25 @@ open class AppRepository @Inject internal constructor( database.glucoseValueDao.getModifiedFrom(lastId) .subscribeOn(Schedulers.io()) + /* + * returns a Pair of the next entity to sync and the ID of the "update". + * The update id might either be the entry id itself if it is a new entry - or the id + * of the update ("historic") entry. The sync counter should be incremented to that id if it was synced successfully. + * + * It is a Maybe as there might be no next element. + * */ + fun getNextSyncElementGlucoseValue(id: Long): Maybe> = + database.glucoseValueDao.getNextModifiedOrNewAfter(id) + .flatMap { nextIdElement -> + val nextIdElemReferenceId = nextIdElement.referenceId + if (nextIdElemReferenceId == null) { + Maybe.just(nextIdElement to nextIdElement.id) + } else { + database.glucoseValueDao.getCurrentFromHistoric(nextIdElemReferenceId) + .map { it to nextIdElement.id} + } + } + fun getBgReadingsCorrespondingLastHistoryRecord(lastId: Long): GlucoseValue? = database.glucoseValueDao.getLastHistoryRecord(lastId) @@ -84,6 +103,25 @@ open class AppRepository @Inject internal constructor( .subscribeOn(Schedulers.io()) // TEMP TARGETS + /* + * returns a Pair of the next entity to sync and the ID of the "update". + * The update id might either be the entry id itself if it is a new entry - or the id + * of the update ("historic") entry. The sync counter should be incremented to that id if it was synced successfully. + * + * It is a Maybe as there might be no next element. + * */ + fun getNextSyncElementTemporaryTarget(id: Long): Maybe> = + database.temporaryTargetDao.getNextModifiedOrNewAfter(id) + .flatMap { nextIdElement -> + val nextIdElemReferenceId = nextIdElement.referenceId + if (nextIdElemReferenceId == null) { + Maybe.just(nextIdElement to nextIdElement.id) + } else { + database.temporaryTargetDao.getCurrentFromHistoric(nextIdElemReferenceId) + .map { it to nextIdElement.id} + } + } + fun compatGetTemporaryTargetData(): Single> = database.temporaryTargetDao.getTemporaryTargetData() .subscribeOn(Schedulers.io()) @@ -93,21 +131,11 @@ open class AppRepository @Inject internal constructor( .map { if (!ascending) it.reversed() else it } .subscribeOn(Schedulers.io()) - fun getAllChangedTemporaryTargetsFromTime(timestamp: Long, amount: Int): Single> = - database.temporaryTargetDao.getAllChangedFromTime(timestamp, amount) - .subscribeOn(Schedulers.io()) - fun getTemporaryTargetDataIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single> = database.temporaryTargetDao.getTemporaryTargetDataIncludingInvalidFromTime(timestamp) .map { if (!ascending) it.reversed() else it } .subscribeOn(Schedulers.io()) - fun findTemporaryTargetByNSIdSingle(nsId: String): TemporaryTarget? = - database.temporaryTargetDao.findByNSId(nsId) - - fun findTemporaryTargetByTimestamp(timestamp: Long): TemporaryTarget? = - database.temporaryTargetDao.findByTimestamp(timestamp) - fun getModifiedTemporaryTargetsDataFromId(lastId: Long): Single> = database.temporaryTargetDao.getModifiedFrom(lastId) .subscribeOn(Schedulers.io()) diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt index fdaefe78ad..0738101140 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt @@ -37,6 +37,14 @@ internal interface GlucoseValueDao : TraceableDao { @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE referenceId = :id ORDER BY id DESC LIMIT 1") fun getLastHistoryRecord(id: Long): GlucoseValue? + // This query will be used with v3 to get all changed records @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_GLUCOSE_VALUES WHERE id > :id) ORDER BY id ASC") fun getModifiedFrom(id: Long): Single> + + // for WS we need 1 record only + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE id > :id ORDER BY id ASC limit 1") + fun getNextModifiedOrNewAfter(id: Long): Maybe + + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE id = :referenceId") + fun getCurrentFromHistoric(referenceId: Long): Maybe } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryTargetDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryTargetDao.kt index 4630c4f72c..0bdaa08136 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryTargetDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryTargetDao.kt @@ -17,15 +17,9 @@ internal interface TemporaryTargetDao : TraceableDao { @Query("DELETE FROM $TABLE_TEMPORARY_TARGETS") override fun deleteAllEntries() - @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE dateCreated > :timestamp AND referenceId IS NULL ORDER BY timestamp ASC LIMIT :amount") - fun getAllChangedFromTime(timestamp: Long, amount: Int): Single> - @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE nightscoutId = :nsId AND referenceId IS NULL") fun findByNSId(nsId: String): TemporaryTarget? - @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE timestamp = :timestamp AND referenceId IS NULL") - fun findByTimestamp(timestamp: Long): TemporaryTarget? - @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE timestamp <= :timestamp AND (timestamp + duration) > :timestamp AND referenceId IS NULL AND isValid = 1 ORDER BY timestamp DESC LIMIT 1") fun getTemporaryTargetActiveAt(timestamp: Long): Maybe @@ -41,6 +35,14 @@ internal interface TemporaryTargetDao : TraceableDao { @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE referenceId = :id ORDER BY id DESC LIMIT 1") fun getLastHistoryRecord(id: Long): TemporaryTarget? + // This query will be used with v3 to get all changed records @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_TEMPORARY_TARGETS WHERE id > :id) ORDER BY id ASC") fun getModifiedFrom(id: Long): Single> + + // for WS we need 1 record only + @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE id > :id ORDER BY id ASC limit 1") + fun getNextModifiedOrNewAfter(id: Long): Maybe + + @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE id = :referenceId") + fun getCurrentFromHistoric(referenceId: Long): Maybe } \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdGlucoseValueTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdGlucoseValueTransaction.kt new file mode 100644 index 0000000000..954aadd39b --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateNsIdGlucoseValueTransaction.kt @@ -0,0 +1,12 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.GlucoseValue + +class UpdateNsIdGlucoseValueTransaction(val glucoseValue: GlucoseValue) : Transaction() { + + override fun run() { + val current = database.glucoseValueDao.findById(glucoseValue.id) + if (current != null && current.interfaceIDs.nightscoutId != glucoseValue.interfaceIDs.nightscoutId) + database.glucoseValueDao.updateExistingEntry(glucoseValue) + } +} \ No newline at end of file