Profile sync, removed NSProfile

This commit is contained in:
Milos Kozak 2021-05-04 21:07:47 +02:00
parent 88f5eec306
commit 0f2f5cd1fa
33 changed files with 516 additions and 1521 deletions

View file

@ -1,7 +1,5 @@
package info.nightscout.androidaps.data.defaultProfile
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.data.ProfileImplOld
import info.nightscout.androidaps.data.PureProfile
import info.nightscout.androidaps.extensions.pureProfileFromJson
import info.nightscout.androidaps.interfaces.GlucoseUnit

View file

@ -1,7 +1,6 @@
package info.nightscout.androidaps.data.defaultProfile
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.data.ProfileImplOld
import info.nightscout.androidaps.data.PureProfile
import info.nightscout.androidaps.extensions.pureProfileFromJson
import info.nightscout.androidaps.interfaces.GlucoseUnit

View file

@ -29,7 +29,6 @@ import info.nightscout.androidaps.plugins.general.tidepool.TidepoolFragment
import info.nightscout.androidaps.plugins.general.wear.WearFragment
import info.nightscout.androidaps.plugins.insulin.InsulinFragment
import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment
import info.nightscout.androidaps.plugins.profile.ns.NSProfileFragment
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment
import info.nightscout.androidaps.plugins.source.BGSourceFragment
import info.nightscout.androidaps.plugins.treatments.TreatmentsFragment
@ -46,8 +45,7 @@ abstract class FragmentsModule {
@ContributesAndroidInjector abstract fun contributesAutomationFragment(): AutomationFragment
@ContributesAndroidInjector abstract fun contributesBGSourceFragment(): BGSourceFragment
@ContributesAndroidInjector
abstract fun contributesConfigBuilderFragment(): ConfigBuilderFragment
@ContributesAndroidInjector abstract fun contributesConfigBuilderFragment(): ConfigBuilderFragment
@ContributesAndroidInjector abstract fun contributesFoodFragment(): FoodFragment
@ContributesAndroidInjector abstract fun contributesInsulinFragment(): InsulinFragment
@ -58,10 +56,8 @@ abstract class FragmentsModule {
@ContributesAndroidInjector abstract fun contributesOverviewFragment(): OverviewFragment
@ContributesAndroidInjector abstract fun contributesLoopFragment(): LoopFragment
@ContributesAndroidInjector abstract fun contributesMaintenanceFragment(): MaintenanceFragment
@ContributesAndroidInjector abstract fun contributesNSProfileFragment(): NSProfileFragment
@ContributesAndroidInjector abstract fun contributesNSClientFragment(): NSClientFragment
@ContributesAndroidInjector
abstract fun contributesSmsCommunicatorFragment(): SmsCommunicatorFragment
@ContributesAndroidInjector abstract fun contributesSmsCommunicatorFragment(): SmsCommunicatorFragment
@ContributesAndroidInjector abstract fun contributesWearFragment(): WearFragment
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
@ -85,8 +81,7 @@ abstract class FragmentsModule {
@ContributesAndroidInjector abstract fun contributesEditEventDialog(): EditEventDialog
@ContributesAndroidInjector abstract fun contributesEditTriggerDialog(): EditTriggerDialog
@ContributesAndroidInjector
abstract fun contributesEditQuickWizardDialog(): EditQuickWizardDialog
@ContributesAndroidInjector abstract fun contributesEditQuickWizardDialog(): EditQuickWizardDialog
@ContributesAndroidInjector abstract fun contributesExtendedBolusDialog(): ExtendedBolusDialog
@ContributesAndroidInjector abstract fun contributesFillDialog(): FillDialog
@ -102,8 +97,7 @@ abstract class FragmentsModule {
@ContributesAndroidInjector abstract fun contributesWizardDialog(): WizardDialog
@ContributesAndroidInjector abstract fun contributesWizardInfoDialog(): WizardInfoDialog
@ContributesAndroidInjector
abstract fun contributesExchangeAuthTokenDialot(): OpenHumansLoginActivity.ExchangeAuthTokenDialog
@ContributesAndroidInjector abstract fun contributesExchangeAuthTokenDialog(): OpenHumansLoginActivity.ExchangeAuthTokenDialog
@ContributesAndroidInjector abstract fun contributesPasswordCheck(): PasswordCheck
}

View file

@ -37,7 +37,6 @@ import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin
import info.nightscout.androidaps.plugins.insulin.InsulinOrefUltraRapidActingPlugin
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
import info.nightscout.androidaps.plugins.pump.mdi.MDIPlugin
@ -192,12 +191,6 @@ abstract class PluginsModule {
@IntKey(220)
abstract fun bindOpenAPSSMBPlugin(plugin: OpenAPSSMBPlugin): PluginBase
@Binds
@AllConfigs
@IntoMap
@IntKey(230)
abstract fun bindNSProfilePlugin(plugin: NSProfilePlugin): PluginBase
@Binds
@NotNSClient
@IntoMap

View file

@ -9,7 +9,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.NSClientMbgWorker
import info.nightscout.androidaps.plugins.general.nsclient.NSClientRemoveWorker
import info.nightscout.androidaps.plugins.general.nsclient.NSClientUpdateRemoveAckWorker
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
import info.nightscout.androidaps.plugins.source.*
@Module
@ -24,7 +24,7 @@ abstract class WorkersModule {
@ContributesAndroidInjector abstract fun contributesTomatoWorker(): TomatoPlugin.TomatoWorker
@ContributesAndroidInjector abstract fun contributesEversenseWorker(): EversensePlugin.EversenseWorker
@ContributesAndroidInjector abstract fun contributesNSClientSourceWorker(): NSClientSourcePlugin.NSClientSourceWorker
@ContributesAndroidInjector abstract fun contributesNSProfileWorker(): NSProfilePlugin.NSProfileWorker
@ContributesAndroidInjector abstract fun contributesNSProfileWorker(): LocalProfilePlugin.NSProfileWorker
@ContributesAndroidInjector abstract fun contributesSmsCommunicatorWorker(): SmsCommunicatorPlugin.SmsCommunicatorWorker
@ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientAddUpdateWorker
@ContributesAndroidInjector abstract fun contributesNSClientAddAckWorker(): NSClientAddAckWorker

View file

@ -2,14 +2,13 @@ package info.nightscout.androidaps.plugins.general.nsclient
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.DeviceStatus
import info.nightscout.androidaps.database.entities.*
import info.nightscout.androidaps.extensions.toJson
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.DataSyncSelector
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.extensions.toJson
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -26,6 +25,23 @@ class DataSyncSelectorImplementation @Inject constructor(
private val localProfilePlugin: LocalProfilePlugin
) : DataSyncSelector {
override fun doUpload() {
if (sp.getBoolean(R.string.key_ns_upload, true)) {
processChangedBolusesCompat()
processChangedCarbsCompat()
processChangedBolusCalculatorResultsCompat()
processChangedTemporaryBasalsCompat()
processChangedExtendedBolusesCompat()
processChangedProfileSwitchesCompat()
processChangedGlucoseValuesCompat()
processChangedTempTargetsCompat()
processChangedFoodsCompat()
processChangedTherapyEventsCompat()
processChangedDeviceStatusesCompat()
processChangedProfileStore()
}
}
override fun resetToNextFullSync() {
sp.remove(R.string.key_ns_temporary_target_last_synced_id)
sp.remove(R.string.key_ns_glucose_value_last_synced_id)
@ -459,8 +475,7 @@ class DataSyncSelectorImplementation @Inject constructor(
if (lastChange == 0L) return
localProfilePlugin.createProfileStore()
val profileJson = localProfilePlugin.profile?.data ?: return
if (sp.getBoolean(R.string.key_ns_uploadlocalprofile, false))
if (lastChange > lastSync)
nsClientPlugin.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()))
if (lastChange > lastSync)
nsClientPlugin.nsClientService?.dbAdd("profile", profileJson, DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()))
}
}

View file

@ -49,9 +49,6 @@ class NSClientAddUpdateWorker(
@Inject lateinit var uel: UserEntryLogger
override fun doWork(): Result {
val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT
if (!acceptNSData) return Result.success()
val treatments = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data"))
@ -75,62 +72,66 @@ class NSClientAddUpdateWorker(
if (mills > latestDateInReceivedData) latestDateInReceivedData = mills
if (insulin > 0) {
bolusFromJson(json)?.let { bolus ->
repository.runTransactionForResult(SyncNsBolusTransaction(bolus, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(Action.BOLUS, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount)
)
aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it")
if (sp.getBoolean(R.string.key_ns_receive_insulin, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
bolusFromJson(json)?.let { bolus ->
repository.runTransactionForResult(SyncNsBolusTransaction(bolus, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving bolus", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
result.invalidated.forEach {
uel.log(Action.BOLUS_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated bolus $it")
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(Action.BOLUS, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount)
)
aapsLogger.debug(LTag.DATABASE, "Inserted bolus $it")
}
result.invalidated.forEach {
uel.log(Action.BOLUS_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated bolus $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId bolus $it")
}
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId bolus $it")
}
}
} ?: aapsLogger.error("Error parsing bolus json $json")
} ?: aapsLogger.error("Error parsing bolus json $json")
}
}
if (carbs > 0) {
carbsFromJson(json)?.let { carb ->
repository.runTransactionForResult(SyncNsCarbsTransaction(carb, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(Action.CARBS, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Gram(it.amount.toInt())
)
aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it")
if (sp.getBoolean(R.string.key_ns_receive_carbs, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
carbsFromJson(json)?.let { carb ->
repository.runTransactionForResult(SyncNsCarbsTransaction(carb, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving carbs", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
result.invalidated.forEach {
uel.log(Action.CARBS_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Gram(it.amount.toInt())
)
aapsLogger.debug(LTag.DATABASE, "Invalidated carbs $it")
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(Action.CARBS, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Gram(it.amount.toInt())
)
aapsLogger.debug(LTag.DATABASE, "Inserted carbs $it")
}
result.invalidated.forEach {
uel.log(Action.CARBS_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Gram(it.amount.toInt())
)
aapsLogger.debug(LTag.DATABASE, "Invalidated carbs $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId carbs $it")
}
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId carbs $it")
}
}
} ?: aapsLogger.error("Error parsing bolus json $json")
} ?: aapsLogger.error("Error parsing bolus json $json")
}
}
// Convert back emulated TBR -> EB
if (eventType == TherapyEvent.Type.TEMPORARY_BASAL.text && json.has("extendedEmulated")) {
@ -142,46 +143,48 @@ class NSClientAddUpdateWorker(
when {
insulin > 0 || carbs > 0 -> Any()
eventType == TherapyEvent.Type.TEMPORARY_TARGET.text ->
temporaryTargetFromJson(json)?.let { temporaryTarget ->
repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach { tt ->
uel.log(Action.TT, Sources.NSClient,
ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit.fromGlucoseUnit(tt.lowTarget, Constants.MGDL),
ValueWithUnit.fromGlucoseUnit(tt.highTarget, Constants.MGDL).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryTarget $tt")
if (sp.getBoolean(R.string.key_ns_receive_temp_target, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
temporaryTargetFromJson(json)?.let { temporaryTarget ->
repository.runTransactionForResult(SyncNsTemporaryTargetTransaction(temporaryTarget, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
result.invalidated.forEach { tt ->
uel.log(Action.TT_REMOVED, Sources.NSClient,
ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit.Mgdl(tt.lowTarget),
ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryTarget $tt")
.blockingGet()
.also { result ->
result.inserted.forEach { tt ->
uel.log(Action.TT, Sources.NSClient,
ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit.fromGlucoseUnit(tt.lowTarget, Constants.MGDL),
ValueWithUnit.fromGlucoseUnit(tt.highTarget, Constants.MGDL).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryTarget $tt")
}
result.invalidated.forEach { tt ->
uel.log(Action.TT_REMOVED, Sources.NSClient,
ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit.Mgdl(tt.lowTarget),
ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryTarget $tt")
}
result.ended.forEach { tt ->
uel.log(Action.CANCEL_TT, Sources.NSClient,
ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit.Mgdl(tt.lowTarget),
ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Updated TemporaryTarget $tt")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryTarget $it")
}
}
result.ended.forEach { tt ->
uel.log(Action.CANCEL_TT, Sources.NSClient,
ValueWithUnit.TherapyEventTTReason(tt.reason),
ValueWithUnit.Mgdl(tt.lowTarget),
ValueWithUnit.Mgdl(tt.highTarget).takeIf { tt.lowTarget != tt.highTarget },
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tt.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Updated TemporaryTarget $tt")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryTarget $it")
}
}
} ?: aapsLogger.error("Error parsing TT json $json")
} ?: aapsLogger.error("Error parsing TT json $json")
}
eventType == TherapyEvent.Type.CANNULA_CHANGE.text ||
eventType == TherapyEvent.Type.INSULIN_CHANGE.text ||
eventType == TherapyEvent.Type.SENSOR_CHANGE.text ||
@ -192,158 +195,167 @@ class NSClientAddUpdateWorker(
eventType == TherapyEvent.Type.EXERCISE.text ||
eventType == TherapyEvent.Type.APS_OFFLINE.text ||
eventType == TherapyEvent.Type.PUMP_BATTERY_CHANGE.text ->
therapyEventFromJson(json)?.let { therapyEvent ->
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
val action = when (eventType) {
TherapyEvent.Type.CANNULA_CHANGE.text -> Action.SITE_CHANGE
TherapyEvent.Type.INSULIN_CHANGE.text -> Action.RESERVOIR_CHANGE
else -> Action.CAREPORTAL
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT) {
therapyEventFromJson(json)?.let { therapyEvent ->
repository.runTransactionForResult(SyncNsTherapyEventTransaction(therapyEvent, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
result.inserted.forEach {
uel.log(action, Sources.NSClient,
it.note ?: "",
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.TherapyEventType(it.type)
)
aapsLogger.debug(LTag.DATABASE, "Inserted TherapyEvent $it")
.blockingGet()
.also { result ->
val action = when (eventType) {
TherapyEvent.Type.CANNULA_CHANGE.text -> Action.SITE_CHANGE
TherapyEvent.Type.INSULIN_CHANGE.text -> Action.RESERVOIR_CHANGE
else -> Action.CAREPORTAL
}
result.inserted.forEach {
uel.log(action, Sources.NSClient,
it.note ?: "",
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.TherapyEventType(it.type)
)
aapsLogger.debug(LTag.DATABASE, "Inserted TherapyEvent $it")
}
result.invalidated.forEach {
uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient,
it.note ?: "",
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.TherapyEventType(it.type)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated TherapyEvent $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TherapyEvent $it")
}
}
result.invalidated.forEach {
uel.log(Action.CAREPORTAL_REMOVED, Sources.NSClient,
it.note ?: "",
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.TherapyEventType(it.type)
)
aapsLogger.debug(LTag.DATABASE, "Invalidated TherapyEvent $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TherapyEvent $it")
}
}
} ?: aapsLogger.error("Error parsing TherapyEvent json $json")
} ?: aapsLogger.error("Error parsing TherapyEvent json $json")
}
eventType == TherapyEvent.Type.COMBO_BOLUS.text ->
extendedBolusFromJson(json)?.let { extendedBolus ->
repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBolus, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving extended bolus", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(Action.EXTENDED_BOLUS, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Inserted ExtendedBolus $it")
if (config.NSCLIENT) {
extendedBolusFromJson(json)?.let { extendedBolus ->
repository.runTransactionForResult(SyncNsExtendedBolusTransaction(extendedBolus, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving extended bolus", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
result.invalidated.forEach {
uel.log(Action.EXTENDED_BOLUS_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Invalidated ExtendedBolus $it")
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(Action.EXTENDED_BOLUS, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Inserted ExtendedBolus $it")
}
result.invalidated.forEach {
uel.log(Action.EXTENDED_BOLUS_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Invalidated ExtendedBolus $it")
}
result.ended.forEach {
uel.log(Action.CANCEL_EXTENDED_BOLUS, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Updated ExtendedBolus $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId ExtendedBolus $it")
}
}
result.ended.forEach {
uel.log(Action.CANCEL_EXTENDED_BOLUS, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.Insulin(it.amount),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Updated ExtendedBolus $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId ExtendedBolus $it")
}
}
} ?: aapsLogger.error("Error parsing ExtendedBolus json $json")
} ?: aapsLogger.error("Error parsing ExtendedBolus json $json")
}
eventType == TherapyEvent.Type.TEMPORARY_BASAL.text ->
temporaryBasalFromJson(json)?.let { temporaryBasal ->
repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasal, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving temporary basal", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(Action.TEMP_BASAL, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it")
if (config.NSCLIENT) {
temporaryBasalFromJson(json)?.let { temporaryBasal ->
repository.runTransactionForResult(SyncNsTemporaryBasalTransaction(temporaryBasal, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving temporary basal", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
result.invalidated.forEach {
uel.log(Action.TEMP_BASAL_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryBasal $it")
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(Action.TEMP_BASAL, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Inserted TemporaryBasal $it")
}
result.invalidated.forEach {
uel.log(Action.TEMP_BASAL_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Invalidated TemporaryBasal $it")
}
result.ended.forEach {
uel.log(Action.CANCEL_TEMP_BASAL, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Ended TemporaryBasal $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryBasal $it")
}
}
result.ended.forEach {
uel.log(Action.CANCEL_TEMP_BASAL, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp),
ValueWithUnit.UnitPerHour(it.rate),
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(it.duration).toInt())
)
aapsLogger.debug(LTag.DATABASE, "Ended TemporaryBasal $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId TemporaryBasal $it")
}
}
} ?: aapsLogger.error("Error parsing TemporaryBasal json $json")
} ?: aapsLogger.error("Error parsing TemporaryBasal json $json")
}
eventType == TherapyEvent.Type.PROFILE_SWITCH.text ->
profileSwitchFromJson(json, dateUtil, activePlugin)?.let { profileSwitch ->
repository.runTransactionForResult(SyncNsProfileSwitchTransaction(profileSwitch, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving ProfileSwitch", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(Action.PROFILE_SWITCH, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp))
aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it")
if (sp.getBoolean(R.string.key_ns_receive_profile_switch, false) && buildHelper.isEngineeringMode() || config.NSCLIENT) {
profileSwitchFromJson(json, dateUtil, activePlugin)?.let { profileSwitch ->
repository.runTransactionForResult(SyncNsProfileSwitchTransaction(profileSwitch, invalidateByNsOnly = false))
.doOnError {
aapsLogger.error(LTag.DATABASE, "Error while saving ProfileSwitch", it)
ret = Result.failure(workDataOf("Error" to it.toString()))
}
result.invalidated.forEach {
uel.log(Action.PROFILE_SWITCH_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp))
aapsLogger.debug(LTag.DATABASE, "Invalidated ProfileSwitch $it")
.blockingGet()
.also { result ->
result.inserted.forEach {
uel.log(Action.PROFILE_SWITCH, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp))
aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it")
}
result.invalidated.forEach {
uel.log(Action.PROFILE_SWITCH_REMOVED, Sources.NSClient,
ValueWithUnit.Timestamp(it.timestamp))
aapsLogger.debug(LTag.DATABASE, "Invalidated ProfileSwitch $it")
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId ProfileSwitch $it")
}
}
result.updatedNsId.forEach {
aapsLogger.debug(LTag.DATABASE, "Updated nsId ProfileSwitch $it")
}
}
} ?: aapsLogger.error("Error parsing ProfileSwitch json $json")
} ?: aapsLogger.error("Error parsing ProfileSwitch json $json")
}
}
if (eventType == TherapyEvent.Type.ANNOUNCEMENT.text) {
val date = safeGetLong(json, "mills")
val now = System.currentTimeMillis()
val enteredBy = JsonHelper.safeGetString(json, "enteredBy", "")
val notes = JsonHelper.safeGetString(json, "notes", "")
if (date > now - 15 * 60 * 1000L && notes.isNotEmpty()
&& enteredBy != sp.getString("careportal_enteredby", "AndroidAPS")) {
val defaultVal = config.NSCLIENT
if (sp.getBoolean(R.string.key_ns_announcements, defaultVal)) {
val announcement = Notification(Notification.NS_ANNOUNCEMENT, notes, Notification.ANNOUNCEMENT, 60)
rxBus.send(EventNewNotification(announcement))
if (sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT)
if (eventType == TherapyEvent.Type.ANNOUNCEMENT.text) {
val date = safeGetLong(json, "mills")
val now = System.currentTimeMillis()
val enteredBy = JsonHelper.safeGetString(json, "enteredBy", "")
val notes = JsonHelper.safeGetString(json, "notes", "")
if (date > now - 15 * 60 * 1000L && notes.isNotEmpty()
&& enteredBy != sp.getString("careportal_enteredby", "AndroidAPS")) {
val defaultVal = config.NSCLIENT
if (sp.getBoolean(R.string.key_ns_announcements, defaultVal)) {
val announcement = Notification(Notification.NS_ANNOUNCEMENT, notes, Notification.ANNOUNCEMENT, 60)
rxBus.send(EventNewNotification(announcement))
}
}
}
}
}
nsClientPlugin.updateLatestDateReceivedIfNewer(latestDateInReceivedData)
return ret

View file

@ -8,13 +8,13 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.transactions.SyncNsTherapyEventTransaction
import info.nightscout.androidaps.extensions.therapyEventFromNsMbg
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg
import info.nightscout.androidaps.receivers.DataWorker
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.extensions.therapyEventFromNsMbg
import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject
@ -33,7 +33,7 @@ class NSClientMbgWorker(
override fun doWork(): Result {
var ret = Result.success()
val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT
val acceptNSData = sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT
if (!acceptNSData) return ret
val mbgArray = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))

View file

@ -8,6 +8,7 @@ import android.os.Handler
import android.os.HandlerThread
import android.os.IBinder
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreference
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
@ -147,25 +148,17 @@ class NSClientPlugin @Inject constructor(
override fun preprocessPreferences(preferenceFragment: PreferenceFragmentCompat) {
super.preprocessPreferences(preferenceFragment)
if (config.NSCLIENT) {
val key_ns_uploadlocalprofile = preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_uploadlocalprofile))
if (key_ns_uploadlocalprofile != null) key_ns_uploadlocalprofile.isVisible = false
val key_ns_autobackfill = preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_autobackfill))
if (key_ns_autobackfill != null) key_ns_autobackfill.isVisible = false
val key_ns_create_announcements_from_errors = preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_create_announcements_from_errors))
if (key_ns_create_announcements_from_errors != null) key_ns_create_announcements_from_errors.isVisible = false
val key_ns_create_announcements_from_carbs_req = preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_create_announcements_from_carbs_req))
if (key_ns_create_announcements_from_carbs_req != null) key_ns_create_announcements_from_carbs_req.isVisible = false
val key_ns_upload_only = preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_upload_only))
if (key_ns_upload_only != null) {
key_ns_upload_only.isVisible = false
key_ns_upload_only.isEnabled = false
}
val key_ns_sync_use_absolute = preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_sync_use_absolute))
if (key_ns_sync_use_absolute != null) key_ns_sync_use_absolute.isVisible = false
preferenceFragment.findPreference<PreferenceScreen>(resourceHelper.gs(R.string.ns_sync_options))?.isVisible = false
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_create_announcements_from_errors))?.isVisible = false
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_create_announcements_from_carbs_req))?.isVisible = false
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_sync_use_absolute))?.isVisible = false
} else {
// APS or pumpControl mode
val key_ns_upload_only = preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_upload_only))
if (key_ns_upload_only != null) key_ns_upload_only.isVisible = buildHelper.isEngineeringMode()
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_receive_profile_switch))?.isVisible = buildHelper.isEngineeringMode()
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_receive_insulin))?.isVisible = buildHelper.isEngineeringMode()
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_receive_carbs))?.isVisible = buildHelper.isEngineeringMode()
preferenceFragment.findPreference<SwitchPreference>(resourceHelper.gs(R.string.key_ns_receive_temp_target))?.isVisible = buildHelper.isEngineeringMode()
}
}
@ -232,7 +225,7 @@ class NSClientPlugin @Inject constructor(
fun handleClearAlarm(originalAlarm: NSAlarm, silenceTimeInMilliseconds: Long) {
if (!isEnabled(PluginType.GENERAL)) return
if (sp.getBoolean(R.string.key_ns_noupload, false)) {
if (!sp.getBoolean(R.string.key_ns_upload, false)) {
aapsLogger.debug(LTag.NSCLIENT, "Upload disabled. Message dropped")
return
}

View file

@ -42,8 +42,9 @@ class NSClientRemoveWorker(
@Inject lateinit var uel: UserEntryLogger
override fun doWork(): Result {
val acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.NSCLIENT
if (!acceptNSData) return Result.success()
// Do not accept removed data over WS. Only invalidated trough NSClient
@Suppress("ConstantConditionIf")
if (true) return Result.success()
var ret = Result.success()

View file

@ -36,7 +36,7 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNo
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin.NSProfileWorker
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
import info.nightscout.androidaps.plugins.source.NSClientSourcePlugin.NSClientSourceWorker
import info.nightscout.androidaps.receivers.DataWorker
import info.nightscout.androidaps.services.Intents
@ -472,7 +472,7 @@ class NSClientService : DaggerService() {
val profileStoreJson = profiles[profiles.length() - 1] as JSONObject
rxBus.send(EventNSClientNewLog("PROFILE", "profile received"))
dataWorker.enqueue(
OneTimeWorkRequest.Builder(NSProfileWorker::class.java)
OneTimeWorkRequest.Builder(LocalProfilePlugin.NSProfileWorker::class.java)
.setInputData(dataWorker.storeInputData(profileStoreJson, null))
.build())
if (sp.getBoolean(R.string.key_nsclient_localbroadcasts, false)) {
@ -652,18 +652,7 @@ class NSClientService : DaggerService() {
wakeLock.acquire(mins(10).msecs())
try {
rxBus.send(EventNSClientNewLog("QUEUE", "Resend started: $reason"))
dataSyncSelector.processChangedBolusesCompat()
dataSyncSelector.processChangedCarbsCompat()
dataSyncSelector.processChangedBolusCalculatorResultsCompat()
dataSyncSelector.processChangedTemporaryBasalsCompat()
dataSyncSelector.processChangedExtendedBolusesCompat()
dataSyncSelector.processChangedProfileSwitchesCompat()
dataSyncSelector.processChangedGlucoseValuesCompat()
dataSyncSelector.processChangedTempTargetsCompat()
dataSyncSelector.processChangedFoodsCompat()
dataSyncSelector.processChangedTherapyEventsCompat()
dataSyncSelector.processChangedDeviceStatusesCompat()
dataSyncSelector.processChangedProfileStore()
dataSyncSelector.doUpload()
rxBus.send(EventNSClientNewLog("QUEUE", "Resend ended: $reason"))
} finally {
if (wakeLock.isHeld) wakeLock.release()

View file

@ -54,6 +54,9 @@ class LocalProfileFragment : DaggerFragment() {
private val save = Runnable {
doEdit()
basalView?.updateLabel(resourceHelper.gs(R.string.basal_label) + ": " + sumLabel())
localProfilePlugin.profile?.getSpecificProfile(spinner?.selectedItem.toString())?.let {
binding.basalGraph.show(ProfileSealed.Pure(it))
}
}
private val textWatch = object : TextWatcher {
@ -124,7 +127,7 @@ class LocalProfileFragment : DaggerFragment() {
binding.dia.setParams(currentProfile.dia, hardLimits.minDia(), hardLimits.maxDia(), 0.1, DecimalFormat("0.0"), false, binding.save, textWatch)
binding.dia.tag = "LP_DIA"
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.ic, "IC", resourceHelper.gs(R.string.ic_label), currentProfile.ic, null, hardLimits.minIC(), hardLimits.maxIC(), 0.1, DecimalFormat("0.0"), save)
basalView = TimeListEdit(context, aapsLogger, dateUtil, view, R.id.basal, "BASAL", resourceHelper.gs(R.string.basal_label) + ": " + sumLabel(), currentProfile.basal, null, pumpDescription.basalMinimumRate, 10.0, 0.01, DecimalFormat("0.00"), save)
basalView = TimeListEdit(context, aapsLogger, dateUtil, view, R.id.basal_holder, "BASAL", resourceHelper.gs(R.string.basal_label) + ": " + sumLabel(), currentProfile.basal, null, pumpDescription.basalMinimumRate, 10.0, 0.01, DecimalFormat("0.00"), save)
if (units == Constants.MGDL) {
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.isf, "ISF", resourceHelper.gs(R.string.isf_label), currentProfile.isf, null, HardLimits.MIN_ISF, HardLimits.MAX_ISF, 1.0, DecimalFormat("0"), save)
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.target, "TARGET", resourceHelper.gs(R.string.target_label), currentProfile.targetLow, currentProfile.targetHigh, HardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble(), 1.0, DecimalFormat("0"), save)
@ -162,6 +165,9 @@ class LocalProfileFragment : DaggerFragment() {
}
}
})
localProfilePlugin.profile?.getSpecificProfile(spinner?.selectedItem.toString())?.let {
binding.basalGraph.show(ProfileSealed.Pure(it))
}
binding.profileAdd.setOnClickListener {
if (localProfilePlugin.isEdited) {

View file

@ -1,6 +1,10 @@
package info.nightscout.androidaps.plugins.profile.local
import android.content.Context
import androidx.fragment.app.FragmentActivity
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
@ -12,6 +16,8 @@ import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged
import info.nightscout.androidaps.receivers.DataWorker
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.HardLimits
@ -165,61 +171,64 @@ class LocalProfilePlugin @Inject constructor(
p.dia = sp.getDouble(localProfileNumbered + "dia", Constants.defaultDIA)
try {
p.ic = JSONArray(sp.getString(localProfileNumbered + "ic", defaultArray))
} catch (e1: JSONException) {
try {
p.ic = JSONArray(defaultArray)
} catch (ignored: JSONException) {
}
aapsLogger.error("Exception", e1)
}
try {
p.isf = JSONArray(sp.getString(localProfileNumbered + "isf", defaultArray))
} catch (e1: JSONException) {
try {
p.isf = JSONArray(defaultArray)
} catch (ignored: JSONException) {
}
aapsLogger.error("Exception", e1)
}
try {
p.basal = JSONArray(sp.getString(localProfileNumbered + "basal", defaultArray))
} catch (e1: JSONException) {
try {
p.basal = JSONArray(defaultArray)
} catch (ignored: JSONException) {
}
aapsLogger.error("Exception", e1)
}
try {
p.targetLow = JSONArray(sp.getString(localProfileNumbered + "targetlow", defaultArray))
} catch (e1: JSONException) {
try {
p.targetLow = JSONArray(defaultArray)
} catch (ignored: JSONException) {
}
aapsLogger.error("Exception", e1)
}
try {
p.targetHigh = JSONArray(sp.getString(localProfileNumbered + "targethigh", defaultArray))
} catch (e1: JSONException) {
try {
p.targetHigh = JSONArray(defaultArray)
} catch (ignored: JSONException) {
}
aapsLogger.error("Exception", e1)
profiles.add(p)
} catch (e: JSONException) {
aapsLogger.error("Exception", e)
}
profiles.add(p)
}
// create at least one profile if doesn't exist
if (profiles.size < 1) profiles.add(defaultProfile())
isEdited = false
numOfProfiles = profiles.size
createAndStoreConvertedProfile()
}
@Synchronized
fun loadFromStore(store: ProfileStore) {
try {
val newProfiles: ArrayList<SingleProfile> = ArrayList()
for (p in store.getProfileList()) {
store.getSpecificProfile(p.toString())?.let {
val sp = copyFrom(it, p.toString())
sp.name = p.toString()
newProfiles.add(sp)
}
}
if (newProfiles.size > 0) {
profiles = newProfiles
numOfProfiles = profiles.size
currentProfileIndex = 0
isEdited = false
createAndStoreConvertedProfile()
aapsLogger.debug(LTag.PROFILE, "Accepted ${profiles.size} profiles")
rxBus.send(EventLocalProfileChanged())
} else
aapsLogger.debug(LTag.PROFILE, "ProfileStore not accepted")
} catch (e: Exception) {
aapsLogger.error("Error loading ProfileStore", e)
}
}
private fun defaultProfile(): SingleProfile =
SingleProfile().also { p ->
p.name = Constants.LOCAL_PROFILE
p.mgdl = profileFunction.getUnits() == GlucoseUnit.MGDL
p.dia = Constants.defaultDIA
try {
p.ic = JSONArray(defaultArray)
p.isf = JSONArray(defaultArray)
p.basal = JSONArray(defaultArray)
p.targetLow = JSONArray(defaultArray)
p.targetHigh = JSONArray(defaultArray)
} catch (e: JSONException) {
aapsLogger.error("Exception", e)
}
}
fun copyFrom(pureProfile: PureProfile, newName: String): SingleProfile {
var verifiedName = newName
if (rawProfile?.getSpecificProfile(newName) != null) {
@ -378,4 +387,36 @@ class LocalProfilePlugin @Inject constructor(
get() = rawProfile?.getDefaultProfile()?.let {
DecimalFormatter.to2Decimal(ProfileSealed.Pure(it).percentageBasalSum()) + "U "
} ?: "INVALID"
// cannot be inner class because of needed injection
class NSProfileWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var dataWorker: DataWorker
@Inject lateinit var sp: SP
@Inject lateinit var config: Config
@Inject lateinit var localProfilePlugin: LocalProfilePlugin
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
override fun doWork(): Result {
val profileJson = dataWorker.pickupJSONObject(inputData.getLong(DataWorker.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data"))
if (sp.getBoolean(R.string.key_ns_receive_profile_store, false) || config.NSCLIENT) {
localProfilePlugin.loadFromStore(ProfileStore(injector, profileJson, dateUtil))
aapsLogger.debug(LTag.PROFILE, "Received profileStore: $profileJson")
return Result.success(workDataOf("Data" to profileJson.toString()))
}
return Result.success()
}
}
}

View file

@ -1,170 +0,0 @@
package info.nightscout.androidaps.plugins.profile.ns
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.ValueWithUnit
import info.nightscout.androidaps.databinding.NsprofileFragmentBinding
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.profile.ns.events.EventNSProfileUpdateGUI
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import javax.inject.Inject
class NSProfileFragment : DaggerFragment() {
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var nsProfilePlugin: NSProfilePlugin
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var config: Config
private var disposable: CompositeDisposable = CompositeDisposable()
private var _binding: NsprofileFragmentBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
_binding = NsprofileFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.profileviewer.closeLayout.close.visibility = View.GONE // not needed for fragment
binding.profileswitch.setOnClickListener {
val name = binding.spinner.selectedItem?.toString() ?: ""
nsProfilePlugin.profile?.let { store ->
store.getSpecificProfile(name)?.let {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.nsprofile),
resourceHelper.gs(R.string.activate_profile) + ": " + name + " ?", Runnable {
uel.log(Action.PROFILE_SWITCH, Sources.NSProfile,
ValueWithUnit.SimpleString(name),
ValueWithUnit.Percent(100))
profileFunction.createProfileSwitch(store, name, 0, 100, 0, dateUtil.now())
})
}
}
}
}
binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
if (_binding == null) return
binding.profileviewer.invalidprofile.visibility = View.VISIBLE
binding.profileviewer.noprofile.visibility = View.VISIBLE
binding.profileviewer.units.text = ""
binding.profileviewer.dia.text = ""
binding.profileviewer.activeprofile.text = ""
binding.profileviewer.ic.text = ""
binding.profileviewer.isf.text = ""
binding.profileviewer.basal.text = ""
binding.profileviewer.basaltotal.text = ""
binding.profileviewer.target.text = ""
binding.profileswitch.visibility = View.GONE
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
if (_binding == null) return
val name = binding.spinner.getItemAtPosition(position).toString()
binding.profileswitch.visibility = View.GONE
nsProfilePlugin.profile?.let { store ->
store.getSpecificProfile(name)?.let { profile ->
if (_binding == null) return
val pss = ProfileSealed.Pure(profile)
binding.profileviewer.units.text = pss.units.asText
binding.profileviewer.dia.text = resourceHelper.gs(R.string.format_hours, pss.dia)
binding.profileviewer.activeprofile.text = name
binding.profileviewer.ic.text = pss.getIcList(resourceHelper, dateUtil)
binding.profileviewer.isf.text = pss.getIsfList(resourceHelper, dateUtil)
binding.profileviewer.basal.text = pss.getBasalList(resourceHelper, dateUtil)
binding.profileviewer.basaltotal.text = String.format(resourceHelper.gs(R.string.profile_total), DecimalFormatter.to2Decimal(pss.baseBasalSum()))
binding.profileviewer.target.text = pss.getTargetList(resourceHelper, dateUtil)
binding.profileviewer.basalGraph.show(pss)
if (pss.isValid("NSProfileFragment", activePlugin.activePump, config, resourceHelper, rxBus)) {
binding.profileviewer.invalidprofile.visibility = View.GONE
binding.profileswitch.visibility = View.VISIBLE
} else {
binding.profileviewer.invalidprofile.visibility = View.VISIBLE
binding.profileswitch.visibility = View.GONE
}
}
}
}
}
}
@Synchronized
override fun onResume() {
super.onResume()
disposable += rxBus
.toObservable(EventNSProfileUpdateGUI::class.java)
.observeOn(aapsSchedulers.main)
.subscribe({ updateGUI() }, fabricPrivacy::logException)
updateGUI()
}
@Synchronized
override fun onPause() {
super.onPause()
disposable.clear()
}
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
@Synchronized
fun updateGUI() {
if (_binding == null) return
binding.profileviewer.noprofile.visibility = View.VISIBLE
nsProfilePlugin.profile?.let { profileStore ->
context?.let { context ->
val profileList = profileStore.getProfileList()
val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
binding.spinner.adapter = adapter
// set selected to actual profile
for (p in profileList.indices) {
if (profileList[p] == profileFunction.getProfileName())
binding.spinner.setSelection(p)
}
binding.profileviewer.noprofile.visibility = View.GONE
}
}
}
}

View file

@ -1,110 +0,0 @@
package info.nightscout.androidaps.plugins.profile.ns
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventProfileStoreChanged
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ProfileSource
import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
import info.nightscout.androidaps.plugins.profile.ns.events.EventNSProfileUpdateGUI
import info.nightscout.androidaps.receivers.DataWorker
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class NSProfilePlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
private val rxBus: RxBusWrapper,
resourceHelper: ResourceHelper,
private val sp: SP,
private val dateUtil: DateUtil,
config: Config
) : PluginBase(PluginDescription()
.mainType(PluginType.PROFILE)
.fragmentClass(NSProfileFragment::class.java.name)
.pluginIcon(R.drawable.ic_nightscout_profile)
.pluginName(R.string.nsprofile)
.shortName(R.string.profileviewer_shortname)
.alwaysEnabled(config.NSCLIENT)
.alwaysVisible(config.NSCLIENT)
.showInList(!config.NSCLIENT)
.description(R.string.description_profile_nightscout),
aapsLogger, resourceHelper, injector
), ProfileSource {
override var profile: ProfileStore? = null
override val profileName: String?
get() = profile?.getDefaultProfileName()
override fun onStart() {
super.onStart()
loadNSProfile()
}
private fun storeNSProfile() {
sp.putString("profile", profile!!.data.toString())
aapsLogger.debug(LTag.PROFILE, "Storing profile")
}
private fun loadNSProfile() {
aapsLogger.debug(LTag.PROFILE, "Loading stored profile")
val profileString = sp.getStringOrNull("profile", null)
if (profileString != null) {
aapsLogger.debug(LTag.PROFILE, "Loaded profile: $profileString")
profile = ProfileStore(injector, JSONObject(profileString), dateUtil)
} else {
aapsLogger.debug(LTag.PROFILE, "Stored profile not found")
// force restart of nsclient to fetch profile
rxBus.send(EventNSClientRestart())
}
}
// cannot be inner class because of needed injection
class NSProfileWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var nsProfilePlugin: NSProfilePlugin
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var dataWorker: DataWorker
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
override fun doWork(): Result {
val profileString = dataWorker.pickupJSONObject(inputData.getLong(DataWorker.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data"))
nsProfilePlugin.profile = ProfileStore(injector, profileString, dateUtil)
nsProfilePlugin.storeNSProfile()
if (nsProfilePlugin.isEnabled()) {
rxBus.send(EventProfileStoreChanged())
rxBus.send(EventNSProfileUpdateGUI())
}
aapsLogger.debug(LTag.PROFILE, "Received profileStore: ${nsProfilePlugin.profile}")
return Result.success()
}
}
}

View file

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

View file

@ -5,12 +5,12 @@ import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.transactions.CgmSourceTransaction
import info.nightscout.androidaps.interfaces.BgSource
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
@ -115,7 +115,7 @@ class NSClientSourcePlugin @Inject constructor(
override fun doWork(): Result {
var ret = Result.success()
if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_autobackfill, true) && !dexcomPlugin.isEnabled()) return Result.success()
if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(R.string.key_ns_receive_cgm, true) && !dexcomPlugin.isEnabled()) return Result.success()
val sgvs = dataWorker.pickupJSONArray(inputData.getLong(DataWorker.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data"))

View file

@ -156,7 +156,7 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
})
}
}
val nsUploadOnly = sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode()
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_insulin, false) || !sp.getBoolean(R.string.key_ns_receive_carbs, false) || !buildHelper.isEngineeringMode()
if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.GONE
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
rxBus.send(EventTreatmentUpdateGui())

View file

@ -102,7 +102,7 @@ class TreatmentsCareportalFragment : DaggerFragment() {
}
}
val nsUploadOnly = sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode()
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || !buildHelper.isEngineeringMode()
if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.GONE
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
rxBus.send(EventTreatmentUpdateGui())

View file

@ -99,7 +99,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
}
}
}
if (sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode()) binding.refreshFromNightscout.visibility = View.GONE
if (!sp.getBoolean(R.string.key_ns_receive_profile_switch, false) || !buildHelper.isEngineeringMode()) binding.refreshFromNightscout.visibility = View.GONE
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
rxBus.send(EventTreatmentUpdateGui())
}

View file

@ -97,7 +97,7 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
})
}
}
val nsUploadOnly = sp.getBoolean(R.string.key_ns_upload_only, true) || !buildHelper.isEngineeringMode()
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_temp_target, false) || !buildHelper.isEngineeringMode()
if (nsUploadOnly) binding.refreshFromNightscout.visibility = View.INVISIBLE
binding.showInvalidated.setOnCheckedChangeListener { _, _ ->
rxBus.send(EventTreatmentUpdateGui())

View file

@ -19,11 +19,8 @@ import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesFragm
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
import info.nightscout.androidaps.plugins.profile.ns.NSProfileFragment
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange
import info.nightscout.androidaps.plugins.pump.omnipod.dash.OmnipodDashPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
@ -53,7 +50,6 @@ class SWDefinition @Inject constructor(
private val configBuilder: ConfigBuilder,
private val loopPlugin: LoopPlugin,
private val nsClientPlugin: NSClientPlugin,
private val nsProfilePlugin: NSProfilePlugin,
private val importExportPrefs: ImportExportPrefs,
private val androidPermission: AndroidPermission,
private val cryptoUtil: CryptoUtil,
@ -254,25 +250,6 @@ class SWDefinition @Inject constructor(
.option(PluginType.BGSOURCE, R.string.configbuilder_bgsource_description)
.label(R.string.configbuilder_bgsource))
.add(SWBreak(injector))
private val screenProfile = SWScreen(injector, R.string.configbuilder_profile)
.skippable(false)
.add(SWInfoText(injector)
.label(R.string.setupwizard_profile_description))
.add(SWBreak(injector))
.add(SWPlugin(injector, this)
.option(PluginType.PROFILE, R.string.configbuilder_profile_description)
.label(R.string.configbuilder_profile))
private val screenNsProfile = SWScreen(injector, R.string.nsprofile)
.skippable(false)
.add(SWInfoText(injector)
.label(R.string.adjustprofileinns))
.add(SWFragment(injector, this)
.add(NSProfileFragment()))
.validator {
nsProfilePlugin.profile?.getDefaultProfile()?.let { ProfileSealed.Pure(it).isValid("StartupWizard", activePlugin.activePump, config, resourceHelper, rxBus) }
?: false
}
.visibility { nsProfilePlugin.isEnabled() }
private val screenLocalProfile = SWScreen(injector, R.string.localprofile)
.skippable(false)
.add(SWFragment(injector, this)
@ -405,8 +382,6 @@ class SWDefinition @Inject constructor(
.add(screenAge)
.add(screenInsulin)
.add(screenBgSource)
.add(screenProfile)
.add(screenNsProfile)
.add(screenLocalProfile)
.add(screenProfileSwitch)
.add(screenPump)
@ -434,8 +409,6 @@ class SWDefinition @Inject constructor(
.add(screenAge)
.add(screenInsulin)
.add(screenBgSource)
.add(screenProfile)
.add(screenNsProfile)
.add(screenLocalProfile)
.add(screenProfileSwitch)
.add(screenPump)

View file

@ -92,8 +92,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="5"
android:paddingBottom="10dp">
android:paddingBottom="10dp"
android:weightSum="5">
<TextView
android:id="@+id/dia_tab"
@ -228,10 +228,24 @@
<LinearLayout
android:id="@+id/basal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:orientation="vertical" />
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/basal_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:orientation="vertical" />
<info.nightscout.androidaps.plugins.treatments.fragments.ProfileGraph
android:id="@+id/basal_graph"
android:layout_width="match_parent"
android:layout_height="100dip"
android:layout_margin="20dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/target"
@ -248,15 +262,15 @@
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="3dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="3dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="3dp"
android:layout_weight="1"
android:drawableStart="@drawable/ic_local_activate"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="@string/activate_profile"
android:drawableStart="@drawable/ic_local_activate" />
android:text="@string/activate_profile" />
<LinearLayout
android:layout_width="match_parent"

View file

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Spinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="5dp" />
<Button
android:id="@+id/profileswitch"
style="?android:attr/buttonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/activate_profile"
android:textColor="@color/colorProfileSwitchButton" />
<include
android:id="@+id/profileviewer"
layout="@layout/profileviewer_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View file

@ -78,7 +78,6 @@
<string name="description_overview">Displays the current state of your loop and buttons for most common actions</string>
<string name="description_persistent_notification">Shows an ongoing notification with a short overview of what your loop is doing</string>
<string name="description_profile_local">Define a profile which is available offline.</string>
<string name="description_profile_nightscout">Provides the profile you have defined in Nightscout</string>
<string name="description_pump_mdi">Pump integration for people who do multiple daily injections for their diabetes therapy</string>
<string name="description_pump_virtual">Pump integration for pumps which don\'t have any driver yet (Open Loop)</string>
<string name="description_sensitivity_aaps">Sensitivity is calculated the same way like Oref0, but you can specify timeframe to the past. Minimal carb absorption is calculated from max carb absorption time from preferences.</string>
@ -128,7 +127,6 @@
<string name="configbuilder">Config Builder</string>
<string name="overview">Overview</string>
<string name="nsprofile">NS Profile</string>
<string name="treatments">Treatments</string>
<string name="virtualpump">Virtual Pump</string>
<string name="careportal">Careportal</string>
@ -340,7 +338,6 @@
<string name="localprofile_shortname">LP</string>
<string name="overview_shortname">HOME</string>
<string name="virtualpump_shortname">VPUMP</string>
<string name="profileviewer_shortname">NSPROFILE</string>
<string name="treatments_shortname">TREAT</string>
<string name="objectives_shortname">OBJ</string>
<string name="wear_shortname">WEAR</string>
@ -499,10 +496,6 @@
<string name="xdripstatus_shortname">xds</string>
<string name="wear_showbgi_title">Show BGI</string>
<string name="wear_showbgi_summary">Add BGI to status line</string>
<string name="ns_noupload">No upload to NS</string>
<string name="ns_noupload_summary">All data sent to NS are dropped. AAPS is connected to NS but no change in NS is done</string>
<string name="key_ns_upload_only" translatable="false">ns_upload_only2</string>
<string name="key_ns_noupload" translatable="false">ns_noupload</string>
<string name="overview_extendedbolus_cancel_button">Cancel Extended Bolus</string>
<string name="doprofileswitch">Do Profile Switch</string>
<string name="careportal_sensor_label">Sensor</string>
@ -699,8 +692,6 @@
<string name="category">Category</string>
<string name="subcategory">Subcategory</string>
<string name="bolusrecordedonly">Bolus will be recorded only (not delivered by pump)</string>
<string name="ns_autobackfill_summary">Autobackfill missig BGs from NS</string>
<string name="key_ns_autobackfill" translatable="false">ns_autobackfill</string>
<string name="loop_smbsetbypump_label">SMB set by pump</string>
<string name="overview_show_activity">Activity</string>
<string name="overview_show_bgi">Blood Glucose Impact</string>
@ -783,7 +774,6 @@
<string name="virtualpump_type">Virtual Pump Type</string>
<string name="virtualpump_definition">Pump Definition</string>
<string name="virtualpump_pump_def">Bolus: Step=%1$s\nExtended Bolus: [Step=%2$s, Duration=%3$smin-%4$sh]\nBasal: Step=%5$s\nTBR: %6$s (by %7$s), Duration=%8$smin-%9$sh\n%10$s</string>
<string name="ns_autobackfill_title">Autobackfill BG</string>
<string name="wear_wizard_settings">Wizard Settings</string>
<string name="key_wearwizard_bg" translatable="false">wearwizard_bg</string>
<string name="key_wearwizard_tt" translatable="false">wearwizard_tt</string>
@ -797,7 +787,6 @@
<string name="enable_nsclient">Enable NSClient</string>
<string name="welcometosetupwizard">Welcome to setup wizard. It will guide you through the setup process\n</string>
<string name="readstatus">Read status</string>
<string name="adjustprofileinns">Changes must be done in NS</string>
<string name="exitwizard">Skip setup wizard</string>
<string name="setupwizard_loop_description">Press the button below to enable AndroidAPS to suggest/make basal changes</string>
<string name="key_setupwizard_processed" translatable="false">startupwizard_processed</string>
@ -805,7 +794,6 @@
<string name="setupwizard_sensitivity_url">https://github.com/MilosKozak/AndroidAPS/wiki/Sensitivity-detection-and-COB</string>
<string name="nsclientinfotext">NSClient handles connection to Nightscout. You can skip this part now but you will not be able to pass objectives until you set it up.</string>
<string name="diawarning">Please remember: new insulin profiles require DIA at least 5h. DIA 56h on new profile is equal to DIA 3h on old insulin profiles.</string>
<string name="setupwizard_profile_description">Please select source of profile. If patient is a child you should use NS profile. If there is nobody following you on Nightscout you will probably prefer Local profile. Please remember that you are only selecting the profile source. To use it you must activate it by executing \"Profile switch\"</string>
<string name="setupwizard_aps_description">Select one from availables algorithms. They are sorted from oldest to newest. Newer algorithm is usually more powerful and more aggressive. Thus if you are new looper you may probably start with AMA and not with latest one. Do not forget to read the OpenAPS documentation and configure it before use.</string>
<string name="setupwizard_pump_waiting_for_riley_link_connection">Please configure your RileyLink below. After selecting a RileyLink, it will be possible to continue setup once the RileyLink status is \"Connected\". This might take a minute.\n</string>
<string name="setupwizard_pump_pump_not_initialized"><b>Note:</b> You can continue setup once the pump has been set up.\n</string>
@ -954,7 +942,6 @@
<string name="objectives_button_unstart">Clear started</string>
<string name="doyouwantresetstart">Do you want reset objective start? You may lose your progress.</string>
<string name="setupwizard_units_prompt">Select units you want to display values in</string>
<string name="ns_ploadlocalprofile">Upload local profile changes to NS</string>
<string name="key_wear_detailediob" translatable="false">wear_detailediob</string>
<string name="key_wear_showbgi" translatable="false">wear_showbgi</string>
<string name="dia_short">DIA</string>
@ -1139,5 +1126,30 @@
<string name="profile_carbs_ratio_value">Profile carbs ratio value</string>
<string name="full_sync">Full sync</string>
<string name="prime">Prime</string>
<string name="ns_sync_options">Synchronization</string>
<string name="key_ns_upload" translatable="false">ns_upload</string>
<string name="ns_upload_summary">Profiles, boluses, carbs, temporary basals are uploaded to NS</string>
<string name="ns_upload">Upload data to NS</string>
<string name="key_ns_receive_profile_store" translatable="false">ns_receive_profile_store</string>
<string name="ns_receive_profile_store">Receive profile store</string>
<string name="ns_receive_profile_store_summary">Synchronized profiles from NS profile editor to Local profile</string>
<string name="key_ns_receive_temp_target" translatable="false">ns_receive_temp_target</string>
<string name="ns_receive_temp_target">Receive temporary targets</string>
<string name="ns_receive_temp_target_summary">Accept temporary targets entered through NS or NSClient</string>
<string name="key_ns_receive_profile_switch" translatable="false">ns_receive_profile_switch</string>
<string name="ns_receive_profile_switch">Receive profile switches</string>
<string name="ns_receive_profile_switch_summary">Accept profile switches entered through NS or NSClient</string>
<string name="key_ns_receive_insulin" translatable="false">ns_receive_insulin</string>
<string name="ns_receive_insulin">Receive insulin</string>
<string name="ns_receive_insulin_summary">Accept insulin entered through NS or NSClient (it\'s not delivered, only calculated towards IOB)</string>
<string name="key_ns_receive_carbs" translatable="false">ns_receive_carbs</string>
<string name="ns_receive_carbs">Receive carbs</string>
<string name="ns_receive_carbs_summary">Accept carbs entered through NS or NSClient</string>
<string name="key_ns_receive_therapy_events" translatable="false">ns_receive_therapy_events</string>
<string name="ns_receive_therapy_events">Receive therapy events</string>
<string name="ns_receive_therapy_events_summary">Accept therapy events (cannula, insulin, battery change etc) entered through NS or NSClient</string>
<string name="key_ns_receive_cgm" translatable="false">ns_receive_cgm</string>
<string name="ns_receive_cgm">Receive/backfill CGM data</string>
<string name="ns_receive_cgm_summary">Accept CGM data from NS</string>
</resources>

View file

@ -26,17 +26,59 @@
validate:minLength="12"
validate:testType="minLength"/>
<SwitchPreference
android:defaultValue="true"
android:key="@string/key_ns_logappstartedevent"
android:title="@string/ns_logappstartedevent"
android:summary="@string/ns_logappstartedevent"
/>
<androidx.preference.PreferenceScreen
android:key="@string/ns_sync_options"
android:title="@string/ns_sync_options">
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_ns_uploadlocalprofile"
android:title="@string/ns_ploadlocalprofile" />
<SwitchPreference
android:defaultValue="true"
android:key="@string/key_ns_upload"
android:summary="@string/ns_upload_summary"
android:title="@string/ns_upload" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_ns_receive_cgm"
android:summary="@string/ns_receive_cgm_summary"
android:title="@string/ns_receive_cgm" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_ns_receive_profile_store"
android:summary="@string/ns_receive_profile_store_summary"
android:title="@string/ns_receive_profile_store" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_ns_receive_temp_target"
android:summary="@string/ns_receive_temp_target_summary"
android:title="@string/ns_receive_temp_target" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_ns_receive_profile_switch"
android:summary="@string/ns_receive_profile_switch_summary"
android:title="@string/ns_receive_profile_switch" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_ns_receive_insulin"
android:summary="@string/ns_receive_insulin_summary"
android:title="@string/ns_receive_insulin" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_ns_receive_carbs"
android:summary="@string/ns_receive_carbs_summary"
android:title="@string/ns_receive_carbs" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_ns_receive_therapy_events"
android:summary="@string/ns_receive_therapy_events_summary"
android:title="@string/ns_receive_therapy_events" />
</androidx.preference.PreferenceScreen>>
<androidx.preference.PreferenceScreen
android:key="@string/ns_alarmoptions"
@ -113,9 +155,10 @@
<SwitchPreference
android:defaultValue="true"
android:key="@string/key_ns_autobackfill"
android:summary="@string/ns_autobackfill_summary"
android:title="@string/ns_autobackfill_title" />
android:key="@string/key_ns_logappstartedevent"
android:title="@string/ns_logappstartedevent"
android:summary="@string/ns_logappstartedevent"
/>
<SwitchPreference
android:defaultValue="true"
@ -135,18 +178,6 @@
android:summary="@string/ns_localbroadcasts"
android:title="@string/ns_localbroadcasts_title" />
<SwitchPreference
android:defaultValue="true"
android:key="@string/key_ns_upload_only"
android:summary="@string/ns_upload_only_summary"
android:title="@string/ns_upload_only" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_ns_noupload"
android:summary="@string/ns_noupload_summary"
android:title="@string/ns_noupload" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_ns_sync_use_absolute"

View file

@ -1,728 +0,0 @@
package info.nightscout.androidaps.data;
import static info.nightscout.androidaps.extensions.ProfileSwitchExtensionKt.pureProfileFromJson;
import androidx.annotation.NonNull;
import androidx.collection.LongSparseArray;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.DecimalFormat;
import java.util.TimeZone;
import javax.inject.Inject;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.core.R;
import info.nightscout.androidaps.interfaces.ActivePlugin;
import info.nightscout.androidaps.interfaces.Config;
import info.nightscout.androidaps.interfaces.GlucoseUnit;
import info.nightscout.androidaps.interfaces.Profile;
import info.nightscout.androidaps.interfaces.Pump;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
public class ProfileImplOld implements Profile {
@Inject public AAPSLogger aapsLogger;
@Inject public ActivePlugin activePlugin;
@Inject public ResourceHelper resourceHelper;
@Inject public RxBusWrapper rxBus;
@Inject public FabricPrivacy fabricPrivacy;
@Inject public Config config;
@Inject public DateUtil dateUtil;
private final HasAndroidInjector injector;
private JSONObject json;
private String jsonUnits;
private double dia; // TODO change to insulinInterface link
private TimeZone timeZone;
private JSONArray isf;
private LongSparseArray<Double> isf_v; // oldest at index 0
private JSONArray ic;
private LongSparseArray<Double> ic_v; // oldest at index 0
private JSONArray basal;
private LongSparseArray<Double> basal_v; // oldest at index 0
private JSONArray targetLow;
private LongSparseArray<Double> targetLow_v; // oldest at index 0
private JSONArray targetHigh;
private LongSparseArray<Double> targetHigh_v; // oldest at index 0
private int percentage;
private int timeshift;
protected boolean isValid;
protected boolean isValidated;
protected ProfileImplOld(HasAndroidInjector injector) {
injector.androidInjector().inject(this);
this.injector = injector;
}
@NonNull @Override
public String toString() {
if (json != null)
return json.toString();
else
return "Profile has no JSON";
}
// Constructor from profileStore JSON
public ProfileImplOld(HasAndroidInjector injector, JSONObject json, GlucoseUnit units) {
this(injector);
init(json, 100, 0);
if (this.jsonUnits == null) {
if (units != null)
this.jsonUnits = units.getAsText();
else {
fabricPrivacy.logCustom("Profile failover failed too");
this.jsonUnits = Constants.MGDL;
}
}
}
public ProfileImplOld(HasAndroidInjector injector, JSONObject json, int percentage, int timeshift) {
this(injector);
init(json, percentage, timeshift);
}
protected void init(JSONObject json, int percentage, int timeshift) {
if (json == null) return;
jsonUnits = null;
dia = Constants.defaultDIA;
timeZone = TimeZone.getDefault();
isf_v = null;
ic_v = null;
basal_v = null;
targetLow_v = null;
targetHigh_v = null;
isValid = true;
isValidated = false;
this.percentage = percentage;
this.timeshift = timeshift;
this.json = json;
try {
if (json.has("units"))
jsonUnits = json.getString("units").toLowerCase();
if (json.has("dia"))
dia = json.getDouble("dia");
if (json.has("timezone"))
timeZone = TimeZone.getTimeZone(json.getString("timezone"));
isf = json.getJSONArray("sens");
ic = json.getJSONArray("carbratio");
basal = json.getJSONArray("basal");
targetLow = json.getJSONArray("target_low");
targetHigh = json.getJSONArray("target_high");
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
isValid = false;
isValidated = true;
}
}
public String log() {
String ret = "\n";
for (int hour = 0; hour < 24; hour++) {
double value = getBasalTimeFromMidnight(hour * 60 * 60);
ret += "NS basal value for " + hour + ":00 is " + value + "\n";
}
ret += "NS units: " + getUnits();
return ret;
}
public JSONObject getData() {
if (!json.has("units"))
try {
json.put("units", jsonUnits);
} catch (JSONException e) {
aapsLogger.error("Unhandled exception", e);
}
return json;
}
public double getDia() {
return dia;
}
// mmol or mg/dl
public void setUnits(String units) {
this.jsonUnits = units;
}
public GlucoseUnit getUnits() {
if (jsonUnits.equals(Constants.MMOL)) return GlucoseUnit.MMOL;
else return GlucoseUnit.MGDL;
}
TimeZone getTimeZone() {
return timeZone;
}
private LongSparseArray<Double> convertToSparseArray(JSONArray array) {
if (array == null) {
isValid = false;
return new LongSparseArray<>();
}
double multiplier = getMultiplier(array);
LongSparseArray<Double> sparse = new LongSparseArray<>();
for (int index = 0; index < array.length(); index++) {
try {
final JSONObject o = array.getJSONObject(index);
long tas;
try {
String time = o.getString("time");
tas = getShitfTimeSecs(dateUtil.toSeconds(time));
} catch (JSONException e) {
//log.debug(">>>>>>>>>>>> Used recalculated timeAsSeconds: " + time + " " + tas);
tas = getShitfTimeSecs((int) o.getLong("timeAsSeconds"));
}
double value = o.getDouble("value") * multiplier;
sparse.put(tas, value);
} catch (Exception e) {
aapsLogger.error("Unhandled exception", e);
aapsLogger.error(json.toString());
fabricPrivacy.logException(e);
}
}
// check if start is at 0 (midnight)
// and add last value before midnight if not
if (sparse.keyAt(0) != 0) {
sparse.put(0, sparse.valueAt(sparse.size() - 1));
}
return sparse;
}
public synchronized boolean isValid(String from, Pump pump, Config config, ResourceHelper resourceHelper, RxBusWrapper rxBus) {
if (!isValid)
return false;
if (!isValidated) {
if (basal_v == null)
basal_v = convertToSparseArray(basal);
validate(basal_v);
if (isf_v == null)
isf_v = convertToSparseArray(isf);
validate(isf_v);
if (ic_v == null)
ic_v = convertToSparseArray(ic);
validate(ic_v);
if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow);
validate(targetLow_v);
if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh);
validate(targetHigh_v);
if (targetHigh_v.size() != targetLow_v.size()) isValid = false;
else for (int i = 0; i < targetHigh_v.size(); i++)
if (targetHigh_v.valueAt(i) < targetLow_v.valueAt(i))
isValid = false;
isValidated = true;
}
boolean notify = true;
if (isValid) {
// Check for hours alignment
if (!pump.getPumpDescription().is30minBasalRatesCapable()) {
for (int index = 0; index < basal_v.size(); index++) {
long secondsFromMidnight = basal_v.keyAt(index);
if (notify && secondsFromMidnight % 3600 != 0) {
if (config.getAPS()) {
Notification notification = new Notification(Notification.BASAL_PROFILE_NOT_ALIGNED_TO_HOURS, resourceHelper.gs(R.string.basalprofilenotaligned, from), Notification.NORMAL);
rxBus.send(new EventNewNotification(notification));
}
}
}
}
// Check for minimal basal value
PumpDescription description = pump.getPumpDescription();
for (int i = 0; i < basal_v.size(); i++) {
if (basal_v.valueAt(i) < description.getBasalMinimumRate()) {
basal_v.setValueAt(i, description.getBasalMinimumRate());
if (notify)
sendBelowMinimumNotification(from);
} else if (basal_v.valueAt(i) > description.getBasalMaximumRate()) {
basal_v.setValueAt(i, description.getBasalMaximumRate());
if (notify)
sendAboveMaximumNotification(from);
}
}
}
return isValid;
}
protected void sendBelowMinimumNotification(String from) {
rxBus.send(new EventNewNotification(new Notification(Notification.MINIMAL_BASAL_VALUE_REPLACED, resourceHelper.gs(R.string.minimalbasalvaluereplaced, from), Notification.NORMAL)));
}
protected void sendAboveMaximumNotification(String from) {
rxBus.send(new EventNewNotification(new Notification(Notification.MAXIMUM_BASAL_VALUE_REPLACED, resourceHelper.gs(R.string.maximumbasalvaluereplaced, from), Notification.NORMAL)));
}
private void validate(LongSparseArray array) {
if (array.size() == 0) {
isValid = false;
return;
}
for (int index = 0; index < array.size(); index++) {
if (array.valueAt(index).equals(0d)) {
isValid = false;
return;
}
}
}
/*
private Double getValueToTime(JSONArray array, Integer timeAsSeconds) {
Double lastValue = null;
for (Integer index = 0; index < array.length(); index++) {
try {
JSONObject o = array.getJSONObject(index);
Integer tas = o.getInt("timeAsSeconds");
Double value = o.getDouble("value");
if (lastValue == null) lastValue = value;
if (timeAsSeconds < tas) {
break;
}
lastValue = value;
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
}
return lastValue;
}
*/
Integer getShitfTimeSecs(Integer originalTime) {
int shiftedTime = originalTime + timeshift * 60 * 60;
shiftedTime = (shiftedTime + 24 * 60 * 60) % (24 * 60 * 60);
return shiftedTime;
}
private double getMultiplier(LongSparseArray<Double> array) {
double multiplier = 1d;
if (array == isf_v)
multiplier = 100d / percentage;
else if (array == ic_v)
multiplier = 100d / percentage;
else if (array == basal_v)
multiplier = percentage / 100d;
else
aapsLogger.error("Unknown array type");
return multiplier;
}
private double getMultiplier(JSONArray array) {
double multiplier = 1d;
if (array == isf)
multiplier = 100d / percentage;
else if (array == ic)
multiplier = 100d / percentage;
else if (array == basal)
multiplier = percentage / 100d;
else if (array == targetLow)
multiplier = 1d;
else if (array == targetHigh)
multiplier = 1d;
else
aapsLogger.error("Unknown array type");
return multiplier;
}
private double getValueToTime(LongSparseArray<Double> array, Integer timeAsSeconds) {
Double lastValue = null;
for (int index = 0; index < array.size(); index++) {
long tas = array.keyAt(index);
double value = array.valueAt(index);
if (lastValue == null) lastValue = value;
if (timeAsSeconds < tas) {
break;
}
lastValue = value;
}
return lastValue;
}
private String getValuesList(LongSparseArray<Double> array, LongSparseArray<Double> array2, DecimalFormat format, String units) {
String retValue = "";
for (Integer index = 0; index < array.size(); index++) {
retValue += dateUtil.format_HH_MM((int) array.keyAt(index));
retValue += " ";
retValue += format.format(array.valueAt(index));
if (array2 != null) {
retValue += " - ";
retValue += format.format(array2.valueAt(index));
}
retValue += " " + units;
if (index + 1 < array.size())
retValue += "\n";
}
return retValue;
}
public double getIsfMgdl() {
return info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl(getIsfTimeFromMidnight(info.nightscout.androidaps.interfaces.Profile.Companion.secondsFromMidnight()), getUnits());
}
public double getIsfMgdl(long time) {
return info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl(getIsfTimeFromMidnight(info.nightscout.androidaps.interfaces.Profile.Companion.secondsFromMidnight(time)), getUnits());
}
public double getIsfMgdlTimeFromMidnight(int timeAsSeconds) {
return info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl(getIsfTimeFromMidnight(timeAsSeconds), getUnits());
}
public double getIsfTimeFromMidnight(int timeAsSeconds) {
if (isf_v == null)
isf_v = convertToSparseArray(isf);
return getValueToTime(isf_v, timeAsSeconds);
}
public String getIsfList(ResourceHelper resourceHelper, DateUtil dateUtil) {
if (isf_v == null)
isf_v = convertToSparseArray(isf);
return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits().getAsText() + resourceHelper.gs(R.string.profile_per_unit));
}
public ProfileValue[] getIsfsMgdlValues() {
if (isf_v == null)
isf_v = convertToSparseArray(ic);
ProfileValue[] ret = new ProfileValue[isf_v.size()];
for (int index = 0; index < isf_v.size(); index++) {
int tas = (int) isf_v.keyAt(index);
double value = isf_v.valueAt(index);
ret[index] = new ProfileValue(tas, info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl(value, getUnits()));
}
return ret;
}
public double getIc() {
return getIcTimeFromMidnight(info.nightscout.androidaps.interfaces.Profile.Companion.secondsFromMidnight());
}
public double getIc(long time) {
return getIcTimeFromMidnight(info.nightscout.androidaps.interfaces.Profile.Companion.secondsFromMidnight(time));
}
public double getIcTimeFromMidnight(int timeAsSeconds) {
if (ic_v == null)
ic_v = convertToSparseArray(ic);
return getValueToTime(ic_v, timeAsSeconds);
}
public String getIcList(ResourceHelper resourceHelper, DateUtil dateUtil) {
if (ic_v == null)
ic_v = convertToSparseArray(ic);
return getValuesList(ic_v, null, new DecimalFormat("0.0"), resourceHelper.gs(R.string.profile_carbs_per_unit));
}
public ProfileValue[] getIcsValues() {
if (ic_v == null)
ic_v = convertToSparseArray(ic);
ProfileValue[] ret = new ProfileValue[ic_v.size()];
for (int index = 0; index < ic_v.size(); index++) {
int tas = (int) ic_v.keyAt(index);
double value = ic_v.valueAt(index);
ret[index] = new ProfileValue(tas, value);
}
return ret;
}
public double getBasal() {
return getBasalTimeFromMidnight(info.nightscout.androidaps.interfaces.Profile.Companion.secondsFromMidnight());
}
public double getBasal(long time) {
return getBasalTimeFromMidnight(info.nightscout.androidaps.interfaces.Profile.Companion.secondsFromMidnight(time));
}
public synchronized double getBasalTimeFromMidnight(int timeAsSeconds) {
if (basal_v == null) {
basal_v = convertToSparseArray(basal);
}
return getValueToTime(basal_v, timeAsSeconds);
}
public String getBasalList(ResourceHelper resourceHelper, DateUtil dateUtil) {
if (basal_v == null)
basal_v = convertToSparseArray(basal);
return getValuesList(basal_v, null, new DecimalFormat("0.00"), resourceHelper.gs(R.string.profile_ins_units_per_hour));
}
@NonNull @Override public JSONObject toPureNsJson(DateUtil dateUtil) {
return getData();
}
public synchronized ProfileValue[] getBasalValues() {
if (basal_v == null)
basal_v = convertToSparseArray(basal);
ProfileValue[] ret = new ProfileValue[basal_v.size()];
for (int index = 0; index < basal_v.size(); index++) {
int tas = (int) basal_v.keyAt(index);
double value = basal_v.valueAt(index);
ret[index] = new ProfileValue(tas, value);
}
return ret;
}
public double getTargetMgdl() {
return getTargetMgdl(info.nightscout.androidaps.interfaces.Profile.Companion.secondsFromMidnight());
}
public double getTargetMgdl(int timeAsSeconds) {
return info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl((getTargetLowTimeFromMidnight(timeAsSeconds) + getTargetHighTimeFromMidnight(timeAsSeconds)) / 2, getUnits());
}
public double getTargetLowMgdl() {
return info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl(getTargetLowTimeFromMidnight(info.nightscout.androidaps.interfaces.Profile.Companion.secondsFromMidnight()), getUnits());
}
public double getTargetLowMgdl(long time) {
return info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl(getTargetLowTimeFromMidnight(info.nightscout.androidaps.interfaces.Profile.Companion.secondsFromMidnight(time)), getUnits());
}
double getTargetLowTimeFromMidnight(int timeAsSeconds) {
if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow);
return getValueToTime(targetLow_v, timeAsSeconds);
}
public double getTargetLowMgdlTimeFromMidnight(int timeAsSeconds) {
return info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl(getTargetLowTimeFromMidnight(timeAsSeconds), getUnits());
}
public double getTargetHighMgdl() {
return info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl(getTargetHighTimeFromMidnight(info.nightscout.androidaps.interfaces.Profile.Companion.secondsFromMidnight()), getUnits());
}
public double getTargetHighMgdl(long time) {
return info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl(getTargetHighTimeFromMidnight(info.nightscout.androidaps.interfaces.Profile.Companion.secondsFromMidnight(time)), getUnits());
}
public double getTargetHighTimeFromMidnight(int timeAsSeconds) {
if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh);
return getValueToTime(targetHigh_v, timeAsSeconds);
}
public double getTargetHighMgdlTimeFromMidnight(int timeAsSeconds) {
return info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl(getTargetHighTimeFromMidnight(timeAsSeconds), getUnits());
}
public static class TargetValue {
TargetValue(int timeAsSeconds, double low, double high) {
this.timeAsSeconds = timeAsSeconds;
this.low = low;
this.high = high;
}
public int timeAsSeconds;
public double low;
public double high;
}
public TargetValue[] getTargets() {
if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow);
if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh);
TargetValue[] ret = new TargetValue[targetLow_v.size()];
for (int index = 0; index < targetLow_v.size(); index++) {
int tas = (int) targetLow_v.keyAt(index);
double low = targetLow_v.valueAt(index);
double high = targetHigh_v.valueAt(index);
ret[index] = new TargetValue(tas, low, high);
}
return ret;
}
public ProfileValue[] getSingleTargetsMgdl() {
if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow);
if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh);
ProfileValue[] ret = new ProfileValue[targetLow_v.size()];
for (int index = 0; index < targetLow_v.size(); index++) {
int tas = (int) targetLow_v.keyAt(index);
double target = (targetLow_v.valueAt(index) + targetHigh_v.valueAt(index)) / 2;
ret[index] = new ProfileValue(tas, info.nightscout.androidaps.interfaces.Profile.Companion.toMgdl(target, getUnits()));
}
return ret;
}
@NonNull public String getTargetList(ResourceHelper resourceHelper, DateUtil dateUtil) {
if (targetLow_v == null)
targetLow_v = convertToSparseArray(targetLow);
if (targetHigh_v == null)
targetHigh_v = convertToSparseArray(targetHigh);
return getValuesList(targetLow_v, targetHigh_v, new DecimalFormat("0.0"), getUnits().getAsText());
}
public double getMaxDailyBasal() {
double max = 0d;
for (int hour = 0; hour < 24; hour++) {
double value = getBasalTimeFromMidnight(hour * 60 * 60);
if (value > max) max = value;
}
return max;
}
public double percentageBasalSum() {
double result = 0d;
for (int i = 0; i < 24; i++) {
result += getBasalTimeFromMidnight(i * 60 * 60);
}
return result;
}
public double baseBasalSum() {
double result = 0d;
for (int i = 0; i < 24; i++) {
result += getBasalTimeFromMidnight(i * 60 * 60) / getMultiplier(basal_v);
}
return result;
}
public int getPercentage() {
return percentage;
}
public int getTimeshift() {
return timeshift;
}
public PureProfile convertToNonCustomizedProfile(DateUtil dateUtil) {
JSONObject o = new JSONObject();
try {
o.put("units", jsonUnits);
o.put("dia", dia);
o.put("timezone", timeZone.getID());
// SENS
JSONArray sens = new JSONArray();
double lastValue = -1d;
for (int i = 0; i < 24; i++) {
int timeAsSeconds = i * 60 * 60;
double value = getIsfTimeFromMidnight(timeAsSeconds);
if (value != lastValue) {
JSONObject item = new JSONObject();
String time;
DecimalFormat df = new DecimalFormat("00");
time = df.format(i) + ":00";
item.put("time", time);
item.put("timeAsSeconds", timeAsSeconds);
item.put("value", value);
lastValue = value;
sens.put(item);
}
}
o.put("sens", sens);
// CARBRATIO
JSONArray carbratio = new JSONArray();
lastValue = -1d;
for (int i = 0; i < 24; i++) {
int timeAsSeconds = i * 60 * 60;
double value = getIcTimeFromMidnight(timeAsSeconds);
if (value != lastValue) {
JSONObject item = new JSONObject();
String time;
DecimalFormat df = new DecimalFormat("00");
time = df.format(i) + ":00";
item.put("time", time);
item.put("timeAsSeconds", timeAsSeconds);
item.put("value", value);
lastValue = value;
carbratio.put(item);
}
}
o.put("carbratio", carbratio);
// BASAL
JSONArray basal = new JSONArray();
lastValue = -1d;
for (int i = 0; i < 24; i++) {
int timeAsSeconds = i * 60 * 60;
double value = getBasalTimeFromMidnight(timeAsSeconds);
if (value != lastValue) {
JSONObject item = new JSONObject();
String time;
DecimalFormat df = new DecimalFormat("00");
time = df.format(i) + ":00";
item.put("time", time);
item.put("timeAsSeconds", timeAsSeconds);
item.put("value", value);
lastValue = value;
basal.put(item);
}
}
o.put("basal", basal);
// TARGET_LOW
JSONArray target_low = new JSONArray();
lastValue = -1d;
for (int i = 0; i < 24; i++) {
int timeAsSeconds = i * 60 * 60;
double value = getTargetLowTimeFromMidnight(timeAsSeconds);
if (value != lastValue) {
JSONObject item = new JSONObject();
String time;
DecimalFormat df = new DecimalFormat("00");
time = df.format(i) + ":00";
item.put("time", time);
item.put("timeAsSeconds", timeAsSeconds);
item.put("value", value);
lastValue = value;
target_low.put(item);
}
}
o.put("target_low", target_low);
// TARGET_HIGH
JSONArray target_high = new JSONArray();
lastValue = -1d;
for (int i = 0; i < 24; i++) {
int timeAsSeconds = i * 60 * 60;
double value = getTargetHighTimeFromMidnight(timeAsSeconds);
if (value != lastValue) {
JSONObject item = new JSONObject();
String time;
DecimalFormat df = new DecimalFormat("00");
time = df.format(i) + ":00";
item.put("time", time);
item.put("timeAsSeconds", timeAsSeconds);
item.put("value", value);
lastValue = value;
target_high.put(item);
}
}
o.put("target_high", target_high);
} catch (JSONException e) {
aapsLogger.error("Unhandled exception" + e);
}
return pureProfileFromJson(o, dateUtil);
}
}

View file

@ -2,7 +2,6 @@ package info.nightscout.androidaps.di
import dagger.Module
import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.data.ProfileImplOld
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.plugins.aps.loop.APSResult
@ -16,6 +15,5 @@ abstract class CoreDataClassesModule {
@ContributesAndroidInjector abstract fun apsResultInjector(): APSResult
@ContributesAndroidInjector abstract fun autosensDataInjector(): AutosensData
@ContributesAndroidInjector abstract fun profileInjector(): ProfileImplOld
@ContributesAndroidInjector abstract fun profileStoreInjector(): ProfileStore
}

View file

@ -5,7 +5,6 @@ import info.nightscout.androidaps.database.data.TargetBlock
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
private fun getShiftedTimeSecs(originalSeconds: Int, timeShiftHours: Int): Int {
@ -86,33 +85,18 @@ fun blockFromJsonArray(jsonArray: JSONArray?, dateUtil: DateUtil): List<Block>?
val ret = ArrayList<Block>(size)
try {
for (index in 0 until jsonArray.length() - 1) {
val o: JSONObject = jsonArray.getJSONObject(index)
val tas: Int = try {
o.getInt("timeAsSeconds")
} catch (e: JSONException) {
val time = o.getString("time")
dateUtil.toSeconds(time)
}
val next: JSONObject = jsonArray.getJSONObject(index + 1)
val nextTas: Int = try {
next.getInt("timeAsSeconds")
} catch (e: JSONException) {
val time = next.getString("time")
dateUtil.toSeconds(time)
}
val value: Double = o.getDouble("value")
val o = jsonArray.getJSONObject(index)
val tas = dateUtil.toSeconds(o.getString("time"))
val next = jsonArray.getJSONObject(index + 1)
val nextTas = dateUtil.toSeconds(next.getString("time"))
val value = o.getDouble("value")
if (tas % 3600 != 0) return null
if (nextTas % 3600 != 0) return null
ret.add(index, Block((nextTas - tas) * 1000L, value))
}
val last: JSONObject = jsonArray.getJSONObject(jsonArray.length() - 1)
val lastTas: Int = try {
last.getInt("timeAsSeconds")
} catch (e: JSONException) {
val time = last.getString("time")
dateUtil.toSeconds(time)
}
val value: Double = last.getDouble("value")
val lastTas = dateUtil.toSeconds(last.getString("time"))
val value = last.getDouble("value")
ret.add(jsonArray.length() - 1, Block((T.hours(24).secs() - lastTas) * 1000L, value))
} catch (e: Exception) {
return null
@ -128,41 +112,23 @@ fun targetBlockFromJsonArray(jsonArray1: JSONArray?, jsonArray2: JSONArray?, dat
try {
for (index in 0 until jsonArray1.length() - 1) {
val o1: JSONObject = jsonArray1.getJSONObject(index)
val tas1: Int = try {
o1.getInt("timeAsSeconds")
} catch (e: JSONException) {
val time = o1.getString("time")
dateUtil.toSeconds(time)
}
val value1: Double = o1.getDouble("value")
val next1: JSONObject = jsonArray1.getJSONObject(index + 1)
val nextTas1: Int = try {
next1.getInt("timeAsSeconds")
} catch (e: JSONException) {
val time = next1.getString("time")
dateUtil.toSeconds(time)
}
val o2: JSONObject = jsonArray2.getJSONObject(index)
val tas2: Int = try {
o2.getInt("timeAsSeconds")
} catch (e: JSONException) {
val time = o2.getString("time")
dateUtil.toSeconds(time)
}
val value2: Double = o2.getDouble("value")
val tas1 = dateUtil.toSeconds(o1.getString("time"))
val value1 = o1.getDouble("value")
val next1 = jsonArray1.getJSONObject(index + 1)
val nextTas1 = dateUtil.toSeconds(next1.getString("time"))
val o2 = jsonArray2.getJSONObject(index)
val tas2 = dateUtil.toSeconds(o2.getString("time"))
val value2 = o2.getDouble("value")
if (tas1 != tas2) return null
if (tas1 % 3600 != 0) return null
if (nextTas1 % 3600 != 0) return null
ret.add(index, TargetBlock((nextTas1 - tas1) * 1000L, value1, value2))
}
val last1: JSONObject = jsonArray1.getJSONObject(jsonArray1.length() - 1)
val lastTas1: Int = try {
last1.getInt("timeAsSeconds")
} catch (e: JSONException) {
val time = last1.getString("time")
dateUtil.toSeconds(time)
}
val value1: Double = last1.getDouble("value")
val last2: JSONObject = jsonArray2.getJSONObject(jsonArray2.length() - 1)
val value2: Double = last2.getDouble("value")
val last1 = jsonArray1.getJSONObject(jsonArray1.length() - 1)
val lastTas1 = dateUtil.toSeconds(last1.getString("time"))
val value1 = last1.getDouble("value")
val last2 = jsonArray2.getJSONObject(jsonArray2.length() - 1)
val value2 = last2.getDouble("value")
ret.add(jsonArray1.length() - 1, TargetBlock((T.hours(24).secs() - lastTas1) * 1000L, value1, value2))
} catch (e: Exception) {
return null

View file

@ -94,9 +94,9 @@ fun profileSwitchFromJson(jsonObject: JSONObject, dateUtil: DateUtil, activePlug
/**
* Pure profile doesn't contain timestamp, percentage, timeshift, profileName
*/
fun pureProfileFromJson(jsonObject: JSONObject, dateUtil: DateUtil): PureProfile? {
fun pureProfileFromJson(jsonObject: JSONObject, dateUtil: DateUtil, defaultUnits: String? = null): PureProfile? {
try {
JsonHelper.safeGetStringAllowNull(jsonObject, "units", null) ?: return null
JsonHelper.safeGetStringAllowNull(jsonObject, "units", defaultUnits) ?: return null
val units = GlucoseUnit.fromText(JsonHelper.safeGetString(jsonObject, "units", Constants.MGDL))
val dia = JsonHelper.safeGetDoubleAllowNull(jsonObject, "dia") ?: return null
val timezone = TimeZone.getTimeZone(JsonHelper.safeGetString(jsonObject, "timezone", "UTC"))

View file

@ -18,6 +18,8 @@ interface DataSyncSelector {
data class PairProfileSwitch(val value: ProfileSwitch, val updateRecordId: Long)
data class PairProfileStore(val value: JSONObject, val timestampSync: Long)
fun doUpload()
fun resetToNextFullSync()
fun confirmLastBolusIdIfGreater(lastSynced: Long)

View file

@ -52,12 +52,13 @@ class ProfileStore(val injector: HasAndroidInjector, val data: JSONObject, val d
fun getSpecificProfile(profileName: String): PureProfile? {
var profile: PureProfile? = null
val defaultUnits = JsonHelper.safeGetStringAllowNull(data, "units", null)
getStore()?.let { store ->
if (store.has(profileName)) {
profile = cachedObjects[profileName]
if (profile == null) {
JsonHelper.safeGetJSONObject(store, profileName, null)?.let { profileObject ->
profile = pureProfileFromJson(profileObject, dateUtil)
profile = pureProfileFromJson(profileObject, dateUtil, defaultUnits)
cachedObjects[profileName] = profile
}
}

View file

@ -19,7 +19,6 @@
<string name="key_high_mark" translatable="false">high_mark</string>
<string name="key_ns_create_announcements_from_errors" translatable="false">ns_create_announcements_from_errors</string>
<string name="key_ns_logappstartedevent" translatable="false">ns_logappstartedevent</string>
<string name="key_ns_uploadlocalprofile" translatable="false">ns_uploadlocalprofile</string>
<string name="key_btwatchdog" translatable="false">bt_watchdog</string>
<string name="key_btwatchdog_lastbark" translatable="false">bt_watchdog_last</string>
<string name="key_pump_unreachable_threshold_minutes" translatable="false">pump_unreachable_threshold</string>