Merge pull request #119 from 0pen-dash/revert-118-revert-117-avereha/merge-dev-2
Revert "Revert "avereha/merge dev 2""
This commit is contained in:
commit
7af3685933
|
@ -1,42 +1,7 @@
|
||||||
package info.nightscout.androidaps
|
package info.nightscout.androidaps
|
||||||
|
|
||||||
import android.os.SystemClock
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.test.espresso.Espresso.onData
|
|
||||||
import androidx.test.espresso.Espresso.onView
|
|
||||||
import androidx.test.espresso.action.ViewActions
|
|
||||||
import androidx.test.espresso.action.ViewActions.click
|
|
||||||
import androidx.test.espresso.action.ViewActions.scrollTo
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withClassName
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withTagValue
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.filters.LargeTest
|
import androidx.test.filters.LargeTest
|
||||||
import androidx.test.rule.ActivityTestRule
|
|
||||||
import androidx.test.rule.GrantPermissionRule
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginType
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
|
|
||||||
import info.nightscout.androidaps.plugins.source.RandomBgPlugin
|
|
||||||
import info.nightscout.androidaps.setupwizard.SetupWizardActivity
|
|
||||||
import info.nightscout.androidaps.utils.HardLimits
|
|
||||||
import info.nightscout.androidaps.utils.extensions.isRunningTest
|
|
||||||
import org.hamcrest.CoreMatchers.allOf
|
|
||||||
import org.hamcrest.Description
|
|
||||||
import org.hamcrest.Matcher
|
|
||||||
import org.hamcrest.Matchers
|
|
||||||
import org.hamcrest.TypeSafeMatcher
|
|
||||||
import org.junit.Assert
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
|
|
|
@ -8,14 +8,18 @@ import android.widget.ArrayAdapter
|
||||||
import com.google.common.base.Joiner
|
import com.google.common.base.Joiner
|
||||||
import info.nightscout.androidaps.Constants
|
import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.data.ProfileSealed
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||||
import info.nightscout.androidaps.databinding.DialogProfileswitchBinding
|
import info.nightscout.androidaps.databinding.DialogProfileswitchBinding
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
import info.nightscout.androidaps.utils.HtmlHelper
|
import info.nightscout.androidaps.utils.HtmlHelper
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
@ -31,6 +35,9 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
@Inject lateinit var activePlugin: ActivePlugin
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
@Inject lateinit var uel: UserEntryLogger
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
@Inject lateinit var config: Config
|
||||||
|
@Inject lateinit var hardLimits: HardLimits
|
||||||
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
|
||||||
private var profileIndex: Int? = null
|
private var profileIndex: Int? = null
|
||||||
|
|
||||||
|
@ -129,6 +136,9 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime))
|
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime))
|
||||||
|
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
|
val ps = profileFunction.buildProfileSwitch(profileStore, profileName, duration, percent, timeShift, eventTime)
|
||||||
|
val validity = ProfileSealed.PS(ps).isValid(resourceHelper.gs(R.string.careportal_profileswitch), activePlugin.activePump, config, resourceHelper, rxBus, hardLimits)
|
||||||
|
if (validity.isValid)
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||||
profileFunction.createProfileSwitch(profileStore,
|
profileFunction.createProfileSwitch(profileStore,
|
||||||
profileName = profileName,
|
profileName = profileName,
|
||||||
|
@ -145,6 +155,14 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
ValueWithUnit.Hour(timeShift).takeIf { timeShift != 0 },
|
ValueWithUnit.Hour(timeShift).takeIf { timeShift != 0 },
|
||||||
ValueWithUnit.Minute(duration).takeIf { duration != 0 })
|
ValueWithUnit.Minute(duration).takeIf { duration != 0 })
|
||||||
})
|
})
|
||||||
|
else {
|
||||||
|
OKDialog.show(
|
||||||
|
activity,
|
||||||
|
resourceHelper.gs(R.string.careportal_profileswitch),
|
||||||
|
HtmlHelper.fromHtml(Joiner.on("<br/>").join(validity.reasons))
|
||||||
|
)
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,6 @@ import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAc
|
||||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
|
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
import info.nightscout.androidaps.queue.commands.Command
|
|
||||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
|
|
@ -125,11 +125,11 @@ class OpenAPSAMAPlugin @Inject constructor(
|
||||||
maxBg = hardLimits.verifyHardLimits(tempTarget.value.highTarget, R.string.temp_target_high_target, HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
maxBg = hardLimits.verifyHardLimits(tempTarget.value.highTarget, R.string.temp_target_high_target, HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
||||||
targetBg = hardLimits.verifyHardLimits(tempTarget.value.target(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
targetBg = hardLimits.verifyHardLimits(tempTarget.value.target(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
||||||
}
|
}
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
if (!hardLimits.checkHardLimits(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
if (!hardLimits.checkHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return
|
if (!hardLimits.checkHardLimits(profile.getIsfMgdl(), R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), R.string.profile_max_daily_basal_value, 0.02, hardLimits.maxBasal())) return
|
if (!hardLimits.checkHardLimits(profile.getMaxDailyBasal(), R.string.profile_max_daily_basal_value, 0.02, hardLimits.maxBasal())) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
|
if (!hardLimits.checkHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
|
||||||
startPart = System.currentTimeMillis()
|
startPart = System.currentTimeMillis()
|
||||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||||
val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")
|
val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")
|
||||||
|
|
|
@ -130,11 +130,11 @@ class OpenAPSSMBPlugin @Inject constructor(
|
||||||
maxBg = hardLimits.verifyHardLimits(tempTarget.value.highTarget, R.string.temp_target_high_target, HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
maxBg = hardLimits.verifyHardLimits(tempTarget.value.highTarget, R.string.temp_target_high_target, HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1].toDouble())
|
||||||
targetBg = hardLimits.verifyHardLimits(tempTarget.value.target(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
targetBg = hardLimits.verifyHardLimits(tempTarget.value.target(), R.string.temp_target_value, HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(), HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble())
|
||||||
}
|
}
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
if (!hardLimits.checkHardLimits(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
if (!hardLimits.checkHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return
|
if (!hardLimits.checkHardLimits(profile.getIsfMgdl(), R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), R.string.profile_max_daily_basal_value, 0.02, hardLimits.maxBasal())) return
|
if (!hardLimits.checkHardLimits(profile.getMaxDailyBasal(), R.string.profile_max_daily_basal_value, 0.02, hardLimits.maxBasal())) return
|
||||||
if (!hardLimits.checkOnlyHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
|
if (!hardLimits.checkHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
|
||||||
startPart = System.currentTimeMillis()
|
startPart = System.currentTimeMillis()
|
||||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||||
val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")
|
val autosensData = iobCobCalculator.getLastAutosensDataWithWaitForCalculationFinish("OpenAPSPlugin")
|
||||||
|
|
|
@ -91,10 +91,10 @@ class ProfileFunctionImplementation @Inject constructor(
|
||||||
if (sp.getString(R.string.key_units, Constants.MGDL) == Constants.MGDL) GlucoseUnit.MGDL
|
if (sp.getString(R.string.key_units, Constants.MGDL) == Constants.MGDL) GlucoseUnit.MGDL
|
||||||
else GlucoseUnit.MMOL
|
else GlucoseUnit.MMOL
|
||||||
|
|
||||||
override fun createProfileSwitch(profileStore: ProfileStore, profileName: String, durationInMinutes: Int, percentage: Int, timeShiftInHours: Int, timestamp: Long) {
|
override fun buildProfileSwitch(profileStore: ProfileStore, profileName: String, durationInMinutes: Int, percentage: Int, timeShiftInHours: Int, timestamp: Long) : ProfileSwitch {
|
||||||
val pureProfile = profileStore.getSpecificProfile(profileName)
|
val pureProfile = profileStore.getSpecificProfile(profileName)
|
||||||
?: throw InvalidParameterSpecException(profileName)
|
?: throw InvalidParameterSpecException(profileName)
|
||||||
val ps = ProfileSwitch(
|
return ProfileSwitch(
|
||||||
timestamp = timestamp,
|
timestamp = timestamp,
|
||||||
basalBlocks = pureProfile.basalBlocks,
|
basalBlocks = pureProfile.basalBlocks,
|
||||||
isfBlocks = pureProfile.isfBlocks,
|
isfBlocks = pureProfile.isfBlocks,
|
||||||
|
@ -105,8 +105,14 @@ class ProfileFunctionImplementation @Inject constructor(
|
||||||
timeshift = T.hours(timeShiftInHours.toLong()).msecs(),
|
timeshift = T.hours(timeShiftInHours.toLong()).msecs(),
|
||||||
percentage = percentage,
|
percentage = percentage,
|
||||||
duration = T.mins(durationInMinutes.toLong()).msecs(),
|
duration = T.mins(durationInMinutes.toLong()).msecs(),
|
||||||
insulinConfiguration = activePlugin.activeInsulin.insulinConfiguration.also { it.insulinEndTime = (pureProfile.dia * 3600 * 1000).toLong() }
|
insulinConfiguration = activePlugin.activeInsulin.insulinConfiguration.also {
|
||||||
|
it.insulinEndTime = (pureProfile.dia * 3600 * 1000).toLong()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createProfileSwitch(profileStore: ProfileStore, profileName: String, durationInMinutes: Int, percentage: Int, timeShiftInHours: Int, timestamp: Long) {
|
||||||
|
val ps = buildProfileSwitch(profileStore, profileName, durationInMinutes, percentage, timeShiftInHours, timestamp)
|
||||||
disposable += repository.runTransactionForResult(InsertOrUpdateProfileSwitch(ps))
|
disposable += repository.runTransactionForResult(InsertOrUpdateProfileSwitch(ps))
|
||||||
.subscribe({ result ->
|
.subscribe({ result ->
|
||||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it") }
|
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it") }
|
||||||
|
|
|
@ -740,7 +740,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
||||||
graphData.addTreatments()
|
graphData.addTreatments()
|
||||||
if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
|
if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
|
||||||
graphData.addActivity(0.8)
|
graphData.addActivity(0.8)
|
||||||
if (pump.pumpDescription.isTempBasalCapable && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal])
|
if ((pump.pumpDescription.isTempBasalCapable || config.NSCLIENT) && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal])
|
||||||
graphData.addBasals()
|
graphData.addBasals()
|
||||||
graphData.addTargetLine()
|
graphData.addTargetLine()
|
||||||
graphData.addNowLine(dateUtil.now())
|
graphData.addNowLine(dateUtil.now())
|
||||||
|
|
|
@ -28,6 +28,7 @@ import info.nightscout.androidaps.setupwizard.elements.*
|
||||||
import info.nightscout.androidaps.setupwizard.events.EventSWUpdate
|
import info.nightscout.androidaps.setupwizard.events.EventSWUpdate
|
||||||
import info.nightscout.androidaps.utils.AndroidPermission
|
import info.nightscout.androidaps.utils.AndroidPermission
|
||||||
import info.nightscout.androidaps.utils.CryptoUtil
|
import info.nightscout.androidaps.utils.CryptoUtil
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
import info.nightscout.androidaps.utils.extensions.isRunningTest
|
import info.nightscout.androidaps.utils.extensions.isRunningTest
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
@ -53,7 +54,8 @@ class SWDefinition @Inject constructor(
|
||||||
private val importExportPrefs: ImportExportPrefs,
|
private val importExportPrefs: ImportExportPrefs,
|
||||||
private val androidPermission: AndroidPermission,
|
private val androidPermission: AndroidPermission,
|
||||||
private val cryptoUtil: CryptoUtil,
|
private val cryptoUtil: CryptoUtil,
|
||||||
private val config: Config
|
private val config: Config,
|
||||||
|
private val hardLimits: HardLimits
|
||||||
) {
|
) {
|
||||||
|
|
||||||
lateinit var activity: AppCompatActivity
|
lateinit var activity: AppCompatActivity
|
||||||
|
@ -255,7 +257,7 @@ class SWDefinition @Inject constructor(
|
||||||
.add(SWFragment(injector, this)
|
.add(SWFragment(injector, this)
|
||||||
.add(LocalProfileFragment()))
|
.add(LocalProfileFragment()))
|
||||||
.validator {
|
.validator {
|
||||||
localProfilePlugin.profile?.getDefaultProfile()?.let { ProfileSealed.Pure(it).isValid("StartupWizard", activePlugin.activePump, config, resourceHelper, rxBus) }
|
localProfilePlugin.profile?.getDefaultProfile()?.let { ProfileSealed.Pure(it).isValid("StartupWizard", activePlugin.activePump, config, resourceHelper, rxBus, hardLimits).isValid }
|
||||||
?: false
|
?: false
|
||||||
}
|
}
|
||||||
.visibility { localProfilePlugin.isEnabled() }
|
.visibility { localProfilePlugin.isEnabled() }
|
||||||
|
|
|
@ -250,8 +250,6 @@
|
||||||
<string name="smscommunicator_loophasbeendisabled">Loop has been disabled</string>
|
<string name="smscommunicator_loophasbeendisabled">Loop has been disabled</string>
|
||||||
<string name="smscommunicator_loophasbeenenabled">Loop has been enabled</string>
|
<string name="smscommunicator_loophasbeenenabled">Loop has been enabled</string>
|
||||||
<string name="smscommunicator_loopisenabled">Loop is enabled</string>
|
<string name="smscommunicator_loopisenabled">Loop is enabled</string>
|
||||||
<string name="valuelimitedto">%1$.2f limited to %2$.2f</string>
|
|
||||||
<string name="valueoutofrange">»%1$s« is out of hard limits</string>
|
|
||||||
<string name="smscommunicator_pumpconnectwithcode">To connect pump reply with code %1$s</string>
|
<string name="smscommunicator_pumpconnectwithcode">To connect pump reply with code %1$s</string>
|
||||||
<string name="smscommunicator_pumpconnectfail">Connection to pump failed</string>
|
<string name="smscommunicator_pumpconnectfail">Connection to pump failed</string>
|
||||||
<string name="smscommunicator_pumpdisconnectwithcode">To disconnect pump for %1$d minutes reply with code %2$s</string>
|
<string name="smscommunicator_pumpdisconnectwithcode">To disconnect pump for %1$d minutes reply with code %2$s</string>
|
||||||
|
@ -400,12 +398,6 @@
|
||||||
<string name="adult">Adult</string>
|
<string name="adult">Adult</string>
|
||||||
<string name="resistantadult">Insulin resistant adult</string>
|
<string name="resistantadult">Insulin resistant adult</string>
|
||||||
<string name="pregnant">Pregnancy</string>
|
<string name="pregnant">Pregnancy</string>
|
||||||
<string name="key_age" translatable="false">age</string>
|
|
||||||
<string name="key_child" translatable="false">child</string>
|
|
||||||
<string name="key_teenage" translatable="false">teenage</string>
|
|
||||||
<string name="key_adult" translatable="false">adult</string>
|
|
||||||
<string name="key_resistantadult" translatable="false">resistantadult</string>
|
|
||||||
<string name="key_pregnant" translatable="false">pregnant</string>
|
|
||||||
<string name="patientage_summary">Please select patient type to setup safety limits</string>
|
<string name="patientage_summary">Please select patient type to setup safety limits</string>
|
||||||
<string name="patient_name">Patient name</string>
|
<string name="patient_name">Patient name</string>
|
||||||
<string name="patient_name_summary">Please provide patient name or nickname to differentiate among multiple setups</string>
|
<string name="patient_name_summary">Please provide patient name or nickname to differentiate among multiple setups</string>
|
||||||
|
@ -1082,16 +1074,6 @@
|
||||||
<string name="email_address">Email address</string>
|
<string name="email_address">Email address</string>
|
||||||
<string name="privacy_settings">Privacy setting</string>
|
<string name="privacy_settings">Privacy setting</string>
|
||||||
<string name="privacy_summary">You can provide optional email address if you want to be notified about app crashes. This is not an automated service. You will be contacted by developers in dangerous situations.</string>
|
<string name="privacy_summary">You can provide optional email address if you want to be notified about app crashes. This is not an automated service. You will be contacted by developers in dangerous situations.</string>
|
||||||
<string name="profile_low_target">Profile low target</string>
|
|
||||||
<string name="profile_high_target">Profile high target</string>
|
|
||||||
<string name="temp_target_low_target">Temporary target bottom value</string>
|
|
||||||
<string name="temp_target_high_target">Temporary target top value</string>
|
|
||||||
<string name="temp_target_value">Temporary target value</string>
|
|
||||||
<string name="profile_dia">Profile DIA value</string>
|
|
||||||
<string name="profile_sensitivity_value">Profile sensitivity value</string>
|
|
||||||
<string name="profile_max_daily_basal_value">Maximal profile basal value</string>
|
|
||||||
<string name="current_basal_value">Current basal value</string>
|
|
||||||
<string name="profile_carbs_ratio_value">Profile carbs ratio value</string>
|
|
||||||
<string name="full_sync">Full sync</string>
|
<string name="full_sync">Full sync</string>
|
||||||
<string name="prime">Prime</string>
|
<string name="prime">Prime</string>
|
||||||
<string name="ns_sync_options">Synchronization</string>
|
<string name="ns_sync_options">Synchronization</string>
|
||||||
|
|
|
@ -19,6 +19,8 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
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.Notification
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
|
import info.nightscout.androidaps.utils.Round
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
|
@ -94,34 +96,93 @@ sealed class ProfileSealed(
|
||||||
value.timeZone.rawOffset.toLong()
|
value.timeZone.rawOffset.toLong()
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun isValid(from: String, pump: Pump, config: Config, resourceHelper: ResourceHelper, rxBus: RxBusWrapper): Boolean {
|
override fun isValid(from: String, pump: Pump, config: Config, resourceHelper: ResourceHelper, rxBus: RxBusWrapper, hardLimits: HardLimits): Profile.ValidityCheck {
|
||||||
val notify = true
|
val notify = true
|
||||||
var valid = true
|
val validityCheck = Profile.ValidityCheck()
|
||||||
val description = pump.pumpDescription
|
val description = pump.pumpDescription
|
||||||
if (!description.is30minBasalRatesCapable) {
|
|
||||||
for (basal in basalBlocks) {
|
for (basal in basalBlocks) {
|
||||||
|
val basalAmount = basal.amount * percentage / 100.0
|
||||||
|
if (!description.is30minBasalRatesCapable) {
|
||||||
// Check for hours alignment
|
// Check for hours alignment
|
||||||
val duration: Long = basal.duration
|
val duration: Long = basal.duration
|
||||||
if (duration % 3600000 != 0L) {
|
if (duration % 3600000 != 0L) {
|
||||||
if (notify && config.APS) {
|
if (notify && config.APS) {
|
||||||
val notification = Notification(Notification.BASAL_PROFILE_NOT_ALIGNED_TO_HOURS, resourceHelper.gs(R.string.basalprofilenotaligned, from), Notification.NORMAL)
|
val notification = Notification(
|
||||||
|
Notification.BASAL_PROFILE_NOT_ALIGNED_TO_HOURS,
|
||||||
|
resourceHelper.gs(R.string.basalprofilenotaligned, from),
|
||||||
|
Notification.NORMAL
|
||||||
|
)
|
||||||
rxBus.send(EventNewNotification(notification))
|
rxBus.send(EventNewNotification(notification))
|
||||||
}
|
}
|
||||||
valid = false
|
validityCheck.isValid = false
|
||||||
|
validityCheck.reasons.add(
|
||||||
|
resourceHelper.gs(
|
||||||
|
R.string.basalprofilenotaligned,
|
||||||
|
from
|
||||||
|
)
|
||||||
|
)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Check for minimal basal value
|
// Check for minimal basal value
|
||||||
if (basal.amount < description.basalMinimumRate) {
|
if (basalAmount < description.basalMinimumRate) {
|
||||||
basal.amount = description.basalMinimumRate
|
basal.amount = description.basalMinimumRate
|
||||||
if (notify) sendBelowMinimumNotification(from, rxBus, resourceHelper)
|
if (notify) sendBelowMinimumNotification(from, rxBus, resourceHelper)
|
||||||
valid = false
|
validityCheck.isValid = false
|
||||||
} else if (basal.amount > description.basalMaximumRate) {
|
validityCheck.reasons.add(resourceHelper.gs(R.string.minimalbasalvaluereplaced, from))
|
||||||
|
break
|
||||||
|
} else if (basalAmount > description.basalMaximumRate) {
|
||||||
basal.amount = description.basalMaximumRate
|
basal.amount = description.basalMaximumRate
|
||||||
if (notify) sendAboveMaximumNotification(from, rxBus, resourceHelper)
|
if (notify) sendAboveMaximumNotification(from, rxBus, resourceHelper)
|
||||||
valid = false
|
validityCheck.isValid = false
|
||||||
|
validityCheck.reasons.add(resourceHelper.gs(R.string.maximumbasalvaluereplaced, from))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (!hardLimits.isInRange(basalAmount, 0.01, hardLimits.maxBasal())) {
|
||||||
|
validityCheck.isValid = false
|
||||||
|
validityCheck.reasons.add(resourceHelper.gs(R.string.value_out_of_hard_limits, resourceHelper.gs(R.string.basal_value), basalAmount))
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!hardLimits.isInRange(dia, hardLimits.minDia(), hardLimits.maxDia())) {
|
||||||
|
validityCheck.isValid = false
|
||||||
|
validityCheck.reasons.add(resourceHelper.gs(R.string.value_out_of_hard_limits, resourceHelper.gs(R.string.profile_dia), dia))
|
||||||
}
|
}
|
||||||
return valid
|
for (ic in icBlocks)
|
||||||
|
if (!hardLimits.isInRange(ic.amount * 100.0 / percentage, hardLimits.minIC(), hardLimits.maxIC())) {
|
||||||
|
validityCheck.isValid = false
|
||||||
|
validityCheck.reasons.add(resourceHelper.gs(R.string.value_out_of_hard_limits, resourceHelper.gs(R.string.profile_carbs_ratio_value), ic.amount * 100.0 / percentage))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for (isf in isfBlocks)
|
||||||
|
if (!hardLimits.isInRange(toMgdl(isf.amount * 100.0 / percentage, units), HardLimits.MIN_ISF, HardLimits.MAX_ISF)) {
|
||||||
|
validityCheck.isValid = false
|
||||||
|
validityCheck.reasons.add(resourceHelper.gs(R.string.value_out_of_hard_limits, resourceHelper.gs(R.string.profile_sensitivity_value), isf.amount * 100.0 / percentage))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for (target in targetBlocks) {
|
||||||
|
if (hardLimits.isInRange(
|
||||||
|
Round.roundTo(target.lowTarget, 0.1),
|
||||||
|
HardLimits.VERY_HARD_LIMIT_MIN_BG[0].toDouble(),
|
||||||
|
HardLimits.VERY_HARD_LIMIT_MIN_BG[1].toDouble()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
validityCheck.isValid = false
|
||||||
|
validityCheck.reasons.add(resourceHelper.gs(R.string.value_out_of_hard_limits, resourceHelper.gs(R.string.profile_low_target), target.lowTarget))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (hardLimits.isInRange(
|
||||||
|
Round.roundTo(target.highTarget, 0.1),
|
||||||
|
HardLimits.VERY_HARD_LIMIT_MAX_BG[0].toDouble(),
|
||||||
|
HardLimits.VERY_HARD_LIMIT_MAX_BG[1].toDouble()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
validityCheck.isValid = false
|
||||||
|
validityCheck.reasons.add(resourceHelper.gs(R.string.value_out_of_hard_limits, resourceHelper.gs(R.string.profile_high_target), target.highTarget))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return validityCheck
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun sendBelowMinimumNotification(from: String, rxBus: RxBusWrapper, resourceHelper: ResourceHelper) {
|
protected open fun sendBelowMinimumNotification(from: String, rxBus: RxBusWrapper, resourceHelper: ResourceHelper) {
|
||||||
|
|
|
@ -17,15 +17,18 @@ import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.ValueWrapper
|
import info.nightscout.androidaps.database.ValueWrapper
|
||||||
import info.nightscout.androidaps.extensions.getCustomizedName
|
import info.nightscout.androidaps.extensions.getCustomizedName
|
||||||
import info.nightscout.androidaps.extensions.pureProfileFromJson
|
import info.nightscout.androidaps.extensions.pureProfileFromJson
|
||||||
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
import info.nightscout.androidaps.interfaces.Profile
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
import info.nightscout.androidaps.utils.HtmlHelper
|
import info.nightscout.androidaps.utils.HtmlHelper
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import java.io.File.separator
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -39,6 +42,7 @@ class ProfileViewerDialog : DaggerDialogFragment() {
|
||||||
@Inject lateinit var activePlugin: ActivePlugin
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
@Inject lateinit var config: Config
|
@Inject lateinit var config: Config
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
@Inject lateinit var hardLimits: HardLimits
|
||||||
|
|
||||||
private var time: Long = 0
|
private var time: Long = 0
|
||||||
|
|
||||||
|
@ -149,7 +153,9 @@ class ProfileViewerDialog : DaggerDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.noprofile.visibility = View.GONE
|
binding.noprofile.visibility = View.GONE
|
||||||
binding.invalidprofile.visibility = if (profile1.isValid("ProfileViewDialog", activePlugin.activePump, config, resourceHelper, rxBus)) View.GONE else View.VISIBLE
|
val validity = profile1.isValid("ProfileViewDialog", activePlugin.activePump, config, resourceHelper, rxBus, hardLimits)
|
||||||
|
binding.invalidprofile.text = resourceHelper.gs(R.string.invalidprofile) + "\n" + validity.reasons.joinToString(separator = "\n")
|
||||||
|
binding.invalidprofile.visibility = validity.isValid.not().toVisibility()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
profile?.let {
|
profile?.let {
|
||||||
|
@ -164,7 +170,9 @@ class ProfileViewerDialog : DaggerDialogFragment() {
|
||||||
binding.basalGraph.show(it)
|
binding.basalGraph.show(it)
|
||||||
|
|
||||||
binding.noprofile.visibility = View.GONE
|
binding.noprofile.visibility = View.GONE
|
||||||
binding.invalidprofile.visibility = if (it.isValid("ProfileViewDialog", activePlugin.activePump, config, resourceHelper, rxBus)) View.GONE else View.VISIBLE
|
val validity = it.isValid("ProfileViewDialog", activePlugin.activePump, config, resourceHelper, rxBus, hardLimits)
|
||||||
|
binding.invalidprofile.text = resourceHelper.gs(R.string.invalidprofile) + "\n" + validity.reasons.joinToString(separator = "\n")
|
||||||
|
binding.invalidprofile.visibility = validity.isValid.not().toVisibility()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.DecimalFormatter.to0Decimal
|
import info.nightscout.androidaps.utils.DecimalFormatter.to0Decimal
|
||||||
import info.nightscout.androidaps.utils.DecimalFormatter.to1Decimal
|
import info.nightscout.androidaps.utils.DecimalFormatter.to1Decimal
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
import info.nightscout.androidaps.utils.Round
|
import info.nightscout.androidaps.utils.Round
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
@ -13,7 +14,9 @@ import org.json.JSONObject
|
||||||
|
|
||||||
interface Profile {
|
interface Profile {
|
||||||
|
|
||||||
fun isValid(from: String, pump: Pump, config: Config, resourceHelper: ResourceHelper, rxBus: RxBusWrapper): Boolean
|
class ValidityCheck(var isValid: Boolean = true, val reasons: ArrayList<String> = arrayListOf())
|
||||||
|
|
||||||
|
fun isValid(from: String, pump: Pump, config: Config, resourceHelper: ResourceHelper, rxBus: RxBusWrapper, hardLimits: HardLimits): ValidityCheck
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Units used for ISF & target
|
* Units used for ISF & target
|
||||||
|
|
|
@ -46,6 +46,18 @@ interface ProfileFunction {
|
||||||
*/
|
*/
|
||||||
fun getRequestedProfile(): ProfileSwitch?
|
fun getRequestedProfile(): ProfileSwitch?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a new circadian profile switch request based on provided profile
|
||||||
|
*
|
||||||
|
* @param profileStore ProfileStore to use
|
||||||
|
* @param profileName this profile from profile store
|
||||||
|
* @param durationInMinutes
|
||||||
|
* @param percentage 100 = no modification
|
||||||
|
* @param timeShiftInHours 0 = no modification
|
||||||
|
* @param timestamp expected time
|
||||||
|
*/
|
||||||
|
fun buildProfileSwitch(profileStore: ProfileStore, profileName: String, durationInMinutes: Int, percentage: Int, timeShiftInHours: Int, timestamp: Long): ProfileSwitch
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new circadian profile switch request based on provided profile
|
* Create a new circadian profile switch request based on provided profile
|
||||||
*
|
*
|
||||||
|
|
|
@ -63,7 +63,7 @@ class PumpDescription() {
|
||||||
is30minBasalRatesCapable = false
|
is30minBasalRatesCapable = false
|
||||||
isRefillingCapable = true
|
isRefillingCapable = true
|
||||||
isBatteryReplaceable = true
|
isBatteryReplaceable = true
|
||||||
storesCarbInfo = true
|
storesCarbInfo = false
|
||||||
supportsTDDs = false
|
supportsTDDs = false
|
||||||
needsManualTDDLoad = true
|
needsManualTDDLoad = true
|
||||||
hasCustomUnreachableAlertCheck = false
|
hasCustomUnreachableAlertCheck = false
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
package info.nightscout.androidaps.utils
|
package info.nightscout.androidaps.utils
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||||
|
import info.nightscout.androidaps.core.R
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction
|
import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
@ -15,6 +16,7 @@ import javax.inject.Singleton
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
@OpenForTesting
|
||||||
@Singleton
|
@Singleton
|
||||||
class HardLimits @Inject constructor(
|
class HardLimits @Inject constructor(
|
||||||
private val aapsLogger: AAPSLogger,
|
private val aapsLogger: AAPSLogger,
|
||||||
|
@ -81,9 +83,12 @@ class HardLimits @Inject constructor(
|
||||||
fun maxIC(): Double = MAX_IC[loadAge()]
|
fun maxIC(): Double = MAX_IC[loadAge()]
|
||||||
|
|
||||||
// safety checks
|
// safety checks
|
||||||
fun checkOnlyHardLimits(value: Double, valueName: Int, lowLimit: Double, highLimit: Double): Boolean =
|
fun checkHardLimits(value: Double, valueName: Int, lowLimit: Double, highLimit: Double): Boolean =
|
||||||
value == verifyHardLimits(value, valueName, lowLimit, highLimit)
|
value == verifyHardLimits(value, valueName, lowLimit, highLimit)
|
||||||
|
|
||||||
|
fun isInRange(value: Double, lowLimit: Double, highLimit: Double): Boolean =
|
||||||
|
value in lowLimit..highLimit
|
||||||
|
|
||||||
fun verifyHardLimits(value: Double, valueName: Int, lowLimit: Double, highLimit: Double): Double {
|
fun verifyHardLimits(value: Double, valueName: Int, lowLimit: Double, highLimit: Double): Double {
|
||||||
var newValue = value
|
var newValue = value
|
||||||
if (newValue < lowLimit || newValue > highLimit) {
|
if (newValue < lowLimit || newValue > highLimit) {
|
|
@ -90,7 +90,11 @@ class SPImplementation @Inject constructor(
|
||||||
return try {
|
return try {
|
||||||
sharedPreferences.getLong(key, defaultValue)
|
sharedPreferences.getLong(key, defaultValue)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
try {
|
||||||
SafeParse.stringToLong(sharedPreferences.getString(key, defaultValue.toString()))
|
SafeParse.stringToLong(sharedPreferences.getString(key, defaultValue.toString()))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
defaultValue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,12 @@
|
||||||
<string name="key_active_pump_change_timestamp" translatable="false">active_pump_change_timestamp</string>
|
<string name="key_active_pump_change_timestamp" translatable="false">active_pump_change_timestamp</string>
|
||||||
<string name="key_active_pump_type" translatable="false">active_pump_type</string>
|
<string name="key_active_pump_type" translatable="false">active_pump_type</string>
|
||||||
<string name="key_active_pump_serial_number" translatable="false">active_pump_serial_number</string>
|
<string name="key_active_pump_serial_number" translatable="false">active_pump_serial_number</string>
|
||||||
|
<string name="key_age" translatable="false">age</string>
|
||||||
|
<string name="key_child" translatable="false">child</string>
|
||||||
|
<string name="key_teenage" translatable="false">teenage</string>
|
||||||
|
<string name="key_adult" translatable="false">adult</string>
|
||||||
|
<string name="key_resistantadult" translatable="false">resistantadult</string>
|
||||||
|
<string name="key_pregnant" translatable="false">pregnant</string>
|
||||||
|
|
||||||
<!-- General-->
|
<!-- General-->
|
||||||
<string name="refresh">Refresh</string>
|
<string name="refresh">Refresh</string>
|
||||||
|
@ -472,6 +478,22 @@
|
||||||
<string name="uel_loop_removed">LOOP REMOVED</string>
|
<string name="uel_loop_removed">LOOP REMOVED</string>
|
||||||
<string name="uel_other">OTHER</string>
|
<string name="uel_other">OTHER</string>
|
||||||
|
|
||||||
|
<!-- HardLimits -->
|
||||||
|
<string name="profile_low_target">Profile low target</string>
|
||||||
|
<string name="profile_high_target">Profile high target</string>
|
||||||
|
<string name="temp_target_low_target">Temporary target bottom value</string>
|
||||||
|
<string name="temp_target_high_target">Temporary target top value</string>
|
||||||
|
<string name="temp_target_value">Temporary target value</string>
|
||||||
|
<string name="profile_dia">Profile DIA value</string>
|
||||||
|
<string name="profile_sensitivity_value">Profile sensitivity value</string>
|
||||||
|
<string name="profile_max_daily_basal_value">Maximal profile basal value</string>
|
||||||
|
<string name="current_basal_value">Current basal value</string>
|
||||||
|
<string name="profile_carbs_ratio_value">Profile carbs ratio value</string>
|
||||||
|
<string name="valuelimitedto">%1$.2f limited to %2$.2f</string>
|
||||||
|
<string name="valueoutofrange">»%1$s« is out of hard limits</string>
|
||||||
|
<string name="value_out_of_hard_limits">»%1$s« %2$.2f is out of hard limits</string>
|
||||||
|
<string name="basal_value">Basal value</string>
|
||||||
|
|
||||||
<plurals name="days">
|
<plurals name="days">
|
||||||
<item quantity="one">%1$d day</item>
|
<item quantity="one">%1$d day</item>
|
||||||
<item quantity="other">%1$d days</item>
|
<item quantity="other">%1$d days</item>
|
||||||
|
|
|
@ -2,11 +2,10 @@ package info.nightscout.androidaps.data
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import dagger.android.AndroidInjector
|
import dagger.android.AndroidInjector
|
||||||
import dagger.android.HasAndroidInjector
|
|
||||||
import info.nightscout.androidaps.TestBase
|
import info.nightscout.androidaps.TestBase
|
||||||
import info.nightscout.androidaps.TestPumpPlugin
|
import info.nightscout.androidaps.TestPumpPlugin
|
||||||
import info.nightscout.androidaps.core.R
|
import info.nightscout.androidaps.core.R
|
||||||
import info.nightscout.androidaps.events.Event
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.extensions.pureProfileFromJson
|
import info.nightscout.androidaps.extensions.pureProfileFromJson
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
import info.nightscout.androidaps.interfaces.Config
|
||||||
|
@ -14,18 +13,18 @@ import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
import info.nightscout.androidaps.interfaces.Profile
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.HardLimits
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.TestAapsSchedulers
|
import info.nightscout.androidaps.utils.rx.TestAapsSchedulers
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.`when`
|
import org.mockito.Mockito.`when`
|
||||||
import org.mockito.Mockito.any
|
|
||||||
import org.mockito.Mockito.anyInt
|
import org.mockito.Mockito.anyInt
|
||||||
import org.mockito.Mockito.anyString
|
import org.mockito.Mockito.anyString
|
||||||
import org.mockito.Mockito.doNothing
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,25 +37,29 @@ class ProfileTest : TestBase() {
|
||||||
@Mock lateinit var resourceHelper: ResourceHelper
|
@Mock lateinit var resourceHelper: ResourceHelper
|
||||||
@Mock lateinit var context: Context
|
@Mock lateinit var context: Context
|
||||||
@Mock lateinit var config: Config
|
@Mock lateinit var config: Config
|
||||||
|
@Mock lateinit var sp: SP
|
||||||
|
@Mock lateinit var repository: AppRepository
|
||||||
|
|
||||||
private lateinit var rxBus: RxBusWrapper
|
private lateinit var rxBus: RxBusWrapper
|
||||||
private lateinit var dateUtil: DateUtil
|
private lateinit var dateUtil: DateUtil
|
||||||
private lateinit var testPumpPlugin: TestPumpPlugin
|
private lateinit var testPumpPlugin: TestPumpPlugin
|
||||||
|
private lateinit var hardLimits: HardLimits
|
||||||
|
|
||||||
private var okProfile = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"},{\"time\":\"2:00\",\"value\":\"110\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
private var okProfile = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"sens\":[{\"time\":\"00:00\",\"value\":\"6\"},{\"time\":\"2:00\",\"value\":\"6.2\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
||||||
private var belowLimitValidProfile = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.001\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
private var belowLimitValidProfile = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.001\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
||||||
private var notAlignedBasalValidProfile = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:30\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
private var notAlignedBasalValidProfile = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:30\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
||||||
private var notStartingAtZeroValidProfile = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:30\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
private var notStartingAtZeroValidProfile = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:30\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
||||||
private var noUnitsValidProfile = "{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\"}"
|
private var noUnitsValidProfile = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\"}"
|
||||||
private var wrongProfile = "{\"dia\":\"3\",\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
private var wrongProfile = "{\"dia\":\"5\",\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"100\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"5\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
||||||
|
|
||||||
//String profileStore = "{\"defaultProfile\":\"Default\",\"store\":{\"Default\":" + validProfile + "}}";
|
//String profileStore = "{\"defaultProfile\":\"Default\",\"store\":{\"Default\":" + validProfile + "}}";
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun prepare() {
|
fun prepare() {
|
||||||
testPumpPlugin = TestPumpPlugin(HasAndroidInjector { AndroidInjector { } })
|
testPumpPlugin = TestPumpPlugin { AndroidInjector { } }
|
||||||
dateUtil = DateUtil(context)
|
dateUtil = DateUtil(context)
|
||||||
rxBus = RxBusWrapper(TestAapsSchedulers())
|
rxBus = RxBusWrapper(TestAapsSchedulers())
|
||||||
|
hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, repository)
|
||||||
`when`(activePluginProvider.activePump).thenReturn(testPumpPlugin)
|
`when`(activePluginProvider.activePump).thenReturn(testPumpPlugin)
|
||||||
`when`(resourceHelper.gs(R.string.profile_per_unit)).thenReturn("/U")
|
`when`(resourceHelper.gs(R.string.profile_per_unit)).thenReturn("/U")
|
||||||
`when`(resourceHelper.gs(R.string.profile_carbs_per_unit)).thenReturn("g/U")
|
`when`(resourceHelper.gs(R.string.profile_carbs_per_unit)).thenReturn("g/U")
|
||||||
|
@ -69,10 +72,10 @@ class ProfileTest : TestBase() {
|
||||||
|
|
||||||
// Test valid profile
|
// Test valid profile
|
||||||
var p = ProfileSealed.Pure(pureProfileFromJson(JSONObject(okProfile), dateUtil)!!)
|
var p = ProfileSealed.Pure(pureProfileFromJson(JSONObject(okProfile), dateUtil)!!)
|
||||||
Assert.assertEquals(true, p.isValid("Test", testPumpPlugin, config, resourceHelper, rxBus))
|
Assert.assertEquals(true, p.isValid("Test", testPumpPlugin, config, resourceHelper, rxBus, hardLimits).isValid)
|
||||||
// Assert.assertEquals(true, p.log().contains("NS units: mmol"))
|
// Assert.assertEquals(true, p.log().contains("NS units: mmol"))
|
||||||
// JSONAssert.assertEquals(JSONObject(okProfile), p.toPureNsJson(dateUtil), false)
|
// JSONAssert.assertEquals(JSONObject(okProfile), p.toPureNsJson(dateUtil), false)
|
||||||
Assert.assertEquals(3.0, p.dia, 0.01)
|
Assert.assertEquals(5.0, p.dia, 0.01)
|
||||||
// Assert.assertEquals(TimeZone.getTimeZone("UTC"), p.timeZone)
|
// Assert.assertEquals(TimeZone.getTimeZone("UTC"), p.timeZone)
|
||||||
Assert.assertEquals("00:30", dateUtil.format_HH_MM(30 * 60))
|
Assert.assertEquals("00:30", dateUtil.format_HH_MM(30 * 60))
|
||||||
val c = Calendar.getInstance()
|
val c = Calendar.getInstance()
|
||||||
|
@ -80,13 +83,13 @@ class ProfileTest : TestBase() {
|
||||||
c[Calendar.MINUTE] = 0
|
c[Calendar.MINUTE] = 0
|
||||||
c[Calendar.SECOND] = 0
|
c[Calendar.SECOND] = 0
|
||||||
c[Calendar.MILLISECOND] = 0
|
c[Calendar.MILLISECOND] = 0
|
||||||
Assert.assertEquals(1800.0, p.getIsfMgdl(c.timeInMillis), 0.01)
|
Assert.assertEquals(108.0, p.getIsfMgdl(c.timeInMillis), 0.01)
|
||||||
c[Calendar.HOUR_OF_DAY] = 2
|
c[Calendar.HOUR_OF_DAY] = 2
|
||||||
Assert.assertEquals(1980.0, p.getIsfMgdl(c.timeInMillis), 0.01)
|
Assert.assertEquals(111.6, p.getIsfMgdl(c.timeInMillis), 0.01)
|
||||||
// Assert.assertEquals(110.0, p.getIsfTimeFromMidnight(2 * 60 * 60), 0.01)
|
// Assert.assertEquals(110.0, p.getIsfTimeFromMidnight(2 * 60 * 60), 0.01)
|
||||||
Assert.assertEquals("""
|
Assert.assertEquals("""
|
||||||
00:00 100,0 mmol/U
|
00:00 6,0 mmol/U
|
||||||
02:00 110,0 mmol/U
|
02:00 6,2 mmol/U
|
||||||
""".trimIndent(), p.getIsfList(resourceHelper, dateUtil).replace(".", ","))
|
""".trimIndent(), p.getIsfList(resourceHelper, dateUtil).replace(".", ","))
|
||||||
Assert.assertEquals(30.0, p.getIc(c.timeInMillis), 0.01)
|
Assert.assertEquals(30.0, p.getIc(c.timeInMillis), 0.01)
|
||||||
Assert.assertEquals(30.0, p.getIcTimeFromMidnight(2 * 60 * 60), 0.01)
|
Assert.assertEquals(30.0, p.getIcTimeFromMidnight(2 * 60 * 60), 0.01)
|
||||||
|
@ -121,7 +124,7 @@ class ProfileTest : TestBase() {
|
||||||
|
|
||||||
//Test basal profile below limit
|
//Test basal profile below limit
|
||||||
p = ProfileSealed.Pure(pureProfileFromJson(JSONObject(belowLimitValidProfile), dateUtil)!!)
|
p = ProfileSealed.Pure(pureProfileFromJson(JSONObject(belowLimitValidProfile), dateUtil)!!)
|
||||||
p.isValid("Test", testPumpPlugin, config, resourceHelper, rxBus)
|
p.isValid("Test", testPumpPlugin, config, resourceHelper, rxBus, hardLimits)
|
||||||
|
|
||||||
// Test profile w/o units
|
// Test profile w/o units
|
||||||
Assert.assertNull(pureProfileFromJson(JSONObject(noUnitsValidProfile), dateUtil))
|
Assert.assertNull(pureProfileFromJson(JSONObject(noUnitsValidProfile), dateUtil))
|
||||||
|
@ -139,21 +142,21 @@ class ProfileTest : TestBase() {
|
||||||
Assert.assertEquals(0.05, p.getBasal(c.timeInMillis), 0.01)
|
Assert.assertEquals(0.05, p.getBasal(c.timeInMillis), 0.01)
|
||||||
Assert.assertEquals(1.2, p.percentageBasalSum(), 0.01)
|
Assert.assertEquals(1.2, p.percentageBasalSum(), 0.01)
|
||||||
Assert.assertEquals(60.0, p.getIc(c.timeInMillis), 0.01)
|
Assert.assertEquals(60.0, p.getIc(c.timeInMillis), 0.01)
|
||||||
Assert.assertEquals(3960.0, p.getIsfMgdl(c.timeInMillis), 0.01)
|
Assert.assertEquals(223.2, p.getIsfMgdl(c.timeInMillis), 0.01)
|
||||||
|
|
||||||
// Test timeshift functionality
|
// Test timeshift functionality
|
||||||
p = ProfileSealed.Pure(pureProfileFromJson(JSONObject(okProfile), dateUtil)!!)
|
p = ProfileSealed.Pure(pureProfileFromJson(JSONObject(okProfile), dateUtil)!!)
|
||||||
p.ts = 1
|
p.ts = 1
|
||||||
Assert.assertEquals(
|
Assert.assertEquals(
|
||||||
"""
|
"""
|
||||||
00:00 110.0 mmol/U
|
00:00 6.2 mmol/U
|
||||||
01:00 100.0 mmol/U
|
01:00 6.0 mmol/U
|
||||||
03:00 110.0 mmol/U
|
03:00 6.2 mmol/U
|
||||||
""".trimIndent(), p.getIsfList(resourceHelper, dateUtil))
|
""".trimIndent(), p.getIsfList(resourceHelper, dateUtil))
|
||||||
|
|
||||||
// Test hour alignment
|
// Test hour alignment
|
||||||
testPumpPlugin.pumpDescription.is30minBasalRatesCapable = false
|
testPumpPlugin.pumpDescription.is30minBasalRatesCapable = false
|
||||||
p = ProfileSealed.Pure(pureProfileFromJson(JSONObject(notAlignedBasalValidProfile), dateUtil)!!)
|
p = ProfileSealed.Pure(pureProfileFromJson(JSONObject(notAlignedBasalValidProfile), dateUtil)!!)
|
||||||
p.isValid("Test", testPumpPlugin, config, resourceHelper, rxBus)
|
p.isValid("Test", testPumpPlugin, config, resourceHelper, rxBus, hardLimits)
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue