Merge pull request #386 from nightscout/tt

TempTarget -> room
This commit is contained in:
Milos Kozak 2021-03-02 22:41:36 +01:00 committed by GitHub
commit efddea0eee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
76 changed files with 1255 additions and 1002 deletions

View file

@ -110,7 +110,7 @@ android {
defaultConfig {
multiDexEnabled true
versionCode 1500
version "2.8.2.1-dev-b"
version "2.8.2.1-dev-c"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'

View file

@ -74,9 +74,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
@Inject OpenHumansUploader openHumansUploader;
public static final String DATABASE_NAME = "AndroidAPSDb";
public static final String DATABASE_TEMPORARYBASALS = "TemporaryBasals";
public static final String DATABASE_EXTENDEDBOLUSES = "ExtendedBoluses";
public static final String DATABASE_TEMPTARGETS = "TempTargets";
public static final String DATABASE_DANARHISTORY = "DanaRHistory";
public static final String DATABASE_DBREQUESTS = "DBRequests";
public static final String DATABASE_CAREPORTALEVENTS = "CareportalEvents";
@ -87,15 +85,9 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public static Long earliestDataChange = null;
private static final ScheduledExecutorService bgWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledBgPost = null;
private static final ScheduledExecutorService tempBasalsWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledTemBasalsPost = null;
private static final ScheduledExecutorService tempTargetWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledTemTargetPost = null;
private static final ScheduledExecutorService extendedBolusWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledExtendedBolusPost = null;
@ -119,8 +111,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
try {
aapsLogger.info(LTag.DATABASE, "onCreate");
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
//TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class);
@ -151,8 +141,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (oldVersion < 7) {
aapsLogger.info(LTag.DATABASE, "onUpgrade");
TableUtils.dropTable(connectionSource, TempTarget.class, true);
//TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
TableUtils.dropTable(connectionSource, DbRequest.class, true);
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
@ -201,8 +189,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void resetDatabases() {
try {
TableUtils.dropTable(connectionSource, TempTarget.class, true);
//TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
TableUtils.dropTable(connectionSource, DbRequest.class, true);
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
@ -211,8 +197,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.dropTable(connectionSource, ProfileSwitch.class, true);
TableUtils.dropTable(connectionSource, TDD.class, true);
TableUtils.dropTable(connectionSource, OmnipodHistoryRecord.class, true);
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
//TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class);
@ -228,7 +212,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
virtualPumpPlugin.setFakingStatus(true);
scheduleTemporaryBasalChange();
scheduleExtendedBolusChange();
scheduleTemporaryTargetChange();
scheduleCareportalEventChange();
scheduleProfileSwitchChange();
new java.util.Timer().schedule(
@ -242,16 +225,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
);
}
public void resetTempTargets() {
try {
TableUtils.dropTable(connectionSource, TempTarget.class, true);
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
scheduleTemporaryTargetChange();
}
public void resetTemporaryBasals() {
try {
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
@ -306,10 +279,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// ------------------ getDao -------------------------------------------
private Dao<TempTarget, Long> getDaoTempTargets() throws SQLException {
return getDao(TempTarget.class);
}
private Dao<DanaRHistoryRecord, String> getDaoDanaRHistory() throws SQLException {
return getDao(DanaRHistoryRecord.class);
}
@ -476,8 +445,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
}
// -------------------- TEMPTARGET HANDLING -------------------
public static void updateEarliestDataChange(long newDate) {
if (earliestDataChange == null) {
earliestDataChange = newDate;
@ -488,196 +455,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
}
// ---------------- TempTargets handling ---------------
public List<TempTarget> getTemptargetsDataFromTime(long mills, boolean ascending) {
try {
Dao<TempTarget, Long> daoTempTargets = getDaoTempTargets();
List<TempTarget> tempTargets;
QueryBuilder<TempTarget, Long> queryBuilder = daoTempTargets.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills);
PreparedQuery<TempTarget> preparedQuery = queryBuilder.prepare();
tempTargets = daoTempTargets.query(preparedQuery);
return tempTargets;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<TempTarget>();
}
public List<TempTarget> getAllTempTargets() {
try {
return getDaoTempTargets().queryForAll();
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return Collections.emptyList();
}
public List<TempTarget> getTemptargetsDataFromTime(long from, long to, boolean ascending) {
try {
Dao<TempTarget, Long> daoTempTargets = getDaoTempTargets();
List<TempTarget> tempTargets;
QueryBuilder<TempTarget, Long> queryBuilder = daoTempTargets.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.between("date", from, to);
PreparedQuery<TempTarget> preparedQuery = queryBuilder.prepare();
tempTargets = daoTempTargets.query(preparedQuery);
return tempTargets;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<TempTarget>();
}
public boolean createOrUpdate(TempTarget tempTarget) {
try {
TempTarget old;
tempTarget.date = roundDateToSec(tempTarget.date);
if (tempTarget.source == Source.NIGHTSCOUT) {
old = getDaoTempTargets().queryForId(tempTarget.date);
if (old != null) {
if (!old.isEqual(tempTarget)) {
getDaoTempTargets().delete(old); // need to delete/create because date may change too
old.copyFrom(tempTarget);
getDaoTempTargets().create(old);
openHumansUploader.enqueueTempTarget(old);
aapsLogger.debug(LTag.DATABASE, "TEMPTARGET: Updating record by date from: " + Source.getString(tempTarget.source) + " " + old.toString());
scheduleTemporaryTargetChange();
return true;
}
return false;
}
// find by NS _id
if (tempTarget._id != null) {
QueryBuilder<TempTarget, Long> queryBuilder = getDaoTempTargets().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", tempTarget._id);
PreparedQuery<TempTarget> preparedQuery = queryBuilder.prepare();
List<TempTarget> trList = getDaoTempTargets().query(preparedQuery);
if (trList.size() > 0) {
old = trList.get(0);
if (!old.isEqual(tempTarget)) {
getDaoTempTargets().delete(old); // need to delete/create because date may change too
old.copyFrom(tempTarget);
getDaoTempTargets().create(old);
openHumansUploader.enqueueTempTarget(old);
aapsLogger.debug(LTag.DATABASE, "TEMPTARGET: Updating record by _id from: " + Source.getString(tempTarget.source) + " " + old.toString());
scheduleTemporaryTargetChange();
return true;
}
}
}
getDaoTempTargets().create(tempTarget);
aapsLogger.debug(LTag.DATABASE, "TEMPTARGET: New record from: " + Source.getString(tempTarget.source) + " " + tempTarget.toString());
scheduleTemporaryTargetChange();
return true;
}
if (tempTarget.source == Source.USER) {
getDaoTempTargets().create(tempTarget);
openHumansUploader.enqueueTempTarget(tempTarget);
aapsLogger.debug(LTag.DATABASE, "TEMPTARGET: New record from: " + Source.getString(tempTarget.source) + " " + tempTarget.toString());
scheduleTemporaryTargetChange();
return true;
}
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return false;
}
public void delete(TempTarget tempTarget) {
try {
getDaoTempTargets().delete(tempTarget);
openHumansUploader.enqueueTempTarget(tempTarget, true);
scheduleTemporaryTargetChange();
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
}
private void scheduleTemporaryTargetChange() {
class PostRunnable implements Runnable {
public void run() {
aapsLogger.debug(LTag.DATABASE, "Firing EventTempTargetChange");
rxBus.send(new EventTempTargetChange());
scheduledTemTargetPost = null;
}
}
// prepare task for execution in 1 sec
// cancel waiting task to prevent sending multiple posts
if (scheduledTemTargetPost != null)
scheduledTemTargetPost.cancel(false);
Runnable task = new PostRunnable();
final int sec = 1;
scheduledTemTargetPost = tempTargetWorker.schedule(task, sec, TimeUnit.SECONDS);
}
/*
{
"_id": "58795998aa86647ba4d68ce7",
"enteredBy": "",
"eventType": "Temporary Target",
"reason": "Eating Soon",
"targetTop": 80,
"targetBottom": 80,
"duration": 120,
"created_at": "2017-01-13T22:50:00.782Z",
"carbs": null,
"insulin": null
}
*/
public void createTemptargetFromJsonIfNotExists(JSONObject trJson) {
try {
String units = JsonHelper.safeGetString(trJson, "units", Constants.MGDL);
TempTarget tempTarget = new TempTarget()
.date(trJson.getLong("mills"))
.duration(JsonHelper.safeGetInt(trJson, "duration"))
.low(Profile.toMgdl(JsonHelper.safeGetDouble(trJson, "targetBottom"), units))
.high(Profile.toMgdl(JsonHelper.safeGetDouble(trJson, "targetTop"), units))
.reason(JsonHelper.safeGetString(trJson, "reason", ""))
._id(trJson.getString("_id"))
.source(Source.NIGHTSCOUT);
createOrUpdate(tempTarget);
} catch (JSONException e) {
aapsLogger.error("Unhandled exception: " + trJson.toString(), e);
}
}
public void deleteTempTargetById(String _id) {
TempTarget stored = findTempTargetById(_id);
if (stored != null) {
aapsLogger.debug(LTag.DATABASE, "TEMPTARGET: Removing TempTarget record from database: " + stored.toString());
delete(stored);
scheduleTemporaryTargetChange();
}
}
public TempTarget findTempTargetById(String _id) {
try {
QueryBuilder<TempTarget, Long> queryBuilder = getDaoTempTargets().queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", _id);
PreparedQuery<TempTarget> preparedQuery = queryBuilder.prepare();
List<TempTarget> list = getDaoTempTargets().query(preparedQuery);
if (list.size() == 1) {
return list.get(0);
} else {
return null;
}
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return null;
}
// ----------------- DanaRHistory handling --------------------
public void createOrUpdate(DanaRHistoryRecord record) {
@ -1723,7 +1500,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (stored != null) {
aapsLogger.debug(LTag.DATABASE, "PROFILESWITCH: Removing ProfileSwitch record from database: " + stored.toString());
delete(stored);
scheduleTemporaryTargetChange();
scheduleProfileSwitchChange();
}
}
@ -1958,8 +1735,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
+ getDaoCareportalEvents().countOf()
+ getDaoProfileSwitch().countOf()
+ getDaoTDD().countOf()
+ getDaoTemporaryBasal().countOf()
+ getDaoTempTargets().countOf();
+ getDaoTemporaryBasal().countOf();
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}

View file

@ -5,6 +5,7 @@ import androidx.annotation.NonNull;
import com.j256.ormlite.dao.CloseableIterator;
import org.jetbrains.annotations.Nullable;
import org.json.JSONObject;
import java.sql.SQLException;
import java.util.List;
@ -13,7 +14,9 @@ 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 {
@ -77,8 +80,8 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
MainApp.getDbHelper().createOrUpdateTDD(record);
}
@Override public void createOrUpdate(@NonNull TemporaryBasal tempBasal) {
MainApp.getDbHelper().createOrUpdate(tempBasal);
@Override public boolean createOrUpdate(@NonNull TemporaryBasal tempBasal) {
return MainApp.getDbHelper().createOrUpdate(tempBasal);
}
@NonNull @Override public TemporaryBasal findTempBasalByPumpId(long id) {
@ -140,4 +143,56 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
@Nullable @Override public InsightPumpID getPumpStoppedEvent(@NonNull String pumpSerial, long before) {
return MainApp.getDbHelper().getPumpStoppedEvent(pumpSerial, before);
}
@Override public boolean createOrUpdate(@NonNull ExtendedBolus extendedBolus) {
return MainApp.getDbHelper().createOrUpdate(extendedBolus);
}
@Override public void createOrUpdate(@NonNull ProfileSwitch profileSwitch) {
MainApp.getDbHelper().createOrUpdate(profileSwitch);
}
@Override public void delete(@NonNull TemporaryBasal tempBasal) {
MainApp.getDbHelper().delete(tempBasal);
}
@NonNull @Override public List<ExtendedBolus> getExtendedBolusDataFromTime(long mills, boolean ascending) {
return MainApp.getDbHelper().getExtendedBolusDataFromTime(mills, ascending);
}
@Override public void deleteTempBasalById(@NonNull String _id) {
MainApp.getDbHelper().deleteTempBasalById(_id);
}
@Override public void deleteExtendedBolusById(@NonNull String _id) {
MainApp.getDbHelper().deleteExtendedBolusById(_id);
}
@Override public void deleteCareportalEventById(@NonNull String _id) {
MainApp.getDbHelper().deleteCareportalEventById(_id);
}
@Override public void deleteProfileSwitchById(@NonNull String _id) {
MainApp.getDbHelper().deleteProfileSwitchById(_id);
}
@Override public void createTempBasalFromJsonIfNotExists(@NonNull JSONObject json) {
MainApp.getDbHelper().createTempBasalFromJsonIfNotExists(json);
}
@Override public void createExtendedBolusFromJsonIfNotExists(@NonNull JSONObject json) {
MainApp.getDbHelper().createExtendedBolusFromJsonIfNotExists(json);
}
@Override public void createCareportalEventFromJsonIfNotExists(@NonNull JSONObject json) {
MainApp.getDbHelper().createCareportalEventFromJsonIfNotExists(json);
}
@Override public void createProfileSwitchFromJsonIfNotExists(@NonNull ActivePluginProvider activePluginProvider, @NonNull NSUpload nsUpload, @NonNull JSONObject trJson) {
MainApp.getDbHelper().createProfileSwitchFromJsonIfNotExists(activePluginProvider, nsUpload, trJson);
}
@Override public void resetDatabases() {
MainApp.getDbHelper().resetDatabases();
}
}

View file

@ -11,12 +11,14 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.databinding.DialogCarbsBinding
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
@ -27,8 +29,11 @@ import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.formatColor
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import java.text.DecimalFormat
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import kotlin.math.max
@ -45,6 +50,7 @@ class CarbsDialog : DialogFragmentWithDate() {
@Inject lateinit var carbsGenerator: CarbsGenerator
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var carbTimer: CarbTimer
@Inject lateinit var repository: AppRepository
companion object {
@ -53,6 +59,8 @@ class CarbsDialog : DialogFragmentWithDate() {
private const val FAV3_DEFAULT = 20
}
private val disposable = CompositeDisposable()
private val textWatcher: TextWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable) {
validateInputs()
@ -153,6 +161,7 @@ class CarbsDialog : DialogFragmentWithDate() {
override fun onDestroyView() {
super.onDestroyView()
disposable.clear()
_binding = null
}
@ -213,38 +222,50 @@ class CarbsDialog : DialogFragmentWithDate() {
when {
activitySelected -> {
uel.log("TT ACTIVITY", d1 = activityTT, i1 = activityTTDuration)
val tempTarget = TempTarget()
.date(System.currentTimeMillis())
.duration(activityTTDuration)
.reason(resourceHelper.gs(R.string.activity))
.source(Source.USER)
.low(Profile.toMgdl(activityTT, profileFunction.getUnits()))
.high(Profile.toMgdl(activityTT, profileFunction.getUnits()))
treatmentsPlugin.addToHistoryTempTarget(tempTarget)
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(activityTTDuration.toLong()),
reason = TemporaryTarget.Reason.ACTIVITY,
lowTarget = Profile.toMgdl(activityTT, profileFunction.getUnits()),
highTarget = Profile.toMgdl(activityTT, profileFunction.getUnits())
)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadTempTarget(it) }
result.updated.forEach { nsUpload.updateTempTarget(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it)
})
}
eatingSoonSelected -> {
uel.log("TT EATING SOON", d1 = eatingSoonTT, i1 = eatingSoonTTDuration)
val tempTarget = TempTarget()
.date(System.currentTimeMillis())
.duration(eatingSoonTTDuration)
.reason(resourceHelper.gs(R.string.eatingsoon))
.source(Source.USER)
.low(Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()))
.high(Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()))
treatmentsPlugin.addToHistoryTempTarget(tempTarget)
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
reason = TemporaryTarget.Reason.EATING_SOON,
lowTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()),
highTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits())
)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadTempTarget(it) }
result.updated.forEach { nsUpload.updateTempTarget(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it)
})
}
hypoSelected -> {
uel.log("TT HYPO", d1 = hypoTT, i1 = hypoTTDuration)
val tempTarget = TempTarget()
.date(System.currentTimeMillis())
.duration(hypoTTDuration)
.reason(resourceHelper.gs(R.string.hypo))
.source(Source.USER)
.low(Profile.toMgdl(hypoTT, profileFunction.getUnits()))
.high(Profile.toMgdl(hypoTT, profileFunction.getUnits()))
treatmentsPlugin.addToHistoryTempTarget(tempTarget)
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(hypoTTDuration.toLong()),
reason = TemporaryTarget.Reason.HYPOGLYCEMIA,
lowTarget = Profile.toMgdl(hypoTT, profileFunction.getUnits()),
highTarget = Profile.toMgdl(hypoTT, profileFunction.getUnits())
)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadTempTarget(it) }
result.updated.forEach { nsUpload.updateTempTarget(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it)
})
}
}
if (carbsAfterConstraints > 0) {

View file

@ -16,6 +16,7 @@ import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.databinding.DialogCareBinding
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
@ -39,6 +40,7 @@ class CareDialog : DialogFragmentWithDate() {
@Inject lateinit var nsUpload: NSUpload
@Inject lateinit var translator: Translator
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var databaseHelper: DatabaseHelperInterface
enum class EventType {
BGCHECK,
@ -223,8 +225,8 @@ class CareDialog : DialogFragmentWithDate() {
}
careportalEvent.json = json.toString()
uel.log("CAREPORTAL", careportalEvent.eventType)
MainApp.getDbHelper().createOrUpdate(careportalEvent)
nsUpload.uploadCareportalEntryToNS(json)
databaseHelper.createOrUpdate(careportalEvent)
nsUpload.uploadCareportalEntryToNS(json, eventTime)
}, null)
}
return true

View file

@ -15,16 +15,19 @@ import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.databinding.DialogInsulinBinding
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
@ -32,8 +35,11 @@ import info.nightscout.androidaps.utils.extensions.formatColor
import info.nightscout.androidaps.utils.extensions.toSignedString
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import java.text.DecimalFormat
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import kotlin.math.abs
import kotlin.math.max
@ -50,6 +56,7 @@ class InsulinDialog : DialogFragmentWithDate() {
@Inject lateinit var repository: AppRepository
@Inject lateinit var config: Config
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var nsUpload: NSUpload
companion object {
@ -58,6 +65,8 @@ class InsulinDialog : DialogFragmentWithDate() {
private const val PLUS3_DEFAULT = 2.0
}
private val disposable = CompositeDisposable()
private val textWatcher: TextWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable) {
validateInputs()
@ -139,6 +148,7 @@ class InsulinDialog : DialogFragmentWithDate() {
override fun onDestroyView() {
super.onDestroyView()
disposable.clear()
_binding = null
}
@ -179,14 +189,18 @@ class InsulinDialog : DialogFragmentWithDate() {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
if (eatingSoonChecked) {
uel.log("TT EATING SOON", d1 = eatingSoonTT, i1 = eatingSoonTTDuration)
val tempTarget = TempTarget()
.date(System.currentTimeMillis())
.duration(eatingSoonTTDuration)
.reason(resourceHelper.gs(R.string.eatingsoon))
.source(Source.USER)
.low(Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()))
.high(Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()))
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
reason = TemporaryTarget.Reason.EATING_SOON,
lowTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()),
highTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits())
)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadTempTarget(it) }
result.updated.forEach { nsUpload.updateTempTarget(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it)
})
}
if (insulinAfterConstraints > 0) {
val detailedBolusInfo = DetailedBolusInfo()

View file

@ -10,20 +10,26 @@ import com.google.common.collect.Lists
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.databinding.DialogTemptargetBinding
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import java.text.DecimalFormat
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class TempTargetDialog : DialogFragmentWithDate() {
@ -32,12 +38,14 @@ class TempTargetDialog : DialogFragmentWithDate() {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var repository: AppRepository
@Inject lateinit var nsUpload: NSUpload
private lateinit var reasonList: List<String>
private val disposable = CompositeDisposable()
private var _binding: DialogTemptargetBinding? = null
// This property is only valid between onCreateView and
@ -47,7 +55,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("duration", binding.duration.value)
savedInstanceState.putDouble("temptarget", binding.temptarget.value)
savedInstanceState.putDouble("tempTarget", binding.temptarget.value)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
@ -65,12 +73,12 @@ class TempTargetDialog : DialogFragmentWithDate() {
if (profileFunction.getUnits() == Constants.MMOL)
binding.temptarget.setParams(
savedInstanceState?.getDouble("temptarget")
savedInstanceState?.getDouble("tempTarget")
?: 8.0,
Constants.MIN_TT_MMOL, Constants.MAX_TT_MMOL, 0.1, DecimalFormat("0.0"), false, binding.okcancel.ok)
else
binding.temptarget.setParams(
savedInstanceState?.getDouble("temptarget")
savedInstanceState?.getDouble("tempTarget")
?: 144.0,
Constants.MIN_TT_MGDL, Constants.MAX_TT_MGDL, 1.0, DecimalFormat("0"), false, binding.okcancel.ok)
@ -79,7 +87,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
// temp target
context?.let { context ->
if (activePlugin.activeTreatments.tempTargetFromHistory != null)
if (repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() is ValueWrapper.Existing)
binding.targetCancel.visibility = View.VISIBLE
else
binding.targetCancel.visibility = View.GONE
@ -142,6 +150,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
override fun onDestroyView() {
super.onDestroyView()
disposable.clear()
_binding = null
}
@ -166,21 +175,30 @@ class TempTargetDialog : DialogFragmentWithDate() {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_temporarytarget), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
uel.log("TT", d1 = target, i1 = duration)
if (target == 0.0 || duration == 0) {
val tempTarget = TempTarget()
.date(eventTime)
.duration(0)
.low(0.0).high(0.0)
.source(Source.USER)
treatmentsPlugin.addToHistoryTempTarget(tempTarget)
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(eventTime))
.subscribe({ result ->
result.updated.forEach { nsUpload.updateTempTarget(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it)
})
} else {
val tempTarget = TempTarget()
.date(eventTime)
.duration(duration)
.reason(reason)
.source(Source.USER)
.low(Profile.toMgdl(target, profileFunction.getUnits()))
.high(Profile.toMgdl(target, profileFunction.getUnits()))
treatmentsPlugin.addToHistoryTempTarget(tempTarget)
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = eventTime,
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
reason = when (reason) {
"Eating Soon" -> TemporaryTarget.Reason.EATING_SOON
"Activity" -> TemporaryTarget.Reason.ACTIVITY
"Hypo" -> TemporaryTarget.Reason.HYPOGLYCEMIA
else -> TemporaryTarget.Reason.CUSTOM
},
lowTarget = Profile.toMgdl(target, profileFunction.getUnits()),
highTarget = Profile.toMgdl(target, profileFunction.getUnits())
)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadTempTarget(it) }
result.updated.forEach { nsUpload.updateTempTarget(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it)
})
}
if (duration == 10) sp.putBoolean(R.string.key_objectiveusetemptarget, true)
})

View file

@ -19,26 +19,24 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.databinding.DialogWizardBinding
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.TreatmentsInterface
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.valueToUnits
import info.nightscout.androidaps.utils.wizard.BolusWizard
import io.reactivex.disposables.CompositeDisposable
import java.text.DecimalFormat
@ -58,9 +56,11 @@ class WizardDialog : DaggerDialogFragment() {
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
@Inject lateinit var repository: AppRepository
@Inject lateinit var treatmentsPlugin: TreatmentsInterface
@Inject lateinit var dateUtil: DateUtil
private var wizard: BolusWizard? = null
@ -207,7 +207,7 @@ class WizardDialog : DaggerDialogFragment() {
private fun onCheckedChanged(buttonView: CompoundButton, @Suppress("UNUSED_PARAMETER") state: Boolean) {
saveCheckedStates()
binding.ttcheckbox.isEnabled = binding.bgcheckbox.isChecked && treatmentsPlugin.tempTargetFromHistory != null
binding.ttcheckbox.isEnabled = binding.bgcheckbox.isChecked && repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() is ValueWrapper.Existing
if (buttonView.id == binding.cobcheckbox.id)
processCobCheckBox()
calculateInsulin()
@ -271,7 +271,7 @@ class WizardDialog : DaggerDialogFragment() {
} else {
binding.bgInput.value = 0.0
}
binding.ttcheckbox.isEnabled = treatmentsPlugin.tempTargetFromHistory != null
binding.ttcheckbox.isEnabled = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() is ValueWrapper.Existing
// IOB calculation
treatmentsPlugin.updateTotalIOBTreatments()
@ -313,7 +313,8 @@ class WizardDialog : DaggerDialogFragment() {
}
bg = if (binding.bgcheckbox.isChecked) bg else 0.0
val tempTarget = if (binding.ttcheckbox.isChecked) treatmentsPlugin.tempTargetFromHistory else null
val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet()
val tempTarget = if (binding.ttcheckbox.isChecked && dbRecord is ValueWrapper.Existing) dbRecord.value else null
// COB
var cob = 0.0

View file

@ -2,7 +2,9 @@ package info.nightscout.androidaps.historyBrowser
import android.content.Context
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
@ -32,8 +34,10 @@ class TreatmentsPluginHistory @Inject constructor(
nsUpload: NSUpload,
fabricPrivacy: FabricPrivacy,
dateUtil: DateUtil,
uploadQueue: UploadQueue
) : TreatmentsPlugin(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, context, sp, profileFunction, activePlugin, nsUpload, fabricPrivacy, dateUtil, uploadQueue) {
uploadQueue: UploadQueue,
databaseHelper: DatabaseHelperInterface,
repository: AppRepository
) : TreatmentsPlugin(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, context, sp, profileFunction, activePlugin, nsUpload, fabricPrivacy, dateUtil, uploadQueue, databaseHelper, repository) {
init {
onStart()

View file

@ -76,6 +76,7 @@ open class LoopPlugin @Inject constructor(
private val receiverStatusStore: ReceiverStatusStore,
private val fabricPrivacy: FabricPrivacy,
private val nsUpload: NSUpload,
private val databaseHelper: DatabaseHelperInterface,
private val hardLimits: HardLimits
) : PluginBase(PluginDescription()
.mainType(PluginType.LOOP)
@ -627,7 +628,7 @@ open class LoopPlugin @Inject constructor(
}
})
}
if (pump.pumpDescription.isExtendedBolusCapable && treatmentsPlugin.isInHistoryExtendedBoluslInProgress) {
if (pump.pumpDescription.isExtendedBolusCapable && treatmentsPlugin.isInHistoryExtendedBolusInProgress) {
commandQueue.cancelExtended(object : Callback() {
override fun run() {
if (!result.success) {
@ -664,7 +665,7 @@ open class LoopPlugin @Inject constructor(
event.source = Source.USER
event.eventType = CareportalEvent.OPENAPSOFFLINE
event.json = data.toString()
MainApp.getDbHelper().createOrUpdate(event)
databaseHelper.createOrUpdate(event)
nsUpload.uploadOpenAPSOffline(event)
}

View file

@ -4,6 +4,8 @@ import android.content.Context
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
@ -20,6 +22,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.Profiler
import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.extensions.target
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.json.JSONException
import javax.inject.Inject
@ -39,7 +42,9 @@ open class OpenAPSAMAPlugin @Inject constructor(
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
private val hardLimits: HardLimits,
private val profiler: Profiler,
private val fabricPrivacy: FabricPrivacy
private val fabricPrivacy: FabricPrivacy,
private val dateUtil: DateUtil,
private val repository: AppRepository
) : PluginBase(PluginDescription()
.mainType(PluginType.APS)
.fragmentClass(OpenAPSAMAFragment::class.java.name)
@ -112,11 +117,12 @@ open class OpenAPSAMAPlugin @Inject constructor(
var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetHighMgdl, 0.1), "maxBg", hardLimits.VERY_HARD_LIMIT_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MAX_BG[1].toDouble())
var targetBg = hardLimits.verifyHardLimits(profile.targetMgdl, "targetBg", hardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble())
var isTempTarget = false
treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis())?.let { tempTarget ->
isTempTarget = true
minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble())
maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet()
if (tempTarget is ValueWrapper.Existing) {
isTempTarget = true
minBg = hardLimits.verifyHardLimits(tempTarget.value.lowTarget, "minBg", hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble())
maxBg = hardLimits.verifyHardLimits(tempTarget.value.highTarget, "maxBg", hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
targetBg = hardLimits.verifyHardLimits(tempTarget.value.target(), "targetBg", hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
}
if (!hardLimits.checkOnlyHardLimits(profile.dia, "dia", hardLimits.minDia(), hardLimits.maxDia())) return
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC())) return

View file

@ -6,6 +6,8 @@ import androidx.preference.SwitchPreference
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
@ -21,6 +23,7 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.Profiler
import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.extensions.target
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject
@ -40,7 +43,9 @@ open class OpenAPSSMBPlugin @Inject constructor(
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
private val hardLimits: HardLimits,
private val profiler: Profiler,
private val sp: SP
private val sp: SP,
private val dateUtil: DateUtil,
private val repository: AppRepository
) : PluginBase(PluginDescription()
.mainType(PluginType.APS)
.fragmentClass(OpenAPSSMBFragment::class.java.name)
@ -118,11 +123,12 @@ open class OpenAPSSMBPlugin @Inject constructor(
var maxBg = hardLimits.verifyHardLimits(Round.roundTo(profile.targetHighMgdl, 0.1), "maxBg", hardLimits.VERY_HARD_LIMIT_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_MAX_BG[1].toDouble())
var targetBg = hardLimits.verifyHardLimits(profile.targetMgdl, "targetBg", hardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble())
var isTempTarget = false
treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis())?.let { tempTarget ->
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet()
if (tempTarget is ValueWrapper.Existing) {
isTempTarget = true
minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble())
maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
minBg = hardLimits.verifyHardLimits(tempTarget.value.lowTarget, "minBg", hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1].toDouble())
maxBg = hardLimits.verifyHardLimits(tempTarget.value.highTarget, "maxBg", hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
targetBg = hardLimits.verifyHardLimits(tempTarget.value.target(), "targetBg", hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
}
if (!hardLimits.checkOnlyHardLimits(profile.dia, "dia", hardLimits.minDia(), hardLimits.maxDia())) return
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.minIC(), hardLimits.maxIC())) return

View file

@ -68,7 +68,7 @@ class SafetyPlugin @Inject constructor(
value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_on_dev_branch)] = this
}
val pump = activePlugin.activePump
if (!pump.isFakingTempsByExtendedBoluses && treatmentsPlugin.isInHistoryExtendedBoluslInProgress) {
if (!pump.isFakingTempsByExtendedBoluses && treatmentsPlugin.isInHistoryExtendedBolusInProgress) {
value[aapsLogger, false, resourceHelper.gs(R.string.closed_loop_disabled_with_eb)] = this
}
return value

View file

@ -153,7 +153,7 @@ class ActionsFragment : DaggerFragment() {
}
}
extendedBolusCancel?.setOnClickListener {
if (activePlugin.activeTreatments.isInHistoryExtendedBoluslInProgress) {
if (activePlugin.activeTreatments.isInHistoryExtendedBolusInProgress) {
uel.log("CANCEL EXTENDED BOLUS")
commandQueue.cancelExtended(object : Callback() {
override fun run() {

View file

@ -6,11 +6,11 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding
import info.nightscout.androidaps.events.EventNewBG
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.UserEntryLogger
@ -37,6 +37,7 @@ class MaintenanceFragment : DaggerFragment() {
@Inject lateinit var importExportPrefs: ImportExportPrefsInterface
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var repository: AppRepository
@Inject lateinit var databaseHelper: DatabaseHelperInterface
@Inject lateinit var uel: UserEntryLogger
private val compositeDisposable = CompositeDisposable()
@ -65,7 +66,7 @@ class MaintenanceFragment : DaggerFragment() {
uel.log("RESET DATABASES")
compositeDisposable.add(
fromAction {
MainApp.getDbHelper().resetDatabases()
databaseHelper.resetDatabases()
// should be handled by Plugin-Interface and
// additional service interface and plugin registry
foodPlugin.service?.resetFood()

View file

@ -10,10 +10,10 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.text.Spanned;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreference;
import androidx.annotation.NonNull;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@ -27,8 +27,10 @@ import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.TemporaryTarget;
import info.nightscout.androidaps.database.transactions.SyncTemporaryTargetTransaction;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventChargingState;
@ -36,11 +38,13 @@ import info.nightscout.androidaps.events.EventNetworkChange;
import info.nightscout.androidaps.events.EventNsTreatment;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.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;
@ -63,6 +67,9 @@ import info.nightscout.androidaps.utils.rx.AapsSchedulers;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
import static info.nightscout.androidaps.utils.extensions.TemporaryTargetExtensionKt.temporaryTargetFromJson;
import static info.nightscout.androidaps.utils.extensions.TemporaryTargetExtensionKt.temporaryTargetFromNsIdForInvalidating;
@Singleton
public class NSClientPlugin extends PluginBase {
private final CompositeDisposable disposable = new CompositeDisposable();
@ -78,6 +85,9 @@ public class NSClientPlugin extends PluginBase {
private final BuildHelper buildHelper;
private final ActivePluginProvider activePlugin;
private final NSUpload nsUpload;
private final AppRepository repository;
private final DatabaseHelperInterface databaseHelper;
private final UserEntryLogger uel;
public Handler handler;
@ -107,7 +117,10 @@ public class NSClientPlugin extends PluginBase {
Config config,
BuildHelper buildHelper,
ActivePluginProvider activePlugin,
NSUpload nsUpload
NSUpload nsUpload,
DatabaseHelperInterface databaseHelper,
AppRepository repository,
UserEntryLogger uel
) {
super(new PluginDescription()
.mainType(PluginType.GENERAL)
@ -132,6 +145,9 @@ public class NSClientPlugin extends PluginBase {
this.buildHelper = buildHelper;
this.activePlugin = activePlugin;
this.nsUpload = nsUpload;
this.databaseHelper = databaseHelper;
this.repository = repository;
this.uel = uel;
if (config.getNSCLIENT()) {
getPluginDescription().alwaysEnabled(true).visibleByDefault(true);
@ -170,12 +186,12 @@ public class NSClientPlugin extends PluginBase {
disposable.add(rxBus
.toObservable(EventNetworkChange.class)
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> nsClientReceiverDelegate.onStatusEvent(event), fabricPrivacy::logException)
.subscribe(nsClientReceiverDelegate::onStatusEvent, fabricPrivacy::logException)
);
disposable.add(rxBus
.toObservable(EventPreferenceChange.class)
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> nsClientReceiverDelegate.onStatusEvent(event), fabricPrivacy::logException)
.subscribe(nsClientReceiverDelegate::onStatusEvent, fabricPrivacy::logException)
);
disposable.add(rxBus
.toObservable(EventAppExit.class)
@ -197,7 +213,7 @@ public class NSClientPlugin extends PluginBase {
disposable.add(rxBus
.toObservable(EventChargingState.class)
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> nsClientReceiverDelegate.onStatusEvent(event), fabricPrivacy::logException)
.subscribe(nsClientReceiverDelegate::onStatusEvent, fabricPrivacy::logException)
);
disposable.add(rxBus
.toObservable(EventNSClientResend.class)
@ -402,16 +418,21 @@ public class NSClientPlugin extends PluginBase {
}
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("TT DELETED FROM NS", record.getReason().getText(), record.getLowTarget(), record.getHighTarget(), (int) record.getDuration(), 0)),
error -> aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", error)));
// new DB model
EventNsTreatment evtTreatment = new EventNsTreatment(EventNsTreatment.Companion.getREMOVE(), json);
rxBus.send(evtTreatment);
// old DB model
String _id = JsonHelper.safeGetString(json, "_id");
MainApp.getDbHelper().deleteTempTargetById(_id);
MainApp.getDbHelper().deleteTempBasalById(_id);
MainApp.getDbHelper().deleteExtendedBolusById(_id);
MainApp.getDbHelper().deleteCareportalEventById(_id);
MainApp.getDbHelper().deleteProfileSwitchById(_id);
databaseHelper.deleteTempBasalById(_id);
databaseHelper.deleteExtendedBolusById(_id);
databaseHelper.deleteCareportalEventById(_id);
databaseHelper.deleteProfileSwitchById(_id);
}
private void handleTreatmentFromNS(JSONObject json, String action) {
@ -428,13 +449,24 @@ public class NSClientPlugin extends PluginBase {
EventNsTreatment evtTreatment = new EventNsTreatment(mode, json);
rxBus.send(evtTreatment);
} else if (eventType.equals(CareportalEvent.TEMPORARYTARGET)) {
MainApp.getDbHelper().createTemptargetFromJsonIfNotExists(json);
TemporaryTarget temporaryTarget = temporaryTargetFromJson(json);
if (temporaryTarget != null) {
disposable.add(repository.runTransactionForResult(new SyncTemporaryTargetTransaction(temporaryTarget)).subscribe(
result -> {
result.getInserted().forEach(record -> uel.log("TT FROM NS", record.getReason().getText(), record.getLowTarget(), record.getHighTarget(), (int) record.getDuration(), 0));
result.getInvalidated().forEach(record -> uel.log("TT DELETED FROM NS", record.getReason().getText(), record.getLowTarget(), record.getHighTarget(), (int) record.getDuration(), 0));
result.getEnded().forEach(record -> uel.log("TT CANCELED FROM NS", record.getReason().getText(), record.getLowTarget(), record.getHighTarget(), (int) record.getDuration(), 0));
},
error -> aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", error)));
} else {
aapsLogger.error("Error parsing TT json " + json.toString());
}
} else if (eventType.equals(CareportalEvent.TEMPBASAL)) {
MainApp.getDbHelper().createTempBasalFromJsonIfNotExists(json);
databaseHelper.createTempBasalFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.COMBOBOLUS)) {
MainApp.getDbHelper().createExtendedBolusFromJsonIfNotExists(json);
databaseHelper.createExtendedBolusFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.PROFILESWITCH)) {
MainApp.getDbHelper().createProfileSwitchFromJsonIfNotExists(activePlugin, nsUpload, json);
databaseHelper.createProfileSwitchFromJsonIfNotExists(activePlugin, nsUpload, json);
} else if (eventType.equals(CareportalEvent.SITECHANGE) ||
eventType.equals(CareportalEvent.INSULINCHANGE) ||
eventType.equals(CareportalEvent.SENSORCHANGE) ||
@ -446,7 +478,7 @@ public class NSClientPlugin extends PluginBase {
eventType.equals(CareportalEvent.EXERCISE) ||
eventType.equals(CareportalEvent.OPENAPSOFFLINE) ||
eventType.equals(CareportalEvent.PUMPBATTERYCHANGE)) {
MainApp.getDbHelper().createCareportalEventFromJsonIfNotExists(json);
databaseHelper.createCareportalEventFromJsonIfNotExists(json);
}
if (eventType.equals(CareportalEvent.ANNOUNCEMENT)) {
@ -468,7 +500,7 @@ public class NSClientPlugin extends PluginBase {
private void storeMbg(JSONObject mbgJson) {
NSMbg nsMbg = new NSMbg(mbgJson);
CareportalEvent careportalEvent = new CareportalEvent(nsMbg);
MainApp.getDbHelper().createOrUpdate(careportalEvent);
databaseHelper.createOrUpdate(careportalEvent);
aapsLogger.debug(LTag.DATASERVICE, "Adding/Updating new MBG: " + careportalEvent.toString());
}
}

View file

@ -18,6 +18,7 @@ import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.db.*
import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.interfaces.PluginBase
@ -27,7 +28,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.treatments.TreatmentsPlugin
import io.reactivex.rxkotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -36,6 +36,7 @@ import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.rxkotlin.plusAssign
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
@ -268,16 +269,15 @@ class OpenHumansUploader @Inject constructor(
}
@JvmOverloads
fun enqueueTempTarget(tempTarget: TempTarget?, deleted: Boolean = false) = tempTarget?.let {
fun enqueueTempTarget(tempTarget: TemporaryTarget?, deleted: Boolean = false) = tempTarget?.let {
insertQueueItem("TempTargets") {
put("date", tempTarget.date)
put("date", tempTarget.timestamp)
put("isValid", tempTarget.isValid)
put("source", tempTarget.source)
put("nsId", tempTarget._id)
put("low", tempTarget.low)
put("high", tempTarget.high)
put("nsId", tempTarget.interfaceIDs_backing?.nightscoutId)
put("low", tempTarget.lowTarget)
put("high", tempTarget.highTarget)
put("reason", tempTarget.reason)
put("durationInMinutes", tempTarget.durationInMinutes)
put("durationInMinutes", tempTarget.duration)
put("isDeletion", deleted)
}
}
@ -384,7 +384,7 @@ class OpenHumansUploader @Inject constructor(
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allTemporaryBasals) })
.map { enqueueTemporaryBasal(it); increaseCounter() }
.ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allTempTargets) })
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetTemporaryTargetData().blockingGet()) })
.map { enqueueTempTarget(it); increaseCounter() }
.ignoreElements()
.doOnSubscribe {

View file

@ -28,6 +28,10 @@ import info.nightscout.androidaps.Config
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.interfaces.end
import info.nightscout.androidaps.databinding.OverviewFragmentBinding
import info.nightscout.androidaps.dialogs.*
import info.nightscout.androidaps.events.*
@ -46,7 +50,6 @@ import info.nightscout.androidaps.plugins.general.overview.notifications.Notific
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.source.DexcomPlugin
@ -110,6 +113,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var databaseHelper: DatabaseHelperInterface
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var repository: AppRepository
private val disposable = CompositeDisposable()
@ -291,14 +295,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (childFragmentManager.isStateSaved) return
activity?.let { activity ->
when (v.id) {
R.id.treatment_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) TreatmentDialog().show(childFragmentManager, "Overview") })
R.id.wizard_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) WizardDialog().show(childFragmentManager, "Overview") })
R.id.insulin_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) InsulinDialog().show(childFragmentManager, "Overview") })
R.id.treatment_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) TreatmentDialog().show(childFragmentManager, "Overview") })
R.id.wizard_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) WizardDialog().show(childFragmentManager, "Overview") })
R.id.insulin_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) InsulinDialog().show(childFragmentManager, "Overview") })
R.id.quick_wizard_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) onClickQuickWizard() })
R.id.carbs_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) CarbsDialog().show(childFragmentManager, "Overview") })
R.id.temp_target -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) TempTargetDialog().show(childFragmentManager, "Overview") })
R.id.carbs_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) CarbsDialog().show(childFragmentManager, "Overview") })
R.id.temp_target -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) TempTargetDialog().show(childFragmentManager, "Overview") })
R.id.active_profile -> {
R.id.active_profile -> {
ProfileViewerDialog().also { pvd ->
pvd.arguments = Bundle().also {
it.putLong("time", DateUtil.now())
@ -307,7 +311,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}.show(childFragmentManager, "ProfileViewDialog")
}
R.id.cgm_button -> {
R.id.cgm_button -> {
if (xdripPlugin.isEnabled(PluginType.BGSOURCE))
openCgmApp("com.eveningoutpost.dexdrip")
else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) {
@ -318,7 +322,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
}
R.id.calibration_button -> {
R.id.calibration_button -> {
if (xdripPlugin.isEnabled(PluginType.BGSOURCE)) {
CalibrationDialog().show(childFragmentManager, "CalibrationDialog")
} else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) {
@ -333,7 +337,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
}
R.id.accept_temp_button -> {
R.id.accept_temp_button -> {
profileFunction.getProfile() ?: return
if (loopPlugin.isEnabled(PluginType.LOOP)) {
val lastRun = loopPlugin.lastRun
@ -353,7 +357,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
}
R.id.aps_mode -> {
R.id.aps_mode -> {
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
if (isAdded) LoopDialog().also { dialog ->
dialog.arguments = Bundle().also { it.putInt("showOkCancel", 1) }
@ -385,7 +389,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
return true
}
R.id.aps_mode -> {
R.id.aps_mode -> {
activity?.let { activity ->
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
LoopDialog().also { dialog ->
@ -395,8 +399,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
}
R.id.temp_target -> v.performClick()
R.id.active_profile -> activity?.let { activity -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { ProfileSwitchDialog().show(childFragmentManager, "Overview") }) }
R.id.temp_target -> v.performClick()
R.id.active_profile -> activity?.let { activity -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { ProfileSwitchDialog().show(childFragmentManager, "Overview") }) }
}
return false
@ -672,11 +676,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
// temp target
val tempTarget = treatmentsPlugin.tempTargetFromHistory
if (tempTarget != null) {
val tempTarget: ValueWrapper<TemporaryTarget> = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet()
if (tempTarget is ValueWrapper.Existing) {
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(tempTarget.low, tempTarget.high, Constants.MGDL, units) + " " + DateUtil.untilString(tempTarget.end(), resourceHelper)
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(tempTarget.value.lowTarget, tempTarget.value.highTarget, Constants.MGDL, units) + " " + DateUtil.untilString(tempTarget.value.end, resourceHelper)
} else {
// If the target is not the same as set in the profile then oref has overridden it
val targetUsed = lastRun?.constraintsProcessed?.targetBG ?: 0.0

View file

@ -15,6 +15,8 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.GlucoseValueDataPoint
import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.LoopInterface
@ -26,8 +28,10 @@ import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.extensions.target
import info.nightscout.androidaps.utils.resources.ResourceHelper
import java.util.*
import javax.inject.Inject
@ -40,7 +44,6 @@ class GraphData(
private val graph: GraphView,
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
private val treatmentsPlugin: TreatmentsInterface
) {
// IobCobCalculatorPlugin Cannot be injected: HistoryBrowser
@ -48,6 +51,8 @@ class GraphData(
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var repository: AppRepository
@Inject lateinit var dateUtil: DateUtil
var maxY = Double.MIN_VALUE
private var minY = Double.MAX_VALUE
@ -212,11 +217,11 @@ class GraphData(
lastRun?.constraintsProcessed?.let { toTime = max(it.latestPredictionsTime, toTime) }
var time = fromTime
while (time < toTime) {
val tt = treatmentsPlugin.getTempTargetFromHistory(time)
val value: Double = if (tt == null) {
Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, units)
val tt = repository.getTemporaryTargetActiveAt(time).blockingGet()
val value: Double = if (tt is ValueWrapper.Existing) {
Profile.fromMgdlToUnits(tt.value.target(), units)
} else {
Profile.fromMgdlToUnits(tt.target(), units)
Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, units)
}
if (lastTarget != value) {
if (lastTarget != -1.0) targetsSeriesArray.add(DataPoint(time.toDouble(), lastTarget))
@ -344,7 +349,8 @@ class GraphData(
time += 5 * 60 * 1000L
continue
}
val deviation = if (devBgiScale) iobCobCalculatorPlugin.getAutosensData(time)?.deviation ?:0.0 else 0.0
val deviation = if (devBgiScale) iobCobCalculatorPlugin.getAutosensData(time)?.deviation
?: 0.0 else 0.0
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
val bgi: Double = total.activity * profile.getIsfMgdl(time) * 5.0
@ -405,7 +411,7 @@ class GraphData(
if (showPrediction) {
val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("GraphData")
val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult()
val isTempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis()) != null
val isTempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet() is ValueWrapper.Existing
val iobPrediction: MutableList<DataPointWithLabelInterface> = ArrayList()
val iobPredictionArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
for (i in iobPredictionArray) {
@ -519,10 +525,10 @@ class GraphData(
while (time <= toTime) {
// if align Dev Scale with BGI scale, then calculate BGI value, else bgi = 0.0
val bgi: Double = if (devBgiScale) {
val profile = profileFunction.getProfile(time)
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
total.activity * (profile?.getIsfMgdl(time) ?: 0.0) * 5.0
} else 0.0
val profile = profileFunction.getProfile(time)
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
total.activity * (profile?.getIsfMgdl(time) ?: 0.0) * 5.0
} else 0.0
iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
var color = resourceHelper.gc(R.color.deviationblack) // "="

View file

@ -15,8 +15,11 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.interfaces.*
@ -26,6 +29,7 @@ import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
@ -46,6 +50,7 @@ import io.reactivex.rxkotlin.plusAssign
import org.apache.commons.lang3.StringUtils
import java.text.Normalizer
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.max
@ -70,7 +75,9 @@ class SmsCommunicatorPlugin @Inject constructor(
private var otp: OneTimePassword,
private val config: Config,
private val dateUtil: DateUtil,
private val uel: UserEntryLogger
private val uel: UserEntryLogger,
private val nsUpload: NSUpload,
private val repository: AppRepository
) : PluginBase(PluginDescription()
.mainType(PluginType.GENERAL)
.fragmentClass(SmsCommunicatorFragment::class.java.name)
@ -171,6 +178,7 @@ class SmsCommunicatorPlugin @Inject constructor(
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
@Suppress("SpellCheckingInspection")
override fun doWork(): Result {
val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1))
?: return Result.failure()
@ -237,58 +245,58 @@ class SmsCommunicatorPlugin @Inject constructor(
if (divided.isNotEmpty() && isCommand(divided[0].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber)) {
when (divided[0].toUpperCase(Locale.getDefault())) {
"BG" ->
"BG" ->
if (divided.size == 1) processBG(receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"LOOP" ->
"LOOP" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size == 2 || divided.size == 3) processLOOP(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"TREATMENTS" ->
if (divided.size == 2) processTREATMENTS(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"NSCLIENT" ->
"NSCLIENT" ->
if (divided.size == 2) processNSCLIENT(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"PUMP" ->
"PUMP" ->
if (!remoteCommandsAllowed && divided.size > 1) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size <= 3) processPUMP(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"PROFILE" ->
"PROFILE" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size == 2 || divided.size == 3) processPROFILE(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"BASAL" ->
"BASAL" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size == 2 || divided.size == 3) processBASAL(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"EXTENDED" ->
"EXTENDED" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size == 2 || divided.size == 3) processEXTENDED(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"BOLUS" ->
"BOLUS" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size == 2 && DateUtil.now() - lastRemoteBolusTime < minDistance) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotebolusnotallowed)))
else if (divided.size == 2 && pump.isSuspended()) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.pumpsuspended)))
else if (divided.size == 2 || divided.size == 3) processBOLUS(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"CARBS" ->
"CARBS" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size == 2 || divided.size == 3) processCARBS(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"CAL" ->
"CAL" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size == 2) processCAL(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"TARGET" ->
"TARGET" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size == 2) processTARGET(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"SMS" ->
"SMS" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size == 2) processSMS(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"HELP" ->
"HELP" ->
if (divided.size == 1 || divided.size == 2) processHELP(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else ->
@ -309,8 +317,8 @@ class SmsCommunicatorPlugin @Inject constructor(
if (actualBG != null) {
reply = resourceHelper.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsString(units) + ", "
} else if (lastBG != null) {
val agoMsec = System.currentTimeMillis() - lastBG.timestamp
val agoMin = (agoMsec / 60.0 / 1000.0).toInt()
val agoMilliseconds = System.currentTimeMillis() - lastBG.timestamp
val agoMin = (agoMilliseconds / 60.0 / 1000.0).toInt()
reply = resourceHelper.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsString(units) + " " + String.format(resourceHelper.gs(R.string.sms_minago), agoMin) + ", "
}
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
@ -372,7 +380,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
}
"STATUS" -> {
"STATUS" -> {
val reply = if (loopPlugin.isEnabled(PluginType.LOOP)) {
if (loopPlugin.isSuspended) String.format(resourceHelper.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend())
else resourceHelper.gs(R.string.smscommunicator_loopisenabled)
@ -382,7 +390,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
}
"RESUME" -> {
"RESUME" -> {
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopresumereplywithcode), passCode)
receivedSms.processed = true
@ -406,7 +414,7 @@ class SmsCommunicatorPlugin @Inject constructor(
})
}
"SUSPEND" -> {
"SUSPEND" -> {
var duration = 0
if (divided.size == 3) duration = SafeParse.stringToInt(divided[2])
duration = max(0, duration)
@ -572,23 +580,23 @@ class SmsCommunicatorPlugin @Inject constructor(
sendSMS(Sms(receivedSms.phoneNumber, reply))
}
} else {
val pindex = SafeParse.stringToInt(divided[1])
val pIndex = SafeParse.stringToInt(divided[1])
var percentage = 100
if (divided.size > 2) percentage = SafeParse.stringToInt(divided[2])
if (pindex > list.size) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
if (pIndex > list.size) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else if (percentage == 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else if (pindex == 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else if (pIndex == 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else {
val profile = store.getSpecificProfile(list[pindex - 1] as String)
val profile = store.getSpecificProfile(list[pIndex - 1] as String)
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.noprofile)))
else {
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_profilereplywithcode), list[pindex - 1], percentage, passCode)
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_profilereplywithcode), list[pIndex - 1], percentage, passCode)
receivedSms.processed = true
val finalPercentage = percentage
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(list[pindex - 1] as String, finalPercentage) {
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(list[pIndex - 1] as String, finalPercentage) {
override fun run() {
activePlugin.activeTreatments.doProfileSwitch(store, list[pindex - 1] as String, 0, finalPercentage, 0, DateUtil.now())
activePlugin.activeTreatments.doProfileSwitch(store, list[pIndex - 1] as String, 0, finalPercentage, 0, DateUtil.now())
val replyText = resourceHelper.gs(R.string.profileswitchcreated)
sendSMS(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS PROFILE", replyText)
@ -798,14 +806,18 @@ class SmsCommunicatorPlugin @Inject constructor(
currentProfile.units == Constants.MMOL -> Constants.defaultEatingSoonTTmmol
else -> Constants.defaultEatingSoonTTmgdl
}
val tempTarget = TempTarget()
.date(System.currentTimeMillis())
.duration(eatingSoonTTDuration)
.reason(resourceHelper.gs(R.string.eatingsoon))
.source(Source.USER)
.low(Profile.toMgdl(eatingSoonTT, currentProfile.units))
.high(Profile.toMgdl(eatingSoonTT, currentProfile.units))
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(eatingSoonTTDuration.toLong()),
reason = TemporaryTarget.Reason.EATING_SOON,
lowTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits()),
highTarget = Profile.toMgdl(eatingSoonTT, profileFunction.getUnits())
)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadTempTarget(it) }
result.updated.forEach { nsUpload.updateTempTarget(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it)
})
val tt = if (currentProfile.units == Constants.MMOL) {
DecimalFormatter.to1Decimal(eatingSoonTT)
} else DecimalFormatter.to0Decimal(eatingSoonTT)
@ -926,14 +938,18 @@ class SmsCommunicatorPlugin @Inject constructor(
var tt = sp.getDouble(keyTarget, if (units == Constants.MMOL) defaultTargetMMOL else defaultTargetMGDL)
tt = Profile.toCurrentUnits(profileFunction, tt)
tt = if (tt > 0) tt else if (units == Constants.MMOL) defaultTargetMMOL else defaultTargetMGDL
val tempTarget = TempTarget()
.date(System.currentTimeMillis())
.duration(ttDuration)
.reason(resourceHelper.gs(R.string.eatingsoon))
.source(Source.USER)
.low(Profile.toMgdl(tt, units))
.high(Profile.toMgdl(tt, units))
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(ttDuration.toLong()),
reason = TemporaryTarget.Reason.EATING_SOON,
lowTarget = Profile.toMgdl(tt, profileFunction.getUnits()),
highTarget = Profile.toMgdl(tt, profileFunction.getUnits())
)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadTempTarget(it) }
result.updated.forEach { nsUpload.updateTempTarget(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it)
})
val ttString = if (units == Constants.MMOL) DecimalFormatter.to1Decimal(tt) else DecimalFormatter.to0Decimal(tt)
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_tt_set), ttString, ttDuration)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
@ -946,13 +962,12 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
val tempTarget = TempTarget()
.source(Source.USER)
.date(DateUtil.now())
.duration(0)
.low(0.0)
.high(0.0)
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(dateUtil._now()))
.subscribe({ result ->
result.updated.forEach { nsUpload.updateTempTarget(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it)
})
val replyText = String.format(resourceHelper.gs(R.string.smscommunicator_tt_canceled))
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
uel.log("SMS TARGET", reply)

View file

@ -14,18 +14,26 @@ import info.nightscout.androidaps.danar.DanaRPlugin
import info.nightscout.androidaps.danars.DanaRSPlugin
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.interfaces.end
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TDD
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
@ -44,6 +52,7 @@ import java.text.DateFormat
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton
@ -51,6 +60,7 @@ import javax.inject.Singleton
class ActionStringHandler @Inject constructor(
private val sp: SP,
private val rxBus: RxBusWrapper,
private val aapsLogger: AAPSLogger,
aapsSchedulers: AapsSchedulers,
private val resourceHelper: ResourceHelper,
private val injector: HasAndroidInjector,
@ -72,7 +82,9 @@ class ActionStringHandler @Inject constructor(
private val hardLimits: HardLimits,
private val carbsGenerator: CarbsGenerator,
private val dateUtil: DateUtil,
private val config: Config
private val config: Config,
private val repository: AppRepository,
private val nsUpload: NSUpload
) {
private val TIMEOUT = 65 * 1000
@ -209,7 +221,10 @@ class ActionStringHandler @Inject constructor(
}
val format = DecimalFormat("0.00")
val formatInt = DecimalFormat("0")
val bolusWizard = BolusWizard(injector).doCalc(profile, profileName, activePlugin.activeTreatments.tempTargetFromHistory,
val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet()
val tempTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null
val bolusWizard = BolusWizard(injector).doCalc(profile, profileName, tempTarget,
carbsAfterConstraints, if (cobInfo.displayCob != null) cobInfo.displayCob!! else 0.0, bgReading.valueToUnits(profileFunction.getUnits()),
0.0, percentage.toDouble(), useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend, false)
if (Math.abs(bolusWizard.insulinAfterConstraints - bolusWizard.calculatedTotalInsulin) >= 0.01) {
@ -445,10 +460,10 @@ class ActionStringHandler @Inject constructor(
}
val profile = profileFunction.getProfile() ?: return "No profile set :("
//Check for Temp-Target:
val tempTarget = activePlugin.activeTreatments.tempTargetFromHistory
if (tempTarget != null) {
ret += "Temp Target: " + Profile.toTargetRangeString(tempTarget.low, tempTarget.low, Constants.MGDL, profileFunction.getUnits())
ret += "\nuntil: " + dateUtil.timeString(tempTarget.originalEnd())
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet()
if (tempTarget is ValueWrapper.Existing) {
ret += "Temp Target: " + Profile.toTargetRangeString(tempTarget.value.lowTarget, tempTarget.value.lowTarget, Constants.MGDL, profileFunction.getUnits())
ret += "\nuntil: " + dateUtil.timeString(tempTarget.value.end)
ret += "\n\n"
}
ret += "DEFAULT RANGE: "
@ -571,17 +586,26 @@ class ActionStringHandler @Inject constructor(
}
private fun generateTempTarget(duration: Int, low: Double, high: Double) {
val tempTarget = TempTarget()
.date(System.currentTimeMillis())
.duration(duration)
.reason("WearPlugin")
.source(Source.USER)
if (tempTarget.durationInMinutes != 0) {
tempTarget.low(low).high(high)
} else {
tempTarget.low(0.0).high(0.0)
}
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
if (duration != 0)
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(
timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
reason = TemporaryTarget.Reason.WEAR,
lowTarget = Profile.toMgdl(low, profileFunction.getUnits()),
highTarget = Profile.toMgdl(high, profileFunction.getUnits())
)).subscribe({ result ->
result.inserted.forEach { nsUpload.uploadTempTarget(it) }
result.updated.forEach { nsUpload.updateTempTarget(it) }
}, {
aapsLogger.error("Error while saving temporary target", it)
})
else
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(System.currentTimeMillis()))
.subscribe({ result ->
result.updated.forEach { nsUpload.updateTempTarget(it) }
}, {
aapsLogger.error("Error while saving temporary target", it)
})
}
private fun doFillBolus(amount: Double) {

View file

@ -6,7 +6,10 @@ import android.os.SystemClock
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.ValueWrapper
import info.nightscout.androidaps.events.Event
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
@ -17,13 +20,13 @@ import info.nightscout.androidaps.plugins.general.overview.notifications.Notific
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin.Companion.roundUpTime
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensBgLoaded
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.target
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import java.util.*
@ -56,6 +59,7 @@ class IobCobOref1Thread internal constructor(
@Inject lateinit var profiler: Profiler
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var repository: AppRepository
private var mWakeLock: PowerManager.WakeLock? = null
@ -292,9 +296,9 @@ class IobCobOref1Thread internal constructor(
// TODO AS-FIX
@Suppress("SimplifyBooleanWithConstants")
if (false && sp.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity)) {
val tempTarget = treatmentsPlugin.getTempTargetFromHistory(bgTime)
if (tempTarget != null && tempTarget.target() >= 100) {
autosensData.extraDeviation.add(-(tempTarget.target() - 100) / 20)
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet()
if (tempTarget is ValueWrapper.Existing && tempTarget.value.target() >= 100) {
autosensData.extraDeviation.add(-(tempTarget.value.target() - 100) / 20)
}
}

View file

@ -290,7 +290,7 @@ class VirtualPumpPlugin @Inject constructor(
override fun cancelExtendedBolus(): PumpEnactResult {
val result = PumpEnactResult(injector)
if (treatmentsPlugin.isInHistoryExtendedBoluslInProgress) {
if (treatmentsPlugin.isInHistoryExtendedBolusInProgress) {
val exStop = ExtendedBolus(injector, System.currentTimeMillis())
exStop.source = Source.USER
treatmentsPlugin.addToHistoryExtendedBolus(exStop)

View file

@ -149,7 +149,7 @@ class DexcomPlugin @Inject constructor(
}
}
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Dexcom App", it)
aapsLogger.error("Error while saving values from Dexcom App", it)
})
} catch (e: Exception) {
aapsLogger.error("Error while processing intent from Dexcom App", e)

View file

@ -125,7 +125,7 @@ class EversensePlugin @Inject constructor(
nsUpload.uploadBg(it, GlucoseValue.SourceSensor.EVERSENSE.text)
}
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Eversense App", it)
aapsLogger.error("Error while saving values from Eversense App", it)
})
}
}
@ -147,7 +147,7 @@ class EversensePlugin @Inject constructor(
data.put("glucoseType", "Finger")
data.put("glucose", calibrationGlucoseLevels[i])
data.put("units", Constants.MGDL)
nsUpload.uploadCareportalEntryToNS(data)
nsUpload.uploadCareportalEntryToNS(data, calibrationTimestamps[i])
}
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)

View file

@ -82,7 +82,7 @@ class GlimpPlugin @Inject constructor(
nsUpload.uploadBg(it, GlucoseValue.SourceSensor.GLIMP.text)
}
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Glimp App", it)
aapsLogger.error("Error while saving values from Glimp App", it)
})
return Result.success()
}

View file

@ -100,7 +100,7 @@ class MM640gPlugin @Inject constructor(
nsUpload.uploadBg(it, GlucoseValue.SourceSensor.MM_600_SERIES.text)
}
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Eversense App", it)
aapsLogger.error("Error while saving values from Eversense App", it)
})
} catch (e: JSONException) {
aapsLogger.error("Exception: ", e)

View file

@ -139,7 +139,7 @@ class NSClientSourcePlugin @Inject constructor(
nsClientSourcePlugin.detectSource(it)
}
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from NSClient App", it)
aapsLogger.error("Error while saving values from NSClient App", it)
})
} catch (e: Exception) {
aapsLogger.error("Unhandled exception", e)

View file

@ -93,7 +93,7 @@ class PoctechPlugin @Inject constructor(
nsUpload.uploadBg(it, GlucoseValue.SourceSensor.POCTECH_NATIVE.text)
}
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Poctech App", it)
aapsLogger.error("Error while saving values from Poctech App", it)
})
} catch (e: JSONException) {
aapsLogger.error("Exception: ", e)

View file

@ -82,7 +82,7 @@ class TomatoPlugin @Inject constructor(
nsUpload.uploadBg(it, GlucoseValue.SourceSensor.LIBRE_1_TOMATO.text)
}
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving values from Tomato App", it)
aapsLogger.error("Error while saving values from Tomato App", it)
})
return Result.success()
}

View file

@ -8,8 +8,6 @@ import androidx.annotation.Nullable;
import com.google.firebase.analytics.FirebaseAnalytics;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
@ -18,7 +16,6 @@ import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.activities.ErrorHelperActivity;
import info.nightscout.androidaps.data.DetailedBolusInfo;
@ -26,20 +23,19 @@ import info.nightscout.androidaps.data.Intervals;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.NonOverlappingIntervals;
import info.nightscout.androidaps.data.OverlappingIntervals;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileIntervals;
import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventReloadProfileSwitchData;
import info.nightscout.androidaps.events.EventReloadTempBasalData;
import info.nightscout.androidaps.events.EventReloadTreatmentData;
import info.nightscout.androidaps.events.EventTempTargetChange;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
@ -81,6 +77,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
private final UploadQueue uploadQueue;
private final FabricPrivacy fabricPrivacy;
private final DateUtil dateUtil;
private final DatabaseHelperInterface databaseHelper;
private final AppRepository repository;
private final CompositeDisposable disposable = new CompositeDisposable();
@ -92,7 +90,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
private final ArrayList<Treatment> treatments = new ArrayList<>();
private final Intervals<TemporaryBasal> tempBasals = new NonOverlappingIntervals<>();
private final Intervals<ExtendedBolus> extendedBoluses = new NonOverlappingIntervals<>();
private final Intervals<TempTarget> tempTargets = new OverlappingIntervals<>();
private final ProfileIntervals<ProfileSwitch> profiles = new ProfileIntervals<>();
@Inject
@ -109,7 +106,9 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
NSUpload nsUpload,
FabricPrivacy fabricPrivacy,
DateUtil dateUtil,
UploadQueue uploadQueue
UploadQueue uploadQueue,
DatabaseHelperInterface databaseHelper,
AppRepository repository
) {
super(new PluginDescription()
.mainType(PluginType.TREATMENT)
@ -133,6 +132,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
this.dateUtil = dateUtil;
this.nsUpload = nsUpload;
this.uploadQueue = uploadQueue;
this.databaseHelper = databaseHelper;
this.repository = repository;
}
@Override
@ -158,12 +159,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
.subscribe(event -> initializeProfileSwitchData(range()),
fabricPrivacy::logException
));
disposable.add(rxBus
.toObservable(EventTempTargetChange.class)
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> initializeTempTargetData(range()),
fabricPrivacy::logException
));
disposable.add(rxBus
.toObservable(EventReloadTempBasalData.class)
.observeOn(aapsSchedulers.getIo())
@ -198,7 +193,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
initializeTempBasalData(range);
initializeTreatmentData(range);
initializeExtendedBolusData(range);
initializeTempTargetData(range);
initializeProfileSwitchData(range);
}
@ -213,7 +207,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
private void initializeTempBasalData(long range) {
getAapsLogger().debug(LTag.DATATREATMENTS, "initializeTempBasalData");
synchronized (tempBasals) {
tempBasals.reset().add(MainApp.getDbHelper().getTemporaryBasalsDataFromTime(DateUtil.now() - range, false));
tempBasals.reset().add(databaseHelper.getTemporaryBasalsDataFromTime(DateUtil.now() - range, false));
}
}
@ -221,22 +215,15 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
private void initializeExtendedBolusData(long range) {
getAapsLogger().debug(LTag.DATATREATMENTS, "initializeExtendedBolusData");
synchronized (extendedBoluses) {
extendedBoluses.reset().add(MainApp.getDbHelper().getExtendedBolusDataFromTime(DateUtil.now() - range, false));
extendedBoluses.reset().add(databaseHelper.getExtendedBolusDataFromTime(DateUtil.now() - range, false));
}
}
private void initializeTempTargetData(long range) {
getAapsLogger().debug(LTag.DATATREATMENTS, "initializeTempTargetData");
synchronized (tempTargets) {
tempTargets.reset().add(MainApp.getDbHelper().getTemptargetsDataFromTime(DateUtil.now() - range, false));
}
}
private void initializeProfileSwitchData(long range) {
getAapsLogger().debug(LTag.DATATREATMENTS, "initializeProfileSwitchData");
synchronized (profiles) {
profiles.reset().add(MainApp.getDbHelper().getProfileSwitchData(DateUtil.now() - range, false));
profiles.reset().add(databaseHelper.getProfileSwitchData(DateUtil.now() - range, false));
}
}
@ -401,11 +388,11 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
} else {
uploadQueue.removeID("dbAdd", tempBasalId);
}
MainApp.getDbHelper().delete(tempBasal);
databaseHelper.delete(tempBasal);
}
@Override
public boolean isInHistoryExtendedBoluslInProgress() {
public boolean isInHistoryExtendedBolusInProgress() {
return getExtendedBolusFromHistory(System.currentTimeMillis()) != null; //TODO: crosscheck here
}
@ -425,7 +412,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
PumpInterface pumpInterface = activePlugin.getActivePump();
synchronized (tempBasals) {
for (Integer pos = 0; pos < tempBasals.size(); pos++) {
for (int pos = 0; pos < tempBasals.size(); pos++) {
TemporaryBasal t = tempBasals.get(pos);
if (t.date > time) continue;
IobTotal calc;
@ -576,7 +563,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
@Override
public boolean addToHistoryExtendedBolus(ExtendedBolus extendedBolus) {
//log.debug("Adding new ExtentedBolus record" + extendedBolus.log());
boolean newRecordCreated = MainApp.getDbHelper().createOrUpdate(extendedBolus);
boolean newRecordCreated = databaseHelper.createOrUpdate(extendedBolus);
if (newRecordCreated) {
if (extendedBolus.durationInMinutes == 0) {
if (activePlugin.getActivePump().isFakingTempsByExtendedBoluses())
@ -610,7 +597,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
@Override
public boolean addToHistoryTempBasal(TemporaryBasal tempBasal) {
//log.debug("Adding new TemporaryBasal record" + tempBasal.toString());
boolean newRecordCreated = MainApp.getDbHelper().createOrUpdate(tempBasal);
boolean newRecordCreated = databaseHelper.createOrUpdate(tempBasal);
if (newRecordCreated) {
if (tempBasal.durationInMinutes == 0)
nsUpload.uploadTempBasalEnd(tempBasal.date, false, tempBasal.pumpId);
@ -711,36 +698,6 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
return oldestTime;
}
@Nullable
@Override
public TempTarget getTempTargetFromHistory() {
synchronized (tempTargets) {
return tempTargets.getValueByInterval(System.currentTimeMillis());
}
}
@Nullable
@Override
public TempTarget getTempTargetFromHistory(long time) {
synchronized (tempTargets) {
return tempTargets.getValueByInterval(time);
}
}
@Override
public Intervals<TempTarget> getTempTargetsFromHistory() {
synchronized (tempTargets) {
return new OverlappingIntervals<>(tempTargets);
}
}
@Override
public void addToHistoryTempTarget(TempTarget tempTarget) {
//log.debug("Adding new TemporaryBasal record" + profileSwitch.log());
MainApp.getDbHelper().createOrUpdate(tempTarget);
nsUpload.uploadTempTarget(tempTarget, profileFunction);
}
@Override
@Nullable
public ProfileSwitch getProfileSwitchFromHistory(long time) {
@ -760,8 +717,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
public void addToHistoryProfileSwitch(ProfileSwitch profileSwitch) {
//log.debug("Adding new TemporaryBasal record" + profileSwitch.log());
rxBus.send(new EventDismissNotification(Notification.PROFILE_SWITCH_MISSING));
MainApp.getDbHelper().createOrUpdate(profileSwitch);
nsUpload.uploadProfileSwitch(profileSwitch);
databaseHelper.createOrUpdate(profileSwitch);
nsUpload.uploadProfileSwitch(profileSwitch, profileSwitch.date);
}
@Override

View file

@ -0,0 +1,5 @@
package info.nightscout.androidaps.plugins.treatments.events
import info.nightscout.androidaps.events.EventUpdateGui
class EventTreatmentUpdateGui : EventUpdateGui()

View file

@ -10,37 +10,49 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Intervals
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.interfaces.end
import info.nightscout.androidaps.database.transactions.InvalidateTemporaryTargetTransaction
import info.nightscout.androidaps.databinding.TreatmentsTemptargetFragmentBinding
import info.nightscout.androidaps.databinding.TreatmentsTemptargetItemBinding
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.events.EventTempTargetChange
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction
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.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
import info.nightscout.androidaps.plugins.treatments.events.EventTreatmentUpdateGui
import info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.friendlyDescription
import info.nightscout.androidaps.utils.extensions.highValueToUnitsToString
import info.nightscout.androidaps.utils.extensions.lowValueToUnitsToString
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.Completable
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import io.reactivex.rxkotlin.subscribeBy
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class TreatmentsTempTargetFragment : DaggerFragment() {
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var sp: SP
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var nsUpload: NSUpload
@ -50,9 +62,12 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
@Inject lateinit var buildHelper: BuildHelper
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var repository: AppRepository
private val disposable = CompositeDisposable()
private val millsToThePast = T.days(30).msecs()
private var _binding: TreatmentsTemptargetFragmentBinding? = null
// This property is only valid between onCreateView and
@ -65,29 +80,59 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.recyclerview.setHasFixedSize(true)
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
binding.recyclerview.adapter = RecyclerViewAdapter(activePlugin.activeTreatments.tempTargetsFromHistory)
binding.refreshFromNightscout.setOnClickListener {
context?.let { context ->
OKDialog.showConfirmation(context, resourceHelper.gs(R.string.refresheventsfromnightscout) + " ?", {
uel.log("TT NS REFRESH")
MainApp.getDbHelper().resetTempTargets()
disposable += Completable.fromAction { repository.deleteAllTempTargetEntries() }
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.main)
.subscribeBy(
onError = { aapsLogger.error("Error removing entries", it) },
onComplete = { rxBus.send(EventTempTargetChange()) }
)
rxBus.send(EventNSClientRestart())
})
}
}
val nsUploadOnly = sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode()
if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.GONE
if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.INVISIBLE
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
rxBus.send(EventTreatmentUpdateGui())
}
}
fun swapAdapter() {
val now = System.currentTimeMillis()
if (binding.showInvalidated.isChecked)
repository
.getTemporaryTargetDataIncludingInvalidFromTime(now - millsToThePast, false)
.observeOn(aapsSchedulers.main)
.subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) }
else
repository
.getTemporaryTargetDataFromTime(now - millsToThePast, false)
.observeOn(aapsSchedulers.main)
.subscribe { list -> binding.recyclerview.swapAdapter(RecyclerViewAdapter(list), true) }
}
@Synchronized
override fun onResume() {
super.onResume()
disposable.add(rxBus
swapAdapter()
disposable += rxBus
.toObservable(EventTempTargetChange::class.java)
.observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException)
)
updateGui()
.observeOn(aapsSchedulers.io)
.debounce(1L, TimeUnit.SECONDS)
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above
.observeOn(aapsSchedulers.io)
.debounce(1L, TimeUnit.SECONDS)
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
}
@Synchronized
@ -99,17 +144,14 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
binding.recyclerview.adapter = null // avoid leaks
_binding = null
}
private fun updateGui() {
if (_binding == null) return
binding.recyclerview.swapAdapter(RecyclerViewAdapter(activePlugin.activeTreatments.tempTargetsFromHistory), false)
}
inner class RecyclerViewAdapter internal constructor(private var tempTargetList: List<TemporaryTarget>) : RecyclerView.Adapter<TempTargetsViewHolder>() {
inner class RecyclerViewAdapter internal constructor(var tempTargetList: Intervals<TempTarget>) : RecyclerView.Adapter<TempTargetsViewHolder>() {
var currentlyActiveTarget: TempTarget? = tempTargetList.getValueByInterval(System.currentTimeMillis())
private val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet()
private val currentlyActiveTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): TempTargetsViewHolder =
TempTargetsViewHolder(LayoutInflater.from(viewGroup.context).inflate(R.layout.treatments_temptarget_item, viewGroup, false))
@ -117,35 +159,25 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: TempTargetsViewHolder, position: Int) {
val units = profileFunction.getUnits()
val tempTarget = tempTargetList.getReversed(position)
holder.binding.ph.visibility = if (tempTarget.source == Source.PUMP) View.VISIBLE else View.GONE
holder.binding.ns.visibility = if (NSUpload.isIdValid(tempTarget._id)) View.VISIBLE else View.GONE
if (!tempTarget.isEndingEvent) {
holder.binding.date.text = dateUtil.dateAndTimeString(tempTarget.date) + " - " + dateUtil.timeString(tempTarget.originalEnd())
holder.binding.duration.text = resourceHelper.gs(R.string.format_mins, tempTarget.durationInMinutes)
holder.binding.low.text = tempTarget.lowValueToUnitsToString(units)
holder.binding.high.text = tempTarget.highValueToUnitsToString(units)
holder.binding.reason.text = tempTarget.reason
} else {
holder.binding.date.text = dateUtil.dateAndTimeString(tempTarget.date)
holder.binding.duration.setText(R.string.cancel)
holder.binding.low.text = ""
holder.binding.high.text = ""
holder.binding.reason.text = ""
holder.binding.reasonLabel.text = ""
holder.binding.reasonColon.text = ""
}
if (tempTarget.isInProgress && tempTarget === currentlyActiveTarget) {
holder.binding.date.setTextColor(resourceHelper.gc(R.color.colorActive))
} else if (tempTarget.date > DateUtil.now()) {
holder.binding.date.setTextColor(resourceHelper.gc(R.color.colorScheduled))
} else {
holder.binding.date.setTextColor(holder.binding.reasonColon.currentTextColor)
}
val tempTarget = tempTargetList[position]
holder.binding.ns.visibility = (tempTarget.interfaceIDs.nightscoutId != null).toVisibility()
holder.binding.invalid.visibility = tempTarget.isValid.not().toVisibility()
holder.binding.remove.visibility = tempTarget.isValid.toVisibility()
holder.binding.date.text = dateUtil.dateAndTimeString(tempTarget.timestamp) + " - " + dateUtil.timeString(tempTarget.end)
holder.binding.duration.text = resourceHelper.gs(R.string.format_mins, T.msecs(tempTarget.duration).mins())
holder.binding.low.text = tempTarget.lowValueToUnitsToString(units)
holder.binding.high.text = tempTarget.highValueToUnitsToString(units)
holder.binding.reason.text = tempTarget.reason.text
holder.binding.date.setTextColor(
when {
tempTarget.id == currentlyActiveTarget?.id -> resourceHelper.gc(R.color.colorActive)
tempTarget.timestamp > DateUtil.now() -> resourceHelper.gc(R.color.colorScheduled)
else -> holder.binding.reasonColon.currentTextColor
})
holder.binding.remove.tag = tempTarget
}
override fun getItemCount(): Int = tempTargetList.size()
override fun getItemCount(): Int = tempTargetList.size
inner class TempTargetsViewHolder(view: View) : RecyclerView.ViewHolder(view) {
@ -153,20 +185,23 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
init {
binding.remove.setOnClickListener { v: View ->
val tempTarget = v.tag as TempTarget
val tempTarget = v.tag as TemporaryTarget
context?.let { context ->
OKDialog.showConfirmation(context, resourceHelper.gs(R.string.removerecord),
"""
${resourceHelper.gs(R.string.careportal_temporarytarget)}: ${tempTarget.friendlyDescription(profileFunction.getUnits(), resourceHelper)}
${dateUtil.dateAndTimeString(tempTarget.date)}
${dateUtil.dateAndTimeString(tempTarget.timestamp)}
""".trimIndent(),
{ _: DialogInterface?, _: Int ->
uel.log("TT REMOVE", tempTarget.friendlyDescription(profileFunction.getUnits(), resourceHelper))
val id = tempTarget._id
if (NSUpload.isIdValid(id)) nsUpload.removeCareportalEntryFromNS(id)
else uploadQueue.removeID("dbAdd", id)
MainApp.getDbHelper().delete(tempTarget)
disposable += repository.runTransactionForResult(InvalidateTemporaryTargetTransaction(tempTarget.id))
.subscribe({
val id = tempTarget.interfaceIDs.nightscoutId
if (NSUpload.isIdValid(id)) nsUpload.removeCareportalEntryFromNS(id)
else uploadQueue.removeID("dbAdd", tempTarget.timestamp.toString())
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while invalidating temporary target", it)
})
}, null)
}
}

View file

@ -5,8 +5,10 @@ import android.text.Spanned
import android.util.LongSparseArray
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.db.TDD
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
@ -31,15 +33,17 @@ class TddCalculator @Inject constructor(
rxBus: RxBusWrapper,
resourceHelper: ResourceHelper,
context: Context,
private val aapsSchedulers: AapsSchedulers,
private val sp: SP,
aapsSchedulers: AapsSchedulers,
sp: SP,
private val activePlugin: ActivePluginProvider,
private val profileFunction: ProfileFunction,
fabricPrivacy: FabricPrivacy,
nsUpload: NSUpload,
private val dateUtil: DateUtil,
uploadQueue: UploadQueue
) : TreatmentsPlugin(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, context, sp, profileFunction, activePlugin, nsUpload, fabricPrivacy, dateUtil, uploadQueue) {
uploadQueue: UploadQueue,
databaseHelper: DatabaseHelperInterface,
repository: AppRepository
) : TreatmentsPlugin(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, context, sp, profileFunction, activePlugin, nsUpload, fabricPrivacy, dateUtil, uploadQueue, databaseHelper, repository) {
init {
service = TreatmentService(injector) // plugin is not started
@ -113,6 +117,7 @@ class TddCalculator @Inject constructor(
)
}
@Suppress("SameParameterValue")
private fun toText(tdds: LongSparseArray<TDD>, includeCarbs: Boolean): String {
var t = ""
for (i in 0 until tdds.size()) {

View file

@ -10,9 +10,9 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.events.EventRefreshOverview
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
@ -106,7 +106,7 @@ class BolusWizard @Inject constructor(
// Input
lateinit var profile: Profile
lateinit var profileName: String
var tempTarget: TempTarget? = null
var tempTarget: TemporaryTarget? = null
var carbs: Int = 0
var cob: Double = 0.0
var bg: Double = 0.0
@ -126,7 +126,7 @@ class BolusWizard @Inject constructor(
@JvmOverloads
fun doCalc(profile: Profile,
profileName: String,
tempTarget: TempTarget?,
tempTarget: TemporaryTarget?,
carbs: Int,
cob: Double,
bg: Double,
@ -168,8 +168,8 @@ class BolusWizard @Inject constructor(
targetBGLow = Profile.fromMgdlToUnits(profile.targetLowMgdl, profileFunction.getUnits())
targetBGHigh = Profile.fromMgdlToUnits(profile.targetHighMgdl, profileFunction.getUnits())
if (useTT && tempTarget != null) {
targetBGLow = Profile.fromMgdlToUnits(tempTarget.low, profileFunction.getUnits())
targetBGHigh = Profile.fromMgdlToUnits(tempTarget.high, profileFunction.getUnits())
targetBGLow = Profile.fromMgdlToUnits(tempTarget.lowTarget, profileFunction.getUnits())
targetBGHigh = Profile.fromMgdlToUnits(tempTarget.highTarget, profileFunction.getUnits())
}
if (useBg && bg > 0) {
bgDiff = when {

View file

@ -3,6 +3,8 @@ package info.nightscout.androidaps.utils.wizard
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger
@ -28,11 +30,14 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
@Inject lateinit var repository: AppRepository
@Inject lateinit var dateUtil: DateUtil
lateinit var storage: JSONObject
var position: Int = -1
companion object {
const val YES = 0
const val NO = 1
private const val POSITIVE_ONLY = 2
@ -73,7 +78,8 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
fun isActive(): Boolean = Profile.secondsFromMidnight() >= validFrom() && Profile.secondsFromMidnight() <= validTo()
fun doCalc(profile: Profile, profileName: String, lastBG: GlucoseValue, _synchronized: Boolean): BolusWizard {
val tempTarget = treatmentsPlugin.tempTargetFromHistory
val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet()
val tempTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null
//BG
var bg = 0.0
if (useBG() == YES) {
@ -131,7 +137,7 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
fun validFrom(): Int = safeGetInt(storage, "validFrom")
fun validTo(): Int = safeGetInt(storage, "validTo")
private fun validTo(): Int = safeGetInt(storage, "validTo")
fun useBG(): Int = safeGetInt(storage, "useBG", YES)

View file

@ -1,18 +1,45 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="info.nightscout.androidaps.plugins.treatments.fragments.TreatmentsTempTargetFragment">
<info.nightscout.androidaps.utils.ui.SingleClickButton
android:id="@+id/refresh_from_nightscout"
style="?android:attr/buttonStyle"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:drawableStart="@drawable/ic_refresh"
android:text="@string/refresheventsfromnightscout" />
android:orientation="horizontal">
<info.nightscout.androidaps.utils.ui.SingleClickButton
android:id="@+id/refresh_from_nightscout"
style="?android:attr/buttonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:drawableStart="@drawable/ic_refresh"
android:text="@string/refresheventsfromnightscout"
tools:visibility="visible" />
<CheckBox
android:id="@+id/show_invalidated"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:checked="false"
android:paddingEnd="5dp"
tools:ignore="RtlSymmetry" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/show_calculation"
app:srcCompat="@drawable/ic_visibility" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"

View file

@ -80,15 +80,6 @@
android:layout_weight="1"
android:text="" />
<TextView
android:id="@+id/ph"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:text="PH"
android:textColor="@color/colorSetTempButton"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/ns"
android:layout_width="wrap_content"
@ -134,6 +125,15 @@
android:textStyle="bold"
tools:ignore="HardcodedText,RtlSymmetry" />
<TextView
android:id="@+id/invalid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:text="@string/invalid"
android:textColor="@android:color/holo_red_light" />
<TextView
android:id="@+id/remove"
android:layout_width="wrap_content"
@ -148,10 +148,10 @@
<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:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:background="@color/list_delimiter" />
</LinearLayout>

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.data
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import org.junit.Assert
@ -13,16 +12,16 @@ import java.util.*
class OverlappingIntervalsTest {
private val startDate = DateUtil.now()
var list = OverlappingIntervals<TempTarget>()
private var list = OverlappingIntervals<TempTargetTest>()
@Test fun doTests() {
// create one 10h interval and test value in and out
list.add(TempTarget().date(startDate).duration(T.hours(10).mins().toInt()).low(100.0).high(100.0))
list.add(TempTargetTest().date(startDate).duration(T.hours(10).mins()).low(100.0).high(100.0))
Assert.assertEquals(null, list.getValueByInterval(startDate - T.secs(1).msecs()))
Assert.assertEquals(100.0, list.getValueByInterval(startDate)!!.target(), 0.01)
Assert.assertEquals(null, list.getValueByInterval(startDate + T.hours(10).msecs() + 1))
// stop temp target after 5h
list.add(TempTarget().date(startDate + T.hours(5).msecs()).duration(0))
list.add(TempTargetTest().date(startDate + T.hours(5).msecs()).duration(0))
Assert.assertEquals(null, list.getValueByInterval(startDate - T.secs(1).msecs()))
Assert.assertEquals(100.0, list.getValueByInterval(startDate)!!.target(), 0.01)
Assert.assertEquals(100.0, list.getValueByInterval(startDate + T.hours(5).msecs() - 1)!!.target(), 0.01)
@ -30,7 +29,7 @@ class OverlappingIntervalsTest {
Assert.assertEquals(null, list.getValueByInterval(startDate + T.hours(10).msecs() + 1))
// insert 1h interval inside
list.add(TempTarget().date(startDate + T.hours(3).msecs()).duration(T.hours(1).mins().toInt()).low(200.0).high(200.0))
list.add(TempTargetTest().date(startDate + T.hours(3).msecs()).duration(T.hours(1).mins()).low(200.0).high(200.0))
Assert.assertEquals(null, list.getValueByInterval(startDate - T.secs(1).msecs()))
Assert.assertEquals(100.0, list.getValueByInterval(startDate)!!.target(), 0.01)
Assert.assertEquals(100.0, list.getValueByInterval(startDate + T.hours(5).msecs() - 1)!!.target(), 0.01)
@ -42,19 +41,19 @@ class OverlappingIntervalsTest {
@Test fun testCopyConstructor() {
list.reset()
list.add(TempTarget().date(startDate).duration(T.hours(10).mins().toInt()).low(100.0).high(100.0))
list.add(TempTargetTest().date(startDate).duration(T.hours(10).mins()).low(100.0).high(100.0))
val list2 = OverlappingIntervals(list)
Assert.assertEquals(1, list2.list.size.toLong())
}
@Test fun testReversingArrays() {
val someList: MutableList<TempTarget> = ArrayList()
someList.add(TempTarget().date(startDate).duration(T.hours(3).mins().toInt()).low(200.0).high(200.0))
someList.add(TempTarget().date(startDate + T.hours(1).msecs()).duration(T.hours(1).mins().toInt()).low(100.0).high(100.0))
val someList: MutableList<TempTargetTest> = ArrayList()
someList.add(TempTargetTest().date(startDate).duration(T.hours(3).mins()).low(200.0).high(200.0))
someList.add(TempTargetTest().date(startDate + T.hours(1).msecs()).duration(T.hours(1).mins()).low(100.0).high(100.0))
list.reset()
list.add(someList)
Assert.assertEquals(startDate, list[0].date)
Assert.assertEquals(startDate + T.hours(1).msecs(), list.getReversed(0).date)
Assert.assertEquals(startDate + T.hours(1).msecs(), list.reversedList[0].date)
Assert.assertEquals(startDate, list[0].data.timestamp)
Assert.assertEquals(startDate + T.hours(1).msecs(), list.getReversed(0).data.timestamp)
Assert.assertEquals(startDate + T.hours(1).msecs(), list.reversedList[0].data.timestamp)
}
}

View file

@ -0,0 +1,83 @@
package info.nightscout.androidaps.data
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.interfaces.end
import info.nightscout.androidaps.interfaces.Interval
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import java.util.concurrent.TimeUnit
class TempTargetTest(
var data: TemporaryTarget = TemporaryTarget(
timestamp = 0,
utcOffset = 0,
reason = TemporaryTarget.Reason.CUSTOM,
highTarget = 0.0,
lowTarget = 0.0,
duration = 0
)
) : Interval {
fun date(timestamp: Long): TempTargetTest {
data.timestamp = timestamp
return this
}
fun duration(duration: Long): TempTargetTest {
data.duration = T.mins(duration).msecs()
return this
}
fun low(low: Double): TempTargetTest {
data.lowTarget = low
return this
}
fun high(high: Double): TempTargetTest {
data.highTarget = high
return this
}
fun target(): Double {
return (data.lowTarget + data.highTarget) / 2
}
// -------- Interval interface ---------
private var cuttedEnd: Long? = null
override fun durationInMsec(): Long = data.duration
override fun start(): Long = data.timestamp
override fun originalEnd(): Long = data.end // planned end time at time of creation
override fun end(): Long = cuttedEnd ?: originalEnd() // end time after cut
override fun cutEndTo(end: Long) {
cuttedEnd = end
}
override fun match(time: Long): Boolean = start() <= time && end() >= time
override fun before(time: Long): Boolean = end() < time
override fun after(time: Long): Boolean = start() > time
override fun isInProgress(): Boolean = match(System.currentTimeMillis())
override fun isEndingEvent(): Boolean = data.duration == 0L
override fun isValid(): Boolean = true
// -------- Interval interface end ---------
fun lowValueToUnitsToString(units: String): String =
if (units == Constants.MGDL) DecimalFormatter.to0Decimal(data.lowTarget)
else DecimalFormatter.to1Decimal(data.lowTarget * Constants.MGDL_TO_MMOLL)
fun highValueToUnitsToString(units: String): String =
if (units == Constants.MGDL) DecimalFormatter.to0Decimal(data.highTarget)
else DecimalFormatter.to1Decimal(data.highTarget * Constants.MGDL_TO_MMOLL)
override fun toString(): String = data.toString()
fun friendlyDescription(units: String, resourceHelper: ResourceHelper): String =
Profile.toTargetRangeString(data.lowTarget, data.highTarget, Constants.MGDL, units) +
units +
"@" + resourceHelper.gs(R.string.format_mins, TimeUnit.MILLISECONDS.toMinutes(data.duration)) + "(" + data.reason.text + ")"
}

View file

@ -10,6 +10,7 @@ import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.dana.DanaPump
import info.nightscout.androidaps.danar.DanaRPlugin
import info.nightscout.androidaps.danars.DanaRSPlugin
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
@ -52,7 +53,7 @@ import java.util.*
MainApp::class, ConfigBuilderPlugin::class, ConstraintChecker::class, SP::class, Context::class,
OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class,
VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, GlimpPlugin::class, Profiler::class,
UserEntryLogger::class, IobCobCalculatorPlugin::class, LoggerUtils::class)
UserEntryLogger::class, IobCobCalculatorPlugin::class, LoggerUtils::class, AppRepository::class)
class ConstraintsCheckerTest : TestBaseWithProfile() {
@Mock lateinit var activePlugin: ActivePluginProvider
@ -70,6 +71,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
@Mock lateinit var uel: UserEntryLogger
@Mock lateinit var loggerUtils: LoggerUtils
@Mock lateinit var databaseHelper: DatabaseHelperInterface
@Mock lateinit var repository: AppRepository
private lateinit var danaPump: DanaPump
@ -128,8 +130,8 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
danaRPlugin = DanaRPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, activePlugin, sp, commandQueue, danaPump, dateUtil, fabricPrivacy)
danaRSPlugin = DanaRSPlugin(injector, aapsLogger, aapsSchedulers, rxBus, context, resourceHelper, constraintChecker, profileFunction, activePluginProvider, sp, commandQueue, danaPump, detailedBolusInfoStorage, fabricPrivacy, dateUtil)
insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsInterface, sp, commandQueue, profileFunction, nsUpload, context, uploadQueue, Config(), dateUtil, databaseHelper)
openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsInterface, iobCobCalculatorPlugin, hardLimits, profiler, sp)
openAPSAMAPlugin = OpenAPSAMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsInterface, iobCobCalculatorPlugin, hardLimits, profiler, fabricPrivacy)
openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsInterface, iobCobCalculatorPlugin, hardLimits, profiler, sp, dateUtil, repository)
openAPSAMAPlugin = OpenAPSAMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsInterface, iobCobCalculatorPlugin, hardLimits, profiler, fabricPrivacy, dateUtil, repository)
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, BuildHelper(Config(), loggerUtils), treatmentsInterface, Config())
val constraintsPluginsList = ArrayList<PluginBase>()
constraintsPluginsList.add(safetyPlugin)

View file

@ -7,11 +7,7 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R
import info.nightscout.androidaps.TestBase
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.PumpDescription
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
@ -53,15 +49,16 @@ class LoopPluginTest : TestBase() {
@Mock lateinit var receiverStatusStore: ReceiverStatusStore
@Mock lateinit var nsUpload: NSUpload
@Mock lateinit var notificationManager: NotificationManager
@Mock lateinit var databaseHelper: DatabaseHelperInterface
private lateinit var hardLimits: HardLimits
lateinit var loopPlugin: LoopPlugin
private lateinit var loopPlugin: LoopPlugin
val injector = HasAndroidInjector { AndroidInjector { } }
@Before fun prepareMock() {
hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, nsUpload)
loopPlugin = LoopPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, Config(), constraintChecker, resourceHelper, profileFunction, context, commandQueue, activePlugin, treatmentsPlugin, virtualPumpPlugin, iobCobCalculatorPlugin, receiverStatusStore, fabricPrivacy, nsUpload, hardLimits)
loopPlugin = LoopPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, Config(), constraintChecker, resourceHelper, profileFunction, context, commandQueue, activePlugin, treatmentsPlugin, virtualPumpPlugin, iobCobCalculatorPlugin, receiverStatusStore, fabricPrivacy, nsUpload, databaseHelper, hardLimits)
`when`(activePlugin.activePump).thenReturn(virtualPumpPlugin)
`when`(context.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(notificationManager)
}

View file

@ -12,7 +12,9 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.CommandQueueProvider
import info.nightscout.androidaps.interfaces.Constraint
@ -21,6 +23,7 @@ import info.nightscout.androidaps.interfaces.PumpDescription
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePasswordValidationResult
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo
@ -37,6 +40,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.XdripCalibrations
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.Single
import org.junit.Assert
import org.junit.Before
import org.junit.Test
@ -53,7 +57,11 @@ import org.powermock.modules.junit4.PowerMockRunner
import java.util.*
@RunWith(PowerMockRunner::class)
@PrepareForTest(ConstraintChecker::class, FabricPrivacy::class, VirtualPumpPlugin::class, XdripCalibrations::class, SmsManager::class, CommandQueue::class, LocalProfilePlugin::class, DateUtil::class, IobCobCalculatorPlugin::class, OneTimePassword::class, UserEntryLogger::class, LoopPlugin::class)
@PrepareForTest(
ConstraintChecker::class, FabricPrivacy::class, VirtualPumpPlugin::class, XdripCalibrations::class,
SmsManager::class, CommandQueue::class, LocalProfilePlugin::class, DateUtil::class,
IobCobCalculatorPlugin::class, OneTimePassword::class, UserEntryLogger::class, LoopPlugin::class,
AppRepository::class)
class SmsCommunicatorPluginTest : TestBaseWithProfile() {
@Mock lateinit var context: Context
@ -69,6 +77,8 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
@Mock lateinit var otp: OneTimePassword
@Mock lateinit var xdripCalibrations: XdripCalibrations
@Mock lateinit var uel: UserEntryLogger
@Mock lateinit var nsUpload: NSUpload
@Mock lateinit var repository: AppRepository
var injector: HasAndroidInjector = HasAndroidInjector {
AndroidInjector {
@ -108,7 +118,12 @@ class SmsCommunicatorPluginTest : TestBaseWithProfile() {
`when`(SmsManager.getDefault()).thenReturn(smsManager)
`when`(sp.getString(R.string.key_smscommunicator_allowednumbers, "")).thenReturn("1234;5678")
smsCommunicatorPlugin = SmsCommunicatorPlugin(injector, aapsLogger, resourceHelper, aapsSchedulers, sp, constraintChecker, rxBus, profileFunction, fabricPrivacy, activePlugin, commandQueue, loopPlugin, iobCobCalculatorPlugin, xdripCalibrations, otp, Config(), DateUtil(context), uel)
`when`(
repository.runTransactionForResult(anyObject<InsertTemporaryTargetAndCancelCurrentTransaction>())
).thenReturn(Single.just(InsertTemporaryTargetAndCancelCurrentTransaction.TransactionResult().apply {
}))
smsCommunicatorPlugin = SmsCommunicatorPlugin(injector, aapsLogger, resourceHelper, aapsSchedulers, sp, constraintChecker, rxBus, profileFunction, fabricPrivacy, activePlugin, commandQueue, loopPlugin, iobCobCalculatorPlugin, xdripCalibrations, otp, Config(), DateUtil(context), uel, nsUpload, repository)
smsCommunicatorPlugin.setPluginEnabled(PluginType.GENERAL, true)
Mockito.doAnswer { invocation: InvocationOnMock ->
val callback = invocation.getArgument<Callback>(1)

View file

@ -3,10 +3,10 @@ package info.nightscout.androidaps.plugins.treatments
import android.content.Context
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.db.DatabaseHelper
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.db.TemporaryBasal
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin
@ -21,21 +21,21 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
@Suppress("SpellCheckingInspection")
@RunWith(PowerMockRunner::class)
@PrepareForTest(FabricPrivacy::class, MainApp::class, DatabaseHelper::class)
@PrepareForTest(FabricPrivacy::class, DatabaseHelperInterface::class, AppRepository::class)
class TreatmentsPluginTest : TestBaseWithProfile() {
@Mock lateinit var context: Context
@Mock lateinit var sp: SP
@Mock lateinit var databaseHelper: DatabaseHelper
@Mock lateinit var treatmentService: TreatmentService
@Mock lateinit var nsUpload: NSUpload
@Mock lateinit var uploadQueue: UploadQueue
@Mock lateinit var repository: AppRepository
@Mock lateinit var databaseHelper: DatabaseHelperInterface
val injector = HasAndroidInjector {
AndroidInjector {
@ -44,6 +44,7 @@ class TreatmentsPluginTest : TestBaseWithProfile() {
it.activePlugin = activePluginProvider
it.profileFunction = profileFunction
it.sp = sp
it.dateUtil = DateUtil(context)
}
}
}
@ -53,15 +54,12 @@ class TreatmentsPluginTest : TestBaseWithProfile() {
@Before
fun prepare() {
PowerMockito.mockStatic(MainApp::class.java)
`when`(MainApp.getDbHelper()).thenReturn(databaseHelper)
insulinOrefRapidActingPlugin = InsulinOrefRapidActingPlugin(profileInjector, resourceHelper, profileFunction, rxBus, aapsLogger)
`when`(profileFunction.getProfile(ArgumentMatchers.anyLong())).thenReturn(validProfile)
`when`(activePluginProvider.activeInsulin).thenReturn(insulinOrefRapidActingPlugin)
sot = TreatmentsPlugin(profileInjector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, context, sp, profileFunction, activePluginProvider, nsUpload, fabricPrivacy, dateUtil, uploadQueue)
sot = TreatmentsPlugin(profileInjector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, context, sp, profileFunction, activePluginProvider, nsUpload, fabricPrivacy, dateUtil, uploadQueue, databaseHelper, repository)
sot.service = treatmentService
}

View file

@ -7,27 +7,38 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.automation.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.automation.elements.ComparatorExists
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration
import info.nightscout.androidaps.plugins.general.automation.elements.InputTempTarget
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTempTarget
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.JsonHelper.safeGetDouble
import info.nightscout.androidaps.utils.extensions.friendlyDescription
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import org.json.JSONObject
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class ActionStartTempTarget(injector: HasAndroidInjector) : Action(injector) {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var repository: AppRepository
@Inject lateinit var nsUpload: NSUpload
private val disposable = CompositeDisposable()
var value = InputTempTarget(injector)
var duration = InputDuration(injector, 30, InputDuration.TimeUnit.MINUTES)
@ -41,8 +52,15 @@ class ActionStartTempTarget(injector: HasAndroidInjector) : Action(injector) {
@DrawableRes override fun icon(): Int = R.drawable.ic_temptarget_high
override fun doAction(callback: Callback) {
activePlugin.activeTreatments.addToHistoryTempTarget(tt())
callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run()
disposable += repository.runTransactionForResult(InsertTemporaryTargetAndCancelCurrentTransaction(tt()))
.subscribe({ result ->
result.inserted.forEach { nsUpload.uploadTempTarget(it) }
result.updated.forEach { nsUpload.updateTempTarget(it) }
callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run()
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it)
callback.result(PumpEnactResult(injector).success(false).comment(R.string.error))?.run()
})
}
override fun generateDialog(root: LinearLayout) {
@ -76,14 +94,13 @@ class ActionStartTempTarget(injector: HasAndroidInjector) : Action(injector) {
return this
}
fun tt(): TempTarget =
TempTarget()
.date(DateUtil.now())
.duration(duration.getMinutes())
.reason("Automation")
.source(Source.USER)
.low(Profile.toMgdl(value.value, value.units))
.high(Profile.toMgdl(value.value, value.units))
fun tt() = TemporaryTarget(
timestamp = DateUtil.now(),
duration = TimeUnit.MINUTES.toMillis(duration.getMinutes().toLong()),
reason = TemporaryTarget.Reason.AUTOMATION,
lowTarget = Profile.toMgdl(value.value, value.units),
highTarget = Profile.toMgdl(value.value, value.units)
)
override fun isValid(): Boolean =
if (value.units == Constants.MMOL) { // mmol

View file

@ -3,31 +3,39 @@ package info.nightscout.androidaps.plugins.general.automation.actions
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.automation.R
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import javax.inject.Inject
class ActionStopTempTarget(injector: HasAndroidInjector) : Action(injector) {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var repository: AppRepository
@Inject lateinit var nsUpload: NSUpload
@Inject lateinit var dateUtil: DateUtil
private val disposable = CompositeDisposable()
override fun friendlyName(): Int = R.string.stoptemptarget
override fun shortDescription(): String = resourceHelper.gs(R.string.stoptemptarget)
override fun icon(): Int = R.drawable.ic_stop_24dp
override fun doAction(callback: Callback) {
val tempTarget = TempTarget()
.date(DateUtil.now())
.duration(0)
.reason("Automation")
.source(Source.USER)
.low(0.0).high(0.0)
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(DateUtil.now()))
.subscribe({ result ->
result.updated.forEach { nsUpload.updateTempTarget(it) }
}, {
aapsLogger.error(LTag.BGSOURCE, "Error while saving temporary target", it)
})
callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run()
}

View file

@ -4,14 +4,21 @@ import android.widget.LinearLayout
import com.google.common.base.Optional
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.automation.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.automation.elements.ComparatorExists
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
import javax.inject.Inject
class TriggerTempTarget(injector: HasAndroidInjector) : Trigger(injector) {
@Inject lateinit var repository: AppRepository
@Inject lateinit var dateUtil: DateUtil
var comparator = ComparatorExists(injector)
constructor(injector: HasAndroidInjector, compare: ComparatorExists.Compare) : this(injector) {
@ -28,7 +35,7 @@ class TriggerTempTarget(injector: HasAndroidInjector) : Trigger(injector) {
}
override fun shouldRun(): Boolean {
val tt = treatmentsInterface.tempTargetFromHistory
val tt = repository.getTemporaryTargetActiveAt(dateUtil._now()).blockingGet()
if (tt == null && comparator.value == ComparatorExists.Compare.NOT_EXISTS) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true

View file

@ -5,6 +5,7 @@ import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.rx.TestAapsSchedulers
import org.junit.Before
import org.junit.Rule
import org.mockito.ArgumentMatcher
import org.mockito.Mockito
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
@ -35,6 +36,17 @@ open class TestBase {
return uninitialized()
}
fun <T> argThatKotlin(matcher: ArgumentMatcher<T>): T {
Mockito.argThat(matcher)
return uninitialized()
}
fun <T> eqObject(expected: T): T {
Mockito.eq<T>(expected)
return uninitialized()
}
@Suppress("Unchecked_Cast")
fun <T> uninitialized(): T = null as T
}

View file

@ -2,13 +2,18 @@ package info.nightscout.androidaps.plugins.general.automation.actions
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.automation.R
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.transactions.InsertTemporaryTargetAndCancelCurrentTransaction
import info.nightscout.androidaps.database.transactions.Transaction
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration
import info.nightscout.androidaps.plugins.general.automation.elements.InputTempTarget
import info.nightscout.androidaps.queue.Callback
import io.reactivex.Single
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatcher
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.powermock.modules.junit4.PowerMockRunner
@ -41,13 +46,47 @@ class ActionStartTempTargetTest : ActionsTestBase() {
}
@Test fun doActionTest() {
`when`(activePlugin.activeTreatments).thenReturn(treatmentsInterface)
val expectedTarget = TemporaryTarget(
id = 0,
version = 0,
dateCreated = -1,
isValid = true,
referenceId = null,
interfaceIDs_backing = null,
timestamp = 0,
utcOffset = 0,
reason = TemporaryTarget.Reason.AUTOMATION,
highTarget = 110.0,
lowTarget = 110.0,
duration = 1800000
)
val inserted = mutableListOf<TemporaryTarget>().apply {
add(expectedTarget)
}
val updated = mutableListOf<TemporaryTarget>().apply {
// TODO insert all updated TTs
}
`when`(
repository.runTransactionForResult(argThatKotlin<InsertTemporaryTargetAndCancelCurrentTransaction> {
it.temporaryTarget
.copy(timestamp = expectedTarget.timestamp, utcOffset = expectedTarget.utcOffset) // those can be different
.contentEqualsTo(expectedTarget)
})
).thenReturn(Single.just(InsertTemporaryTargetAndCancelCurrentTransaction.TransactionResult().apply {
inserted.addAll(inserted)
updated.addAll(updated)
}))
sut.doAction(object : Callback() {
override fun run() {
Assert.assertTrue(result.success)
}
})
Mockito.verify(treatmentsInterface, Mockito.times(1)).addToHistoryTempTarget(anyObject())
Mockito.verify(repository, Mockito.times(1)).runTransactionForResult(anyObject<Transaction<InsertTemporaryTargetAndCancelCurrentTransaction.TransactionResult>>())
}
@Test fun hasDialogTest() {

View file

@ -1,7 +1,11 @@
package info.nightscout.androidaps.plugins.general.automation.actions
import info.nightscout.androidaps.automation.R
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.Transaction
import info.nightscout.androidaps.queue.Callback
import io.reactivex.Single
import org.junit.Assert
import org.junit.Before
import org.junit.Test
@ -35,13 +39,26 @@ class ActionStopTempTargetTest : ActionsTestBase() {
}
@Test fun doActionTest() {
`when`(activePlugin.activeTreatments).thenReturn(treatmentsInterface)
val inserted = mutableListOf<TemporaryTarget>().apply {
// insert all inserted TTs
}
val updated = mutableListOf<TemporaryTarget>().apply {
// add(TemporaryTarget(id = 0, version = 0, dateCreated = 0, isValid = false, referenceId = null, interfaceIDs_backing = null, timestamp = 0, utcOffset = 0, reason =, highTarget = 0.0, lowTarget = 0.0, duration = 0))
// insert all updated TTs
}
`when`(
repository.runTransactionForResult(anyObject<Transaction<CancelCurrentTemporaryTargetIfAnyTransaction.TransactionResult>>())
).thenReturn(Single.just(CancelCurrentTemporaryTargetIfAnyTransaction.TransactionResult().apply {
inserted.addAll(inserted)
updated.addAll(updated)
}))
sut.doAction(object : Callback() {
override fun run() {
Assert.assertTrue(result.success)
}
})
Mockito.verify(treatmentsInterface, Mockito.times(1)).addToHistoryTempTarget(anyObject())
Mockito.verify(repository, Mockito.times(1)).runTransactionForResult((anyObject<Transaction<CancelCurrentTemporaryTargetIfAnyTransaction.TransactionResult>>()))
}
@Test fun hasDialogTest() {

View file

@ -6,6 +6,7 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.TestPumpPlugin
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
@ -17,7 +18,7 @@ import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.powermock.core.classloader.annotations.PrepareForTest
@PrepareForTest(RxBusWrapper::class, ActionsTestBase.TestLoopPlugin::class)
@PrepareForTest(RxBusWrapper::class, ActionsTestBase.TestLoopPlugin::class, AppRepository::class)
open class ActionsTestBase : TestBaseWithProfile() {
open class TestLoopPlugin(
@ -44,6 +45,7 @@ open class ActionsTestBase : TestBaseWithProfile() {
@Mock lateinit var profilePlugin: ProfileInterface
@Mock lateinit var smsCommunicatorPlugin: SmsCommunicatorInterface
@Mock lateinit var loopPlugin: TestLoopPlugin
@Mock lateinit var repository: AppRepository
private val pluginDescription = PluginDescription()
lateinit var testPumpPlugin: TestPumpPlugin
@ -54,11 +56,13 @@ open class ActionsTestBase : TestBaseWithProfile() {
it.aapsLogger = aapsLogger
it.resourceHelper = resourceHelper
it.activePlugin = activePlugin
it.repository = repository
}
if (it is ActionStartTempTarget) {
it.aapsLogger = aapsLogger
it.resourceHelper = resourceHelper
it.activePlugin = activePlugin
it.repository = repository
}
if (it is ActionSendSMS) {
it.aapsLogger = aapsLogger

View file

@ -2,7 +2,6 @@ package info.nightscout.androidaps.plugins.general.automation.triggers
import com.google.common.base.Optional
import info.nightscout.androidaps.automation.R
import info.nightscout.androidaps.db.TempTarget
import info.nightscout.androidaps.plugins.general.automation.elements.ComparatorExists
import info.nightscout.androidaps.utils.DateUtil
import org.json.JSONObject
@ -10,7 +9,6 @@ import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.`when`
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
@ -25,20 +23,20 @@ class TriggerTempTargetTest : TriggerTestBase() {
PowerMockito.mockStatic(DateUtil::class.java)
PowerMockito.`when`(DateUtil.now()).thenReturn(now)
}
/*
@Test fun shouldRunTest() {
`when`(treatmentsInterface.tempTargetFromHistory).thenReturn(null)
`when`(repository.getTemporaryTargetActiveAt(anyObject())).thenReturn(null)
var t: TriggerTempTarget = TriggerTempTarget(injector).comparator(ComparatorExists.Compare.EXISTS)
Assert.assertFalse(t.shouldRun())
t = TriggerTempTarget(injector).comparator(ComparatorExists.Compare.NOT_EXISTS)
Assert.assertTrue(t.shouldRun())
PowerMockito.`when`(treatmentsInterface.tempTargetFromHistory).thenReturn(TempTarget())
PowerMockito.`when`(repository.getTemporaryTargetActiveAt(anyObject())).thenReturn(TemporaryTarget(duration = 0, highTarget = 0.0, lowTarget = 0.0, reason = TemporaryTarget.Reason.CUSTOM, timestamp = 0))
t = TriggerTempTarget(injector).comparator(ComparatorExists.Compare.NOT_EXISTS)
Assert.assertFalse(t.shouldRun())
t = TriggerTempTarget(injector).comparator(ComparatorExists.Compare.EXISTS)
Assert.assertTrue(t.shouldRun())
}
*/
@Test fun copyConstructorTest() {
val t: TriggerTempTarget = TriggerTempTarget(injector).comparator(ComparatorExists.Compare.NOT_EXISTS)
val t1 = t.duplicate() as TriggerTempTarget

View file

@ -5,6 +5,7 @@ import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.TestPumpPlugin
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface
import info.nightscout.androidaps.interfaces.PluginDescription
@ -20,10 +21,9 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.junit.Before
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
@PrepareForTest(LastLocationDataContainer::class, AutomationPlugin::class)
@PrepareForTest(LastLocationDataContainer::class, AutomationPlugin::class, AppRepository::class)
open class TriggerTestBase : TestBaseWithProfile() {
@Mock lateinit var sp: SP
@ -32,6 +32,7 @@ open class TriggerTestBase : TestBaseWithProfile() {
@Mock lateinit var iobCobCalculatorPlugin: IobCobCalculatorInterface
@Mock lateinit var context: Context
@Mock lateinit var automationPlugin: AutomationPlugin
@Mock lateinit var repository: AppRepository
lateinit var receiverStatusStore: ReceiverStatusStore
private val pluginDescription = PluginDescription()

View file

@ -6,8 +6,6 @@ import com.j256.ormlite.table.DatabaseTable;
import org.json.JSONException;
import org.json.JSONObject;
import info.nightscout.androidaps.utils.DateUtil;
/**
* Created by mike on 27.02.2016.
* <p>
@ -35,10 +33,10 @@ public class DbRequest {
}
// dbAdd
public DbRequest(String action, String collection, JSONObject json) {
public DbRequest(String action, String collection, JSONObject json, long nsClientId) {
this.action = action;
this.collection = collection;
this.nsClientID = "" + DateUtil.now();
this.nsClientID = "" + nsClientId;
try {
json.put("NSCLIENT_ID", nsClientID);
} catch (JSONException e) {
@ -49,10 +47,10 @@ public class DbRequest {
}
// dbUpdate, dbUpdateUnset
public DbRequest(String action, String collection, String _id, JSONObject json) {
public DbRequest(String action, String collection, String _id, JSONObject json, long nsClientId) {
this.action = action;
this.collection = collection;
this.nsClientID = "" + DateUtil.now();
this.nsClientID = "" + nsClientId;
try {
json.put("NSCLIENT_ID", nsClientID);
} catch (JSONException e) {
@ -63,12 +61,11 @@ public class DbRequest {
}
// dbRemove
public DbRequest(String action, String collection,
String _id) {
public DbRequest(String action, String collection, String _id, long nsClientId) {
JSONObject json = new JSONObject();
this.action = action;
this.collection = collection;
this.nsClientID = "" + DateUtil.now();
this.nsClientID = "" + nsClientId;
try {
json.put("NSCLIENT_ID", nsClientID);
} catch (JSONException e) {

View file

@ -1,199 +0,0 @@
package info.nightscout.androidaps.db;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import java.util.Objects;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.core.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.interfaces.Interval;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
@DatabaseTable(tableName = "TempTargets")
public class TempTarget implements Interval {
@DatabaseField(id = true)
public long date;
@DatabaseField
public boolean isValid = true;
@DatabaseField
public int source = Source.NONE;
@DatabaseField
public String _id = null; // NS _id
@DatabaseField
public double low; // in mgdl
@DatabaseField
public double high; // in mgdl
@DatabaseField
public String reason;
@DatabaseField
public int durationInMinutes;
public double target() {
return (low + high) / 2;
}
public boolean isEqual(TempTarget other) {
if (date != other.date) {
return false;
}
if (durationInMinutes != other.durationInMinutes)
return false;
if (low != other.low)
return false;
if (high != other.high)
return false;
if (!Objects.equals(reason, other.reason))
return false;
if (!Objects.equals(_id, other._id))
return false;
return true;
}
public void copyFrom(TempTarget t) {
date = t.date;
_id = t._id;
durationInMinutes = t.durationInMinutes;
low = t.low;
high = t.high;
reason = t.reason;
}
public TempTarget date(long date) {
this.date = date;
return this;
}
public TempTarget low(double low) {
this.low = low;
return this;
}
public TempTarget high(double high) {
this.high = high;
return this;
}
public TempTarget duration(int duration) {
this.durationInMinutes = duration;
return this;
}
public TempTarget reason(String reason) {
this.reason = reason;
return this;
}
public TempTarget _id(String _id) {
this._id = _id;
return this;
}
public TempTarget source(int source) {
this.source = source;
return this;
}
// -------- Interval interface ---------
Long cuttedEnd = null;
public long durationInMsec() {
return durationInMinutes * 60 * 1000L;
}
public long start() {
return date;
}
// planned end time at time of creation
public long originalEnd() {
return date + durationInMinutes * 60 * 1000L;
}
// end time after cut
public long end() {
if (cuttedEnd != null)
return cuttedEnd;
return originalEnd();
}
public void cutEndTo(long end) {
cuttedEnd = end;
}
public boolean match(long time) {
if (start() <= time && end() >= time)
return true;
return false;
}
public boolean before(long time) {
if (end() < time)
return true;
return false;
}
public boolean after(long time) {
if (start() > time)
return true;
return false;
}
@Override
public boolean isInProgress() {
return match(System.currentTimeMillis());
}
@Override
public boolean isEndingEvent() {
return durationInMinutes == 0;
}
@Override
public boolean isValid() {
return true;
}
// -------- Interval interface end ---------
public String lowValueToUnitsToString(String units) {
if (units.equals(Constants.MGDL)) return DecimalFormatter.to0Decimal(low);
else return DecimalFormatter.to1Decimal(low * Constants.MGDL_TO_MMOLL);
}
public String highValueToUnitsToString(String units) {
if (units.equals(Constants.MGDL)) return DecimalFormatter.to0Decimal(high);
else return DecimalFormatter.to1Decimal(low * Constants.MGDL_TO_MMOLL);
}
public String toString(DateUtil dateUtil) {
return "TemporaryTarget{" +
"date=" + date +
"date=" + dateUtil.dateAndTimeString(date) +
", isValid=" + isValid +
", duration=" + durationInMinutes +
", reason=" + reason +
", low=" + low +
", high=" + high +
'}';
}
public String friendlyDescription(String units, ResourceHelper resourceHelper) {
return Profile.toTargetRangeString(low, high, Constants.MGDL, units) +
units +
"@" + resourceHelper.gs(R.string.mins, durationInMinutes) +
(reason != null && !reason.equals("") ? "(" + reason + ")" : "");
}
}

View file

@ -33,7 +33,7 @@ public class TemporaryBasal implements Interval, DbObjectBase {
@Inject public ProfileFunction profileFunction;
@Inject public ActivePluginProvider activePlugin;
@Inject public SP sp;
@Inject DateUtil dateUtil;
@Inject public DateUtil dateUtil;
private HasAndroidInjector injector;

View file

@ -27,7 +27,7 @@ abstract class DialogFragmentWithDate : DaggerDialogFragment() {
@Inject lateinit var sp: SP
@Inject lateinit var dateUtil: DateUtil
var eventTime = DateUtil.now()
var eventTime: Long = 0
var eventTimeChanged = false
//one shot guards
@ -60,7 +60,7 @@ abstract class DialogFragmentWithDate : DaggerDialogFragment() {
val eventDateView = view.findViewById(R.id.eventdate) as TextView?
val eventTimeView = view.findViewById(R.id.eventtime) as TextView?
eventTime = savedInstanceState?.getLong("eventTime") ?: DateUtil.now()
eventTime = savedInstanceState?.getLong("eventTime") ?: dateUtil.nowWithoutMilliseconds()
eventTimeChanged = savedInstanceState?.getBoolean("eventTimeChanged") ?: false
eventDateView?.text = DateUtil.dateString(eventTime)

View file

@ -2,10 +2,16 @@ 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 {
fun resetDatabases()
fun createOrUpdate(careportalEvent: CareportalEvent)
fun createOrUpdate(extendedBolus: ExtendedBolus): Boolean
fun createOrUpdate(profileSwitch: ProfileSwitch)
fun createOrUpdate(record: DanaRHistoryRecord)
fun createOrUpdate(record: OmnipodHistoryRecord)
fun createOrUpdate(record: InsightBolusID)
@ -17,14 +23,16 @@ interface DatabaseHelperInterface {
fun size(table: String): Long
fun deleteAllDbRequests()
fun deleteDbRequest(id: String): Int
fun delete(tempBasal: TemporaryBasal)
fun delete(extendedBolus: ExtendedBolus)
fun deleteDbRequestbyMongoId(action: String, _id: String)
fun getDbRequestInterator(): CloseableIterator<DbRequest>
fun roundDateToSec(date: Long): Long
fun createOrUpdateTDD(record: TDD)
fun createOrUpdate(tempBasal: TemporaryBasal)
fun createOrUpdate(tempBasal: TemporaryBasal): Boolean
fun findTempBasalByPumpId(id: Long): TemporaryBasal
fun getTemporaryBasalsDataFromTime(mills: Long, ascending: Boolean): List<TemporaryBasal>
fun getExtendedBolusDataFromTime(mills: Long, ascending: Boolean): List<ExtendedBolus>
fun getCareportalEventFromTimestamp(timestamp: Long): CareportalEvent?
fun getAllOmnipodHistoryRecordsFromTimestamp(timestamp: Long, ascending: Boolean): List<OmnipodHistoryRecord>
fun findOmnipodHistoryRecordByPumpId(pumpId: Long): OmnipodHistoryRecord?
@ -32,6 +40,16 @@ interface DatabaseHelperInterface {
fun getProfileSwitchData(from: Long, ascending: Boolean): List<ProfileSwitch>
fun getExtendedBolusByPumpId(pumpId: Long): ExtendedBolus?
// old DB model
fun deleteTempBasalById(_id: String)
fun deleteExtendedBolusById(_id: String)
fun deleteCareportalEventById(_id: String)
fun deleteProfileSwitchById(_id: String)
fun createTempBasalFromJsonIfNotExists(json: JSONObject)
fun createExtendedBolusFromJsonIfNotExists(json: JSONObject)
fun createCareportalEventFromJsonIfNotExists(json: JSONObject)
fun createProfileSwitchFromJsonIfNotExists(activePluginProvider: ActivePluginProvider, nsUpload: NSUpload, trJson: JSONObject)
fun getInsightBolusID(pumpSerial: String, bolusID: Int, timestamp: Long): InsightBolusID?
fun getInsightHistoryOffset(pumpSerial: String): InsightHistoryOffset?
fun getPumpStoppedEvent(pumpSerial: String, before: Long): InsightPumpID?

View file

@ -11,7 +11,6 @@ import info.nightscout.androidaps.data.NonOverlappingIntervals;
import info.nightscout.androidaps.data.ProfileIntervals;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentUpdateReturn;
@ -42,6 +41,7 @@ public interface TreatmentsInterface {
List<Treatment> getTreatmentsFromHistoryAfterTimestamp(long timestamp);
long getLastBolusTime();
long getLastBolusTime(boolean excludeSMB);
// real basals (not faked by extended bolus)
@ -60,7 +60,7 @@ public interface TreatmentsInterface {
void removeTempBasal(TemporaryBasal temporaryBasal);
boolean isInHistoryExtendedBoluslInProgress();
boolean isInHistoryExtendedBolusInProgress();
ExtendedBolus getExtendedBolusFromHistory(long time);
@ -70,14 +70,6 @@ public interface TreatmentsInterface {
boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo, boolean allowUpdate);
TempTarget getTempTargetFromHistory();
TempTarget getTempTargetFromHistory(long time);
Intervals<TempTarget> getTempTargetsFromHistory();
void addToHistoryTempTarget(TempTarget tempTarget);
ProfileSwitch getProfileSwitchFromHistory(long time);
ProfileIntervals<ProfileSwitch> getProfileSwitchesFromHistory();

View file

@ -20,12 +20,12 @@ import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.database.entities.TemporaryTarget;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.DbRequest;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.ProfileSwitch;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface;
import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface;
@ -42,6 +42,7 @@ import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration;
import info.nightscout.androidaps.receivers.ReceiverStatusStore;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
@ -55,10 +56,12 @@ public class NSUpload {
private final AAPSLogger aapsLogger;
private final ResourceHelper resourceHelper;
private final SP sp;
private final Context context;
private final UploadQueueInterface uploadQueue;
private final DatabaseHelperInterface databaseHelper;
private final RunningConfiguration runningConfiguration;
private final ProfileFunction profileFunction;
public static String ISVALID = "isValid";
@Inject
public NSUpload(
@ -66,19 +69,19 @@ public class NSUpload {
AAPSLogger aapsLogger,
ResourceHelper resourceHelper,
SP sp,
Context context,
UploadQueueInterface uploadQueue,
RunningConfiguration runningConfiguration,
DatabaseHelperInterface databaseHelper
DatabaseHelperInterface databaseHelper,
ProfileFunction profileFunction
) {
this.injector = injector;
this.aapsLogger = aapsLogger;
this.resourceHelper = resourceHelper;
this.sp = sp;
this.context = context;
this.uploadQueue = uploadQueue;
this.runningConfiguration = runningConfiguration;
this.databaseHelper = databaseHelper;
this.profileFunction = profileFunction;
}
public void uploadTempBasalStartAbsolute(TemporaryBasal temporaryBasal, Double originalExtendedAmount) {
@ -94,7 +97,7 @@ public class NSUpload {
data.put("enteredBy", "openaps://" + "AndroidAPS");
if (originalExtendedAmount != null)
data.put("originalExtendedAmount", originalExtendedAmount); // for back synchronization
uploadQueue.add(new DbRequest("dbAdd", "treatments", data));
uploadQueue.add(new DbRequest("dbAdd", "treatments", data, temporaryBasal.date));
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
@ -125,7 +128,7 @@ public class NSUpload {
data.put("pumpId", temporaryBasal.pumpId);
data.put("created_at", DateUtil.toISOString(temporaryBasal.date));
data.put("enteredBy", "openaps://" + "AndroidAPS");
uploadQueue.add(new DbRequest("dbAdd", "treatments", data));
uploadQueue.add(new DbRequest("dbAdd", "treatments", data, temporaryBasal.date));
}
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
@ -142,7 +145,7 @@ public class NSUpload {
data.put("isFakedTempBasal", isFakedTempBasal);
if (pumpId != 0)
data.put("pumpId", pumpId);
uploadQueue.add(new DbRequest("dbAdd", "treatments", data));
uploadQueue.add(new DbRequest("dbAdd", "treatments", data, time));
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
@ -161,7 +164,7 @@ public class NSUpload {
data.put("pumpId", extendedBolus.pumpId);
data.put("created_at", DateUtil.toISOString(extendedBolus.date));
data.put("enteredBy", "openaps://" + "AndroidAPS");
uploadQueue.add(new DbRequest("dbAdd", "treatments", data));
uploadQueue.add(new DbRequest("dbAdd", "treatments", data, extendedBolus.date));
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
@ -180,7 +183,7 @@ public class NSUpload {
data.put("enteredBy", "openaps://" + "AndroidAPS");
if (pumpId != 0)
data.put("pumpId", pumpId);
uploadQueue.add(new DbRequest("dbAdd", "treatments", data));
uploadQueue.add(new DbRequest("dbAdd", "treatments", data, time));
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
@ -241,14 +244,13 @@ public class NSUpload {
deviceStatus.pump = pumpstatus;
}
int batteryLevel = receiverStatusStore.getBatteryLevel();
deviceStatus.uploaderBattery = batteryLevel;
deviceStatus.uploaderBattery = receiverStatusStore.getBatteryLevel();
deviceStatus.created_at = DateUtil.toISOString(new Date());
deviceStatus.configuration = runningConfiguration.configuration();
uploadQueue.add(new DbRequest("dbAdd", "devicestatus", deviceStatus.mongoRecord()));
uploadQueue.add(new DbRequest("dbAdd", "devicestatus", deviceStatus.mongoRecord(), System.currentTimeMillis()));
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
@ -279,32 +281,53 @@ public class NSUpload {
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
uploadCareportalEntryToNS(data);
uploadCareportalEntryToNS(data, detailedBolusInfo.date);
}
public void uploadProfileSwitch(ProfileSwitch profileSwitch) {
public void uploadProfileSwitch(ProfileSwitch profileSwitch, long nsClientId) {
try {
JSONObject data = getJson(profileSwitch);
uploadCareportalEntryToNS(data);
uploadCareportalEntryToNS(data, nsClientId);
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
}
public void uploadTempTarget(TempTarget tempTarget, ProfileFunction profileFunction) {
public void uploadTempTarget(TemporaryTarget tempTarget) {
try {
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPORARYTARGET);
data.put("duration", tempTarget.durationInMinutes);
if (tempTarget.low > 0) {
data.put("reason", tempTarget.reason);
data.put("targetBottom", Profile.fromMgdlToUnits(tempTarget.low, profileFunction.getUnits()));
data.put("targetTop", Profile.fromMgdlToUnits(tempTarget.high, profileFunction.getUnits()));
data.put("duration", T.msecs(tempTarget.getDuration()).mins());
data.put(ISVALID, tempTarget.isValid());
if (tempTarget.getLowTarget() > 0) {
data.put("reason", tempTarget.getReason().getText());
data.put("targetBottom", Profile.fromMgdlToUnits(tempTarget.getLowTarget(), profileFunction.getUnits()));
data.put("targetTop", Profile.fromMgdlToUnits(tempTarget.getHighTarget(), profileFunction.getUnits()));
data.put("units", profileFunction.getUnits());
}
data.put("created_at", DateUtil.toISOString(tempTarget.date));
data.put("created_at", DateUtil.toISOString(tempTarget.getTimestamp()));
data.put("enteredBy", "AndroidAPS");
uploadCareportalEntryToNS(data);
uploadCareportalEntryToNS(data, tempTarget.getTimestamp());
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
}
public void updateTempTarget(TemporaryTarget tempTarget) {
try {
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.TEMPORARYTARGET);
data.put("duration", T.msecs(tempTarget.getDuration()).mins());
data.put(ISVALID, tempTarget.isValid());
if (tempTarget.getLowTarget() > 0) {
data.put("reason", tempTarget.getReason().getText());
data.put("targetBottom", Profile.fromMgdlToUnits(tempTarget.getLowTarget(), profileFunction.getUnits()));
data.put("targetTop", Profile.fromMgdlToUnits(tempTarget.getHighTarget(), profileFunction.getUnits()));
data.put("units", profileFunction.getUnits());
}
data.put("created_at", DateUtil.toISOString(tempTarget.getTimestamp()));
data.put("enteredBy", "AndroidAPS");
uploadQueue.add(new DbRequest("dbUpdate", "treatments", tempTarget.getInterfaceIDs().getNightscoutId(), data, tempTarget.getTimestamp()));
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
@ -314,7 +337,7 @@ public class NSUpload {
try {
JSONObject data = getJson(profileSwitch);
if (profileSwitch._id != null) {
uploadQueue.add(new DbRequest("dbUpdate", "treatments", profileSwitch._id, data));
uploadQueue.add(new DbRequest("dbUpdate", "treatments", profileSwitch._id, data, profileSwitch.date));
}
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
@ -339,7 +362,7 @@ public class NSUpload {
return data;
}
public void uploadCareportalEntryToNS(JSONObject data) {
public void uploadCareportalEntryToNS(JSONObject data, long nsClientId) {
try {
if (data.has("preBolus") && data.has("carbs")) {
JSONObject prebolus = new JSONObject();
@ -351,9 +374,9 @@ public class NSUpload {
long mills = DateUtil.fromISODateString(data.getString("created_at")).getTime();
Date preBolusDate = new Date(mills + data.getInt("preBolus") * 60000L + 1000L);
prebolus.put("created_at", DateUtil.toISOString(preBolusDate));
uploadCareportalEntryToNS(prebolus);
uploadCareportalEntryToNS(prebolus, preBolusDate.getTime());
}
DbRequest dbr = new DbRequest("dbAdd", "treatments", data);
DbRequest dbr = new DbRequest("dbAdd", "treatments", data, nsClientId);
aapsLogger.debug("Prepared: " + dbr.log());
uploadQueue.add(dbr);
} catch (Exception e) {
@ -363,7 +386,7 @@ public class NSUpload {
}
public void removeCareportalEntryFromNS(String _id) {
uploadQueue.add(new DbRequest("dbRemove", "treatments", _id));
uploadQueue.add(new DbRequest("dbRemove", "treatments", _id, System.currentTimeMillis()));
}
public void uploadOpenAPSOffline(CareportalEvent event) {
@ -371,7 +394,7 @@ public class NSUpload {
JSONObject data = new JSONObject(event.json);
data.put("created_at", DateUtil.toISOString(event.date));
data.put("enteredBy", "openaps://" + "AndroidAPS");
uploadQueue.add(new DbRequest("dbAdd", "treatments", data));
uploadQueue.add(new DbRequest("dbAdd", "treatments", data, event.date));
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
@ -392,7 +415,7 @@ public class NSUpload {
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
uploadQueue.add(new DbRequest("dbAdd", "treatments", data));
uploadQueue.add(new DbRequest("dbAdd", "treatments", data, date.getTime()));
}
public void uploadBg(GlucoseValue reading, String source) {
@ -407,7 +430,7 @@ public class NSUpload {
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
uploadQueue.add(new DbRequest("dbAdd", "entries", data));
uploadQueue.add(new DbRequest("dbAdd", "entries", data, reading.getTimestamp()));
}
public void updateBg(GlucoseValue reading, String source) {
@ -419,10 +442,9 @@ public class NSUpload {
data.put("sgv", reading.getValue());
data.put("direction", reading.getTrendArrow().getText());
data.put("type", "sgv");
if (reading.getInterfaceIDs() != null)
if (reading.getInterfaceIDs().getNightscoutId() != null) {
uploadQueue.add(new DbRequest("dbUpdate", "entries", reading.getInterfaceIDs().getNightscoutId(), data));
}
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);
}
@ -438,13 +460,13 @@ public class NSUpload {
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
uploadQueue.add(new DbRequest("dbAdd", "treatments", data));
uploadQueue.add(new DbRequest("dbAdd", "treatments", data, System.currentTimeMillis()));
}
}
public void uploadProfileStore(JSONObject profileStore) {
if (sp.getBoolean(R.string.key_ns_uploadlocalprofile, false)) {
uploadQueue.add(new DbRequest("dbAdd", "profile", profileStore));
uploadQueue.add(new DbRequest("dbAdd", "profile", profileStore, System.currentTimeMillis()));
}
}
@ -460,12 +482,12 @@ public class NSUpload {
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
uploadQueue.add(new DbRequest("dbAdd", "treatments", data));
uploadQueue.add(new DbRequest("dbAdd", "treatments", data, time));
}
public void removeFoodFromNS(String _id) {
try {
uploadQueue.add(new DbRequest("dbRemove", "food", _id));
uploadQueue.add(new DbRequest("dbRemove", "food", _id, System.currentTimeMillis()));
} catch (Exception e) {
aapsLogger.error("Unhandled exception", e);
}
@ -482,9 +504,9 @@ public class NSUpload {
JsonHelper.safeGetInt(data, "timeshift"),
eventTime
);
uploadProfileSwitch(profileSwitch);
uploadProfileSwitch(profileSwitch, eventTime);
} else {
uploadCareportalEntryToNS(data);
uploadCareportalEntryToNS(data, eventTime);
}
}

View file

@ -51,7 +51,7 @@ public class DateUtil {
/**
* The date format in iso.
*/
private static final String FORMAT_DATE_ISO_OUT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private static final String FORMAT_DATE_ISO_OUT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
/**
* Takes in an ISO date string of the following format:
@ -255,6 +255,12 @@ public class DateUtil {
return System.currentTimeMillis();
}
public long nowWithoutMilliseconds() {
long n = System.currentTimeMillis();
n = n - n % 1000;
return n;
}
public static long now() {
return System.currentTimeMillis();
}

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.utils
import android.content.Context
import android.os.Bundle
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.ktx.analytics
@ -79,7 +78,7 @@ class FabricPrivacy @Inject constructor(
// Crashlytics logException
fun logException(throwable: Throwable) {
FirebaseCrashlytics.getInstance().recordException(throwable)
aapsLogger.debug(LTag.CORE, "Exception: ", throwable)
aapsLogger.error("Exception: ", throwable)
}
fun fabricEnabled(): Boolean {

View file

@ -129,9 +129,21 @@ object JsonHelper {
return result
}
fun safeGetLongAllowNull(json: JSONObject?, fieldName: String, defaultValue: Long? = null): Long? {
var result: Long? = defaultValue
if (json != null && json.has(fieldName)) {
try {
result = json.getLong(fieldName)
} catch (ignored: JSONException) {
}
}
return result
}
@JvmStatic
fun safeGetBoolean(json: JSONObject?, fieldName: String): Boolean {
var result = false
@JvmOverloads
fun safeGetBoolean(json: JSONObject?, fieldName: String, defaultValue: Boolean = false): Boolean {
var result = defaultValue
if (json != null && json.has(fieldName)) {
try {
result = json.getBoolean(fieldName)

View file

@ -0,0 +1,84 @@
package info.nightscout.androidaps.utils.extensions
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.json.JSONObject
import java.util.concurrent.TimeUnit
fun TemporaryTarget.lowValueToUnitsToString(units: String): String =
if (units == Constants.MGDL) DecimalFormatter.to0Decimal(this.lowTarget)
else DecimalFormatter.to1Decimal(this.lowTarget * Constants.MGDL_TO_MMOLL)
fun TemporaryTarget.highValueToUnitsToString(units: String): String =
if (units == Constants.MGDL) DecimalFormatter.to0Decimal(this.highTarget)
else DecimalFormatter.to1Decimal(this.highTarget * Constants.MGDL_TO_MMOLL)
fun TemporaryTarget.target(): Double =
(this.lowTarget + this.highTarget) / 2
fun TemporaryTarget.friendlyDescription(units: String, resourceHelper: ResourceHelper): String =
Profile.toTargetRangeString(lowTarget, highTarget, Constants.MGDL, units) +
units +
"@" + resourceHelper.gs(R.string.format_mins, TimeUnit.MILLISECONDS.toMinutes(duration)) + "(" + reason.text + ")"
/*
create fake object with nsID and isValid == false
*/
fun temporaryTargetFromNsIdForInvalidating(nsId: String): TemporaryTarget =
temporaryTargetFromJson(
JSONObject()
.put("mills", 1)
.put("duration", -1)
.put("reason", "fake")
.put("_id", nsId)
.put(NSUpload.ISVALID, false)
)!!
fun temporaryTargetFromJson(jsonObject: JSONObject): TemporaryTarget? {
val units = JsonHelper.safeGetString(jsonObject, "units", Constants.MGDL)
val timestamp = JsonHelper.safeGetLongAllowNull(jsonObject, "mills", null) ?: return null
val duration = JsonHelper.safeGetLongAllowNull(jsonObject, "duration", null) ?: return null
var low = JsonHelper.safeGetDouble(jsonObject, "targetBottom")
low = Profile.toMgdl(low, units)
var high = JsonHelper.safeGetDouble(jsonObject, "targetTop")
high = Profile.toMgdl(high, units)
val reasonString = if (duration != 0L) JsonHelper.safeGetStringAllowNull(jsonObject, "reason", null)
?: return null else ""
// this string can be localized from NS, it will not work in this case CUSTOM will be used
val reason = TemporaryTarget.Reason.fromString(reasonString)
val id = JsonHelper.safeGetStringAllowNull(jsonObject, "_id", null) ?: return null
val isValid = JsonHelper.safeGetBoolean(jsonObject, NSUpload.ISVALID, true)
if (duration > 0L) {
// not ending event
if (units == Constants.MMOL) {
if (low < Constants.MIN_TT_MMOL) return null
if (low > Constants.MAX_TT_MMOL) return null
if (high < Constants.MIN_TT_MMOL) return null
if (high > Constants.MAX_TT_MMOL) return null
if (low > high) return null
} else {
if (low < Constants.MIN_TT_MGDL) return null
if (low > Constants.MAX_TT_MGDL) return null
if (high < Constants.MIN_TT_MGDL) return null
if (high > Constants.MAX_TT_MGDL) return null
if (low > high) return null
}
}
val tt = TemporaryTarget(
timestamp = timestamp,
duration = TimeUnit.MINUTES.toMillis(duration),
reason = reason,
lowTarget = low,
highTarget = high,
isValid = isValid
)
tt.interfaceIDs.nightscoutId = id
return tt
}

View file

@ -28,8 +28,8 @@ class DateUtilTest : TestBase() {
@Test
fun toISOStringTest() {
Assert.assertEquals("2017-12-22T00:32:30Z", DateUtil.toISOString(Date(1513902750000L)))
Assert.assertEquals("2017-12-22T00:32:30Z", DateUtil.toISOString(1513902750000L))
Assert.assertEquals("2017-12-22T00:32:30.000Z", DateUtil.toISOString(Date(1513902750000L)))
Assert.assertEquals("2017-12-22T00:32:30.000Z", DateUtil.toISOString(1513902750000L))
}
@Test fun toDateTest() {

View file

@ -91,7 +91,7 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
boolean previousValue = useExtendedBoluses;
useExtendedBoluses = sp.getBoolean(R.string.key_danar_useextended, false);
if (useExtendedBoluses != previousValue && activePlugin.getActiveTreatments().isInHistoryExtendedBoluslInProgress()) {
if (useExtendedBoluses != previousValue && activePlugin.getActiveTreatments().isInHistoryExtendedBolusInProgress()) {
sExecutionService.extendedBolusStop();
}
}
@ -197,9 +197,6 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) {
// Recheck pump status if older than 30 min
//This should not be needed while using queue because connection should be done before calling this
//if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) {
// connect("setTempBasalAbsolute old data");
//}
PumpEnactResult result = new PumpEnactResult(getInjector());
absoluteRate = constraintChecker.applyBasalConstraints(new Constraint<>(absoluteRate), profile).value();
@ -235,7 +232,7 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
if (doLowTemp || doHighTemp) {
int percentRate = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue();
// Any basal less than 0.10u/h will be dumped once per hour, not every 4 mins. So if it's less than .10u/h, set a zero temp.
// Any basal less than 0.10u/h will be dumped once per hour, not every 4 minutes. So if it's less than .10u/h, set a zero temp.
if (absoluteRate < 0.10d) percentRate = 0;
if (percentRate < 100) percentRate = Round.ceilTo((double) percentRate, 10d).intValue();
else percentRate = Round.floorTo((double) percentRate, 10d).intValue();
@ -273,7 +270,7 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
}
}
// Convert duration from minutes to hours
aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " mins (doLowTemp || doHighTemp)");
aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " minutes (doLowTemp || doHighTemp)");
return setTempBasalPercent(percentRate, durationInMinutes, profile, false);
}
if (doExtendedTemp) {
@ -294,7 +291,7 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
Double extendedRateToSet = absoluteRate - getBaseBasalRate();
extendedRateToSet = constraintChecker.applyBasalConstraints(new Constraint<>(extendedRateToSet), profile).value();
// needs to be rounded to 0.1
extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.extendedBolusStep * 2); // *2 because of halfhours
extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.extendedBolusStep * 2); // *2 because of half hours
// What is current rate of extended bolusing in u/h?
aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Extended bolus in progress: " + (activeExtended != null) + " rate: " + danaPump.getExtendedBolusAbsoluteRate() + "U/h duration remaining: " + danaPump.getExtendedBolusRemainingMinutes() + "min");
@ -315,7 +312,7 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
// Now set new extended, no need to to stop previous (if running) because it's replaced
double extendedAmount = extendedRateToSet / 2 * durationInHalfHours;
aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting extended: " + extendedAmount + "U halfhours: " + durationInHalfHours);
aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting extended: " + extendedAmount + "U half hours: " + durationInHalfHours);
result = setExtendedBolus(extendedAmount, durationInMinutes);
if (!result.success) {
aapsLogger.error("setTempBasalAbsolute: Failed to set extended bolus");
@ -336,7 +333,7 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
public PumpEnactResult cancelTempBasal(boolean force) {
if (activePlugin.getActiveTreatments().isInHistoryRealTempBasalInProgress())
return cancelRealTempBasal();
if (activePlugin.getActiveTreatments().isInHistoryExtendedBoluslInProgress() && useExtendedBoluses) {
if (activePlugin.getActiveTreatments().isInHistoryExtendedBolusInProgress() && useExtendedBoluses) {
return cancelExtendedBolus();
}
PumpEnactResult result = new PumpEnactResult(getInjector());
@ -374,13 +371,13 @@ public class DanaRKoreanPlugin extends AbstractDanaRPlugin {
return result;
}
@Override
@NonNull @Override
public PumpEnactResult loadEvents() {
return null; // no history, not needed
return new PumpEnactResult(getInjector()); // no history, not needed
}
@Override
@NonNull @Override
public PumpEnactResult setUserOptions() {
return null;
return new PumpEnactResult(getInjector());
}
}

View file

@ -88,7 +88,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
boolean previousValue = useExtendedBoluses;
useExtendedBoluses = sp.getBoolean(R.string.key_danar_useextended, false);
if (useExtendedBoluses != previousValue && activePlugin.getActiveTreatments().isInHistoryExtendedBoluslInProgress()) {
if (useExtendedBoluses != previousValue && activePlugin.getActiveTreatments().isInHistoryExtendedBolusInProgress()) {
sExecutionService.extendedBolusStop();
}
}
@ -192,12 +192,9 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
// This is called from APS
@NonNull @Override
public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, Profile profile, boolean enforceNew) {
public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew) {
// Recheck pump status if older than 30 min
//This should not be needed while using queue because connection should be done before calling this
//if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) {
// connect("setTempBasalAbsolute old data");
//}
PumpEnactResult result = new PumpEnactResult(getInjector());
absoluteRate = constraintChecker.applyBasalConstraints(new Constraint<>(absoluteRate), profile).value();
@ -232,8 +229,8 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
}
if (doLowTemp || doHighTemp) {
Integer percentRate = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue();
// Any basal less than 0.10u/h will be dumped once per hour, not every 4 mins. So if it's less than .10u/h, set a zero temp.
int percentRate = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue();
// Any basal less than 0.10u/h will be dumped once per hour, not every 4 minutes. So if it's less than .10u/h, set a zero temp.
if (absoluteRate < 0.10d) percentRate = 0;
if (percentRate < 100) percentRate = Round.ceilTo((double) percentRate, 10d).intValue();
else percentRate = Round.floorTo((double) percentRate, 10d).intValue();
@ -271,7 +268,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
}
}
// Convert duration from minutes to hours
aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " mins (doLowTemp || doHighTemp)");
aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " minutes (doLowTemp || doHighTemp)");
return setTempBasalPercent(percentRate, durationInMinutes, profile, false);
}
if (doExtendedTemp) {
@ -292,7 +289,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
Double extendedRateToSet = absoluteRate - getBaseBasalRate();
extendedRateToSet = constraintChecker.applyBasalConstraints(new Constraint<>(extendedRateToSet), profile).value();
// needs to be rounded to 0.1
extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.extendedBolusStep * 2); // *2 because of halfhours
extendedRateToSet = Round.roundTo(extendedRateToSet, pumpDescription.extendedBolusStep * 2); // *2 because of half hours
// What is current rate of extended bolusing in u/h?
aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Extended bolus in progress: " + (activeExtended != null) + " rate: " + danaPump.getExtendedBolusAbsoluteRate() + "U/h duration remaining: " + danaPump.getExtendedBolusRemainingMinutes() + "min");
@ -313,7 +310,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
// Now set new extended, no need to to stop previous (if running) because it's replaced
double extendedAmount = extendedRateToSet / 2 * durationInHalfHours;
aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting extended: " + extendedAmount + "U halfhours: " + durationInHalfHours);
aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute: Setting extended: " + extendedAmount + "U half hours: " + durationInHalfHours);
result = setExtendedBolus(extendedAmount, durationInMinutes);
if (!result.success) {
aapsLogger.error("setTempBasalAbsolute: Failed to set extended bolus");
@ -334,7 +331,7 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
public PumpEnactResult cancelTempBasal(boolean force) {
if (activePlugin.getActiveTreatments().isInHistoryRealTempBasalInProgress())
return cancelRealTempBasal();
if (activePlugin.getActiveTreatments().isInHistoryExtendedBoluslInProgress() && useExtendedBoluses) {
if (activePlugin.getActiveTreatments().isInHistoryExtendedBolusInProgress() && useExtendedBoluses) {
return cancelExtendedBolus();
}
PumpEnactResult result = new PumpEnactResult(getInjector());
@ -363,22 +360,21 @@ public class DanaRPlugin extends AbstractDanaRPlugin {
result.isTempCancel = true;
result.comment = resourceHelper.gs(R.string.ok);
aapsLogger.debug(LTag.PUMP, "cancelRealTempBasal: OK");
return result;
} else {
result.success = false;
result.comment = resourceHelper.gs(R.string.danar_valuenotsetproperly);
result.isTempCancel = true;
aapsLogger.error("cancelRealTempBasal: Failed to cancel temp basal");
return result;
}
return result;
}
@Override
@NonNull @Override
public PumpEnactResult loadEvents() {
return null; // no history, not needed
return new PumpEnactResult(getInjector()); // no history, not needed
}
@Override
@NonNull @Override
public PumpEnactResult setUserOptions() {
return sExecutionService.setUserOptions();
}

View file

@ -24,8 +24,6 @@ class AppRepository @Inject internal constructor(
fun changeObservable(): Observable<List<DBEntry>> = changeSubject.subscribeOn(Schedulers.io())
val databaseVersion = DATABASE_VERSION
/**
* Executes a transaction ignoring its result
* Runs on IO scheduler
@ -88,16 +86,25 @@ class AppRepository @Inject internal constructor(
.subscribeOn(Schedulers.io())
// TEMP TARGETS
fun compatGetTemporaryTargetData(): List<TemporaryTarget> =
database.temporaryTargetDao.compatGetTemporaryTargetData()
fun compatGetTemporaryTargetData(): Single<List<TemporaryTarget>> =
database.temporaryTargetDao.getTemporaryTargetData()
.subscribeOn(Schedulers.io())
fun compatGetTemporaryTargetDataFromTime(timestamp: Long, ascending: Boolean): Single<List<TemporaryTarget>> =
database.temporaryTargetDao.compatGetTemporaryTargetDataFromTime(timestamp)
fun getTemporaryTargetDataFromTime(timestamp: Long, ascending: Boolean): Single<List<TemporaryTarget>> =
database.temporaryTargetDao.getTemporaryTargetDataFromTime(timestamp)
.map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io())
fun findTemporaryTargetByNSIdSingle(nsId: String): Single<ValueWrapper<TemporaryTarget>> =
database.temporaryTargetDao.findByNSIdMaybe(nsId).toWrappedSingle()
fun getTemporaryTargetDataIncludingInvalidFromTime(timestamp: Long, ascending: Boolean): Single<List<TemporaryTarget>> =
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<List<TemporaryTarget>> =
database.temporaryTargetDao.getModifiedFrom(lastId)
@ -106,6 +113,14 @@ class AppRepository @Inject internal constructor(
fun getTemporaryTargetsCorrespondingLastHistoryRecord(lastId: Long): TemporaryTarget? =
database.temporaryTargetDao.getLastHistoryRecord(lastId)
fun getTemporaryTargetActiveAt(timestamp: Long): Single<ValueWrapper<TemporaryTarget>> =
database.temporaryTargetDao.getTemporaryTargetActiveAt(timestamp)
.subscribeOn(Schedulers.io())
.toWrappedSingle()
fun deleteAllTempTargetEntries() =
database.temporaryTargetDao.deleteAllEntries()
// USER ENTRY
fun getAllUserEntries(): Single<List<UserEntry>> =
database.userEntryDao.getAll()

View file

@ -5,7 +5,6 @@ import androidx.room.Query
import info.nightscout.androidaps.database.TABLE_TEMPORARY_TARGETS
import info.nightscout.androidaps.database.entities.TemporaryTarget
import io.reactivex.Maybe
import io.reactivex.Observable
import io.reactivex.Single
@Suppress("FunctionName")
@ -19,16 +18,22 @@ internal interface TemporaryTargetDao : TraceableDao<TemporaryTarget> {
override fun deleteAllEntries()
@Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE nightscoutId = :nsId AND referenceId IS NULL")
fun findByNSIdMaybe(nsId: String): Maybe<TemporaryTarget>
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): TemporaryTarget?
fun getTemporaryTargetActiveAt(timestamp: Long): Maybe<TemporaryTarget>
@Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE timestamp >= :timestamp AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC")
fun compatGetTemporaryTargetDataFromTime(timestamp: Long): Single<List<TemporaryTarget>>
fun getTemporaryTargetDataFromTime(timestamp: Long): Single<List<TemporaryTarget>>
@Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE timestamp >= :timestamp AND referenceId IS NULL ORDER BY timestamp ASC")
fun getTemporaryTargetDataIncludingInvalidFromTime(timestamp: Long): Single<List<TemporaryTarget>>
@Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC")
fun compatGetTemporaryTargetData(): List<TemporaryTarget>
fun getTemporaryTargetData(): Single<List<TemporaryTarget>>
@Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE referenceId = :id ORDER BY id DESC LIMIT 1")
fun getLastHistoryRecord(id: Long): TemporaryTarget?

View file

@ -57,11 +57,13 @@ data class TemporaryTarget(
@SerializedName("Eating Soon")
EATING_SOON("Eating Soon"),
@SerializedName("Automation")
AUTOMATION("Automation")
AUTOMATION("Automation"),
@SerializedName("Wear")
WEAR("Wear")
;
companion object {
fun fromString(direction: String?) = values().firstOrNull { it.text == direction }
fun fromString(reason: String?) = values().firstOrNull { it.text == reason }
?: CUSTOM
}
}

View file

@ -5,12 +5,21 @@ import info.nightscout.androidaps.database.interfaces.end
class CancelCurrentTemporaryTargetIfAnyTransaction(
val timestamp: Long
) : Transaction<Unit>() {
override fun run() {
val current = database.temporaryTargetDao.getTemporaryTargetActiveAt(timestamp)
) : Transaction<CancelCurrentTemporaryTargetIfAnyTransaction.TransactionResult>() {
override fun run(): TransactionResult {
val result = TransactionResult()
val current = database.temporaryTargetDao.getTemporaryTargetActiveAt(timestamp).blockingGet()
if (current != null) {
current.end = timestamp
database.temporaryTargetDao.updateExistingEntry(current)
result.updated.add(current)
}
return result
}
class TransactionResult {
val updated = mutableListOf<TemporaryTarget>()
}
}

View file

@ -4,18 +4,27 @@ import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.interfaces.end
class InsertTemporaryTargetAndCancelCurrentTransaction(
private val temporaryTarget: TemporaryTarget
) : Transaction<Unit>() {
val temporaryTarget: TemporaryTarget
) : Transaction<InsertTemporaryTargetAndCancelCurrentTransaction.TransactionResult>() {
constructor(timestamp: Long, duration: Long, reason: TemporaryTarget.Reason, lowTarget: Double, highTarget: Double) :
this(TemporaryTarget(timestamp = timestamp, reason = reason, lowTarget = lowTarget, highTarget = highTarget, duration = duration))
override fun run() {
val current = database.temporaryTargetDao.getTemporaryTargetActiveAt(temporaryTarget.timestamp)
override fun run(): TransactionResult {
val result = TransactionResult()
val current = database.temporaryTargetDao.getTemporaryTargetActiveAt(temporaryTarget.timestamp).blockingGet()
if (current != null) {
current.end = temporaryTarget.timestamp
database.temporaryTargetDao.updateExistingEntry(current)
result.updated.add(current)
}
database.temporaryTargetDao.insertNewEntry(temporaryTarget)
result.inserted.add(temporaryTarget)
return result
}
class TransactionResult {
val inserted = mutableListOf<TemporaryTarget>()
val updated = mutableListOf<TemporaryTarget>()
}
}

View file

@ -0,0 +1,71 @@
package info.nightscout.androidaps.database.transactions
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.interfaces.end
import kotlin.math.abs
/**
* Sync the TemporaryTarget from NS
*/
class SyncTemporaryTargetTransaction(private val temporaryTarget: TemporaryTarget) : Transaction<SyncTemporaryTargetTransaction.TransactionResult>() {
override fun run(): TransactionResult {
val result = TransactionResult()
if (temporaryTarget.duration != 0L) {
// not ending event
val current: TemporaryTarget? =
temporaryTarget.interfaceIDs.nightscoutId?.let {
database.temporaryTargetDao.findByNSId(it)
}
if (current != null) {
// nsId exists, allow only invalidation
if (current.isValid && !temporaryTarget.isValid) {
current.isValid = false
database.temporaryTargetDao.updateExistingEntry(current)
result.invalidated.add(current)
}
return result
}
// not known nsId
val running = database.temporaryTargetDao.getTemporaryTargetActiveAt(temporaryTarget.timestamp).blockingGet()
if (running != null && abs(running.timestamp - temporaryTarget.timestamp) < 1000 && running.interfaceIDs.nightscoutId == null) { // allow missing milliseconds
// the same record, update nsId only
running.interfaceIDs.nightscoutId = temporaryTarget.interfaceIDs.nightscoutId
database.temporaryTargetDao.updateExistingEntry(running)
result.updatedNsId.add(running)
} else if (running != null) {
// another running record. end current and insert new
running.end = temporaryTarget.timestamp
database.temporaryTargetDao.updateExistingEntry(running)
database.temporaryTargetDao.insertNewEntry(temporaryTarget)
result.ended.add(running)
result.inserted.add(temporaryTarget)
} else {
database.temporaryTargetDao.insertNewEntry(temporaryTarget)
result.inserted.add(temporaryTarget)
}
return result
} else {
// ending event
val running = database.temporaryTargetDao.getTemporaryTargetActiveAt(temporaryTarget.timestamp).blockingGet()
if (running != null) {
running.end = temporaryTarget.timestamp
database.temporaryTargetDao.updateExistingEntry(running)
result.ended.add(running)
}
}
return result
}
class TransactionResult {
val updatedNsId = mutableListOf<TemporaryTarget>()
val inserted = mutableListOf<TemporaryTarget>()
val invalidated = mutableListOf<TemporaryTarget>()
val ended = mutableListOf<TemporaryTarget>()
}
}

View file

@ -31,6 +31,9 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.InsightBolusID;
import info.nightscout.androidaps.db.InsightHistoryOffset;
import info.nightscout.androidaps.db.InsightPumpID;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TDD;
import info.nightscout.androidaps.db.TemporaryBasal;
@ -108,9 +111,6 @@ import info.nightscout.androidaps.plugins.pump.insight.app_layer.status.GetPumpS
import info.nightscout.androidaps.plugins.pump.insight.app_layer.status.GetTotalDailyDoseMessage;
import info.nightscout.androidaps.plugins.pump.insight.app_layer.status.ResetPumpStatusRegisterMessage;
import info.nightscout.androidaps.plugins.pump.insight.connection_service.InsightConnectionService;
import info.nightscout.androidaps.db.InsightBolusID;
import info.nightscout.androidaps.db.InsightHistoryOffset;
import info.nightscout.androidaps.db.InsightPumpID;
import info.nightscout.androidaps.plugins.pump.insight.descriptors.ActiveBasalRate;
import info.nightscout.androidaps.plugins.pump.insight.descriptors.ActiveBolus;
import info.nightscout.androidaps.plugins.pump.insight.descriptors.ActiveTBR;
@ -131,7 +131,6 @@ import info.nightscout.androidaps.plugins.pump.insight.exceptions.app_layer_erro
import info.nightscout.androidaps.plugins.pump.insight.utils.ExceptionTranslator;
import info.nightscout.androidaps.plugins.pump.insight.utils.ParameterBlockUtil;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.TimeChangeType;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
@ -998,6 +997,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
try {
extended.put("ActiveProfile", profileFunction.getProfileName());
} catch (Exception e) {
e.printStackTrace();
}
TemporaryBasal tb = treatmentsPlugin.getTempBasalFromHistory(now);
if (tb != null) {
@ -1576,7 +1576,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
careportalEvent.eventType = CareportalEvent.NOTE;
careportalEvent.json = data.toString();
databaseHelper.createOrUpdate(careportalEvent);
nsUpload.uploadCareportalEntryToNS(data);
nsUpload.uploadCareportalEntryToNS(data, date);
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
@ -1610,7 +1610,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
careportalEvent.eventType = event;
careportalEvent.json = data.toString();
databaseHelper.createOrUpdate(careportalEvent);
nsUpload.uploadCareportalEntryToNS(data);
nsUpload.uploadCareportalEntryToNS(data, date);
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
@ -1681,8 +1681,4 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
return true;
}
@Override
public void timezoneOrDSTChanged(TimeChangeType changeType) {
}
}

View file

@ -595,7 +595,7 @@ public class MedtronicHistoryData {
careportalEvent.eventType = event;
careportalEvent.json = data.toString();
databaseHelper.createOrUpdate(careportalEvent);
nsUpload.uploadCareportalEntryToNS(data);
nsUpload.uploadCareportalEntryToNS(data, date);
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}

View file

@ -1022,7 +1022,7 @@ public class AapsOmnipodErosManager {
careportalEvent.eventType = event;
careportalEvent.json = data.toString();
databaseHelper.createOrUpdate(careportalEvent);
nsUpload.uploadCareportalEntryToNS(data);
nsUpload.uploadCareportalEntryToNS(data, date);
} catch (JSONException e) {
aapsLogger.error(LTag.PUMPCOMM, "Unhandled exception when uploading SiteChange event.", e);
}