Merge branch 'dev' of https://github.com/nightscout/AndroidAPS into avereha/merge-dev-2
This commit is contained in:
commit
efad748939
|
@ -1,42 +1,7 @@
|
|||
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.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
|
||||
|
||||
@LargeTest
|
||||
|
|
|
@ -8,14 +8,18 @@ import android.widget.ArrayAdapter
|
|||
import com.google.common.base.Joiner
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.ProfileSealed
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
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.DialogProfileswitchBinding
|
||||
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.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
|
@ -31,6 +35,9 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@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
|
||||
|
||||
|
@ -129,22 +136,33 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
actions.add(resourceHelper.gs(R.string.time) + ": " + dateUtil.dateAndTimeString(eventTime))
|
||||
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||
profileFunction.createProfileSwitch(profileStore,
|
||||
profileName = profileName,
|
||||
durationInMinutes = duration,
|
||||
percentage = percent,
|
||||
timeShiftInHours = timeShift,
|
||||
timestamp = eventTime)
|
||||
uel.log(Action.PROFILE_SWITCH,
|
||||
Sources.ProfileSwitchDialog,
|
||||
notes,
|
||||
ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged },
|
||||
ValueWithUnit.SimpleString(profileName),
|
||||
ValueWithUnit.Percent(percent),
|
||||
ValueWithUnit.Hour(timeShift).takeIf { timeShift != 0 },
|
||||
ValueWithUnit.Minute(duration).takeIf { duration != 0 })
|
||||
})
|
||||
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)), {
|
||||
profileFunction.createProfileSwitch(profileStore,
|
||||
profileName = profileName,
|
||||
durationInMinutes = duration,
|
||||
percentage = percent,
|
||||
timeShiftInHours = timeShift,
|
||||
timestamp = eventTime)
|
||||
uel.log(Action.PROFILE_SWITCH,
|
||||
Sources.ProfileSwitchDialog,
|
||||
notes,
|
||||
ValueWithUnit.Timestamp(eventTime).takeIf { eventTimeChanged },
|
||||
ValueWithUnit.SimpleString(profileName),
|
||||
ValueWithUnit.Percent(percent),
|
||||
ValueWithUnit.Hour(timeShift).takeIf { timeShift != 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
|
||||
}
|
||||
|
|
|
@ -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.pump.virtual.VirtualPumpPlugin
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.queue.commands.Command
|
||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
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())
|
||||
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.checkOnlyHardLimits(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.checkOnlyHardLimits(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(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
||||
if (!hardLimits.checkHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
||||
if (!hardLimits.checkHardLimits(profile.getIsfMgdl(), R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return
|
||||
if (!hardLimits.checkHardLimits(profile.getMaxDailyBasal(), R.string.profile_max_daily_basal_value, 0.02, hardLimits.maxBasal())) return
|
||||
if (!hardLimits.checkHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
|
||||
startPart = System.currentTimeMillis()
|
||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||
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())
|
||||
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.checkOnlyHardLimits(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.checkOnlyHardLimits(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(profile.dia, R.string.profile_dia, hardLimits.minDia(), hardLimits.maxDia())) return
|
||||
if (!hardLimits.checkHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), R.string.profile_carbs_ratio_value, hardLimits.minIC(), hardLimits.maxIC())) return
|
||||
if (!hardLimits.checkHardLimits(profile.getIsfMgdl(), R.string.profile_sensitivity_value, HardLimits.MIN_ISF, HardLimits.MAX_ISF)) return
|
||||
if (!hardLimits.checkHardLimits(profile.getMaxDailyBasal(), R.string.profile_max_daily_basal_value, 0.02, hardLimits.maxBasal())) return
|
||||
if (!hardLimits.checkHardLimits(pump.baseBasalRate, R.string.current_basal_value, 0.01, hardLimits.maxBasal())) return
|
||||
startPart = System.currentTimeMillis()
|
||||
if (constraintChecker.isAutosensModeEnabled().value()) {
|
||||
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
|
||||
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)
|
||||
?: throw InvalidParameterSpecException(profileName)
|
||||
val ps = ProfileSwitch(
|
||||
return ProfileSwitch(
|
||||
timestamp = timestamp,
|
||||
basalBlocks = pureProfile.basalBlocks,
|
||||
isfBlocks = pureProfile.isfBlocks,
|
||||
|
@ -105,8 +105,14 @@ class ProfileFunctionImplementation @Inject constructor(
|
|||
timeshift = T.hours(timeShiftInHours.toLong()).msecs(),
|
||||
percentage = percentage,
|
||||
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))
|
||||
.subscribe({ result ->
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted ProfileSwitch $it") }
|
||||
|
|
|
@ -740,7 +740,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
graphData.addTreatments()
|
||||
if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
|
||||
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.addTargetLine()
|
||||
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.utils.AndroidPermission
|
||||
import info.nightscout.androidaps.utils.CryptoUtil
|
||||
import info.nightscout.androidaps.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.extensions.isRunningTest
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
|
@ -53,7 +54,8 @@ class SWDefinition @Inject constructor(
|
|||
private val importExportPrefs: ImportExportPrefs,
|
||||
private val androidPermission: AndroidPermission,
|
||||
private val cryptoUtil: CryptoUtil,
|
||||
private val config: Config
|
||||
private val config: Config,
|
||||
private val hardLimits: HardLimits
|
||||
) {
|
||||
|
||||
lateinit var activity: AppCompatActivity
|
||||
|
@ -255,7 +257,7 @@ class SWDefinition @Inject constructor(
|
|||
.add(SWFragment(injector, this)
|
||||
.add(LocalProfileFragment()))
|
||||
.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
|
||||
}
|
||||
.visibility { localProfilePlugin.isEnabled() }
|
||||
|
|
|
@ -250,8 +250,6 @@
|
|||
<string name="smscommunicator_loophasbeendisabled">Loop has been disabled</string>
|
||||
<string name="smscommunicator_loophasbeenenabled">Loop has been 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_pumpconnectfail">Connection to pump failed</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="resistantadult">Insulin resistant adult</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="patient_name">Patient name</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="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="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="prime">Prime</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.notifications.Notification
|
||||
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.resources.ResourceHelper
|
||||
import org.json.JSONArray
|
||||
|
@ -94,34 +96,93 @@ sealed class ProfileSealed(
|
|||
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
|
||||
var valid = true
|
||||
val validityCheck = Profile.ValidityCheck()
|
||||
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
|
||||
val duration: Long = basal.duration
|
||||
if (duration % 3600000 != 0L) {
|
||||
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))
|
||||
}
|
||||
valid = false
|
||||
}
|
||||
// Check for minimal basal value
|
||||
if (basal.amount < description.basalMinimumRate) {
|
||||
basal.amount = description.basalMinimumRate
|
||||
if (notify) sendBelowMinimumNotification(from, rxBus, resourceHelper)
|
||||
valid = false
|
||||
} else if (basal.amount > description.basalMaximumRate) {
|
||||
basal.amount = description.basalMaximumRate
|
||||
if (notify) sendAboveMaximumNotification(from, rxBus, resourceHelper)
|
||||
valid = false
|
||||
validityCheck.isValid = false
|
||||
validityCheck.reasons.add(
|
||||
resourceHelper.gs(
|
||||
R.string.basalprofilenotaligned,
|
||||
from
|
||||
)
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
// Check for minimal basal value
|
||||
if (basalAmount < description.basalMinimumRate) {
|
||||
basal.amount = description.basalMinimumRate
|
||||
if (notify) sendBelowMinimumNotification(from, rxBus, resourceHelper)
|
||||
validityCheck.isValid = false
|
||||
validityCheck.reasons.add(resourceHelper.gs(R.string.minimalbasalvaluereplaced, from))
|
||||
break
|
||||
} else if (basalAmount > description.basalMaximumRate) {
|
||||
basal.amount = description.basalMaximumRate
|
||||
if (notify) sendAboveMaximumNotification(from, rxBus, resourceHelper)
|
||||
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
|
||||
}
|
||||
}
|
||||
return valid
|
||||
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))
|
||||
}
|
||||
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) {
|
||||
|
|
|
@ -17,15 +17,18 @@ import info.nightscout.androidaps.database.AppRepository
|
|||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.extensions.getCustomizedName
|
||||
import info.nightscout.androidaps.extensions.pureProfileFromJson
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import org.json.JSONObject
|
||||
import java.io.File.separator
|
||||
import java.text.DecimalFormat
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -39,6 +42,7 @@ class ProfileViewerDialog : DaggerDialogFragment() {
|
|||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var hardLimits: HardLimits
|
||||
|
||||
private var time: Long = 0
|
||||
|
||||
|
@ -149,7 +153,9 @@ class ProfileViewerDialog : DaggerDialogFragment() {
|
|||
}
|
||||
|
||||
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
|
||||
profile?.let {
|
||||
|
@ -164,7 +170,9 @@ class ProfileViewerDialog : DaggerDialogFragment() {
|
|||
binding.basalGraph.show(it)
|
||||
|
||||
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.DecimalFormatter.to0Decimal
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter.to1Decimal
|
||||
import info.nightscout.androidaps.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.Round
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import org.joda.time.DateTime
|
||||
|
@ -13,7 +14,9 @@ import org.json.JSONObject
|
|||
|
||||
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
|
||||
|
|
|
@ -46,6 +46,18 @@ interface ProfileFunction {
|
|||
*/
|
||||
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
|
||||
*
|
||||
|
|
|
@ -63,7 +63,7 @@ class PumpDescription() {
|
|||
is30minBasalRatesCapable = false
|
||||
isRefillingCapable = true
|
||||
isBatteryReplaceable = true
|
||||
storesCarbInfo = true
|
||||
storesCarbInfo = false
|
||||
supportsTDDs = false
|
||||
needsManualTDDLoad = true
|
||||
hasCustomUnreachableAlertCheck = false
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package info.nightscout.androidaps.utils
|
||||
|
||||
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.transactions.InsertTherapyEventAnnouncementTransaction
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
|
@ -15,6 +16,7 @@ import javax.inject.Singleton
|
|||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
@OpenForTesting
|
||||
@Singleton
|
||||
class HardLimits @Inject constructor(
|
||||
private val aapsLogger: AAPSLogger,
|
||||
|
@ -81,9 +83,12 @@ class HardLimits @Inject constructor(
|
|||
fun maxIC(): Double = MAX_IC[loadAge()]
|
||||
|
||||
// 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)
|
||||
|
||||
fun isInRange(value: Double, lowLimit: Double, highLimit: Double): Boolean =
|
||||
value in lowLimit..highLimit
|
||||
|
||||
fun verifyHardLimits(value: Double, valueName: Int, lowLimit: Double, highLimit: Double): Double {
|
||||
var newValue = value
|
||||
if (newValue < lowLimit || newValue > highLimit) {
|
||||
|
@ -98,4 +103,4 @@ class HardLimits @Inject constructor(
|
|||
}
|
||||
return newValue
|
||||
}
|
||||
}
|
||||
}
|
|
@ -90,7 +90,11 @@ class SPImplementation @Inject constructor(
|
|||
return try {
|
||||
sharedPreferences.getLong(key, defaultValue)
|
||||
} catch (e: Exception) {
|
||||
SafeParse.stringToLong(sharedPreferences.getString(key, defaultValue.toString()))
|
||||
try {
|
||||
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_type" translatable="false">active_pump_type</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-->
|
||||
<string name="refresh">Refresh</string>
|
||||
|
@ -472,6 +478,22 @@
|
|||
<string name="uel_loop_removed">LOOP REMOVED</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">
|
||||
<item quantity="one">%1$d day</item>
|
||||
<item quantity="other">%1$d days</item>
|
||||
|
|
|
@ -2,11 +2,10 @@ package info.nightscout.androidaps.data
|
|||
|
||||
import android.content.Context
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.TestBase
|
||||
import info.nightscout.androidaps.TestPumpPlugin
|
||||
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.interfaces.ActivePlugin
|
||||
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.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.TestAapsSchedulers
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import org.json.JSONObject
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.anyInt
|
||||
import org.mockito.Mockito.anyString
|
||||
import org.mockito.Mockito.doNothing
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
|
@ -38,25 +37,29 @@ class ProfileTest : TestBase() {
|
|||
@Mock lateinit var resourceHelper: ResourceHelper
|
||||
@Mock lateinit var context: Context
|
||||
@Mock lateinit var config: Config
|
||||
@Mock lateinit var sp: SP
|
||||
@Mock lateinit var repository: AppRepository
|
||||
|
||||
private lateinit var rxBus: RxBusWrapper
|
||||
private lateinit var dateUtil: DateUtil
|
||||
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 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 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 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 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 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 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\":\"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\":\"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\":\"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\":\"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\":\"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 + "}}";
|
||||
|
||||
@Before
|
||||
fun prepare() {
|
||||
testPumpPlugin = TestPumpPlugin(HasAndroidInjector { AndroidInjector { } })
|
||||
testPumpPlugin = TestPumpPlugin { AndroidInjector { } }
|
||||
dateUtil = DateUtil(context)
|
||||
rxBus = RxBusWrapper(TestAapsSchedulers())
|
||||
hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context, repository)
|
||||
`when`(activePluginProvider.activePump).thenReturn(testPumpPlugin)
|
||||
`when`(resourceHelper.gs(R.string.profile_per_unit)).thenReturn("/U")
|
||||
`when`(resourceHelper.gs(R.string.profile_carbs_per_unit)).thenReturn("g/U")
|
||||
|
@ -69,10 +72,10 @@ class ProfileTest : TestBase() {
|
|||
|
||||
// Test valid profile
|
||||
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"))
|
||||
// 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("00:30", dateUtil.format_HH_MM(30 * 60))
|
||||
val c = Calendar.getInstance()
|
||||
|
@ -80,13 +83,13 @@ class ProfileTest : TestBase() {
|
|||
c[Calendar.MINUTE] = 0
|
||||
c[Calendar.SECOND] = 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
|
||||
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("""
|
||||
00:00 100,0 mmol/U
|
||||
02:00 110,0 mmol/U
|
||||
00:00 6,0 mmol/U
|
||||
02:00 6,2 mmol/U
|
||||
""".trimIndent(), p.getIsfList(resourceHelper, dateUtil).replace(".", ","))
|
||||
Assert.assertEquals(30.0, p.getIc(c.timeInMillis), 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
|
||||
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
|
||||
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(1.2, p.percentageBasalSum(), 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
|
||||
p = ProfileSealed.Pure(pureProfileFromJson(JSONObject(okProfile), dateUtil)!!)
|
||||
p.ts = 1
|
||||
Assert.assertEquals(
|
||||
"""
|
||||
00:00 110.0 mmol/U
|
||||
01:00 100.0 mmol/U
|
||||
03:00 110.0 mmol/U
|
||||
00:00 6.2 mmol/U
|
||||
01:00 6.0 mmol/U
|
||||
03:00 6.2 mmol/U
|
||||
""".trimIndent(), p.getIsfList(resourceHelper, dateUtil))
|
||||
|
||||
// Test hour alignment
|
||||
testPumpPlugin.pumpDescription.is30minBasalRatesCapable = false
|
||||
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