Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Night mode #2840

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions core/ui/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,18 @@
<string name="max_carbs_title">Max allowed carbs [g]</string>
<string name="patient_type">Patient type</string>

<!-- Night mode -->
<string name="treatment_safety_night_mode">Night mode</string>
<string name="treatment_safety_night_mode_enabled">Use night mode</string>
<string name="treatment_safety_night_mode_bg_offset_title">BG offset</string>
<string name="treatment_safety_night_mode_bg_offset_description">There will be no SMB when below this BG offset from profile target at night unless COB or a low TT is active\ne.g. if normalTarget is 5.5 (99) and this setting is 1.5 (27) there will be no SMB below 7.0 (126)</string>
<string name="treatment_safety_night_mode_start_title">Start time (24h format)</string>
<string name="treatment_safety_night_mode_end_title">End time (24h format)</string>
<string name="treatment_safety_night_mode_disable_with_cob_title">Disable night mode when COB > 0</string>
<string name="treatment_safety_night_mode_disable_with_low_temp_target_title">Disable night mode when Temporary Target below Profile Target is set</string>
<string name="treatment_safety_night_mode_smb_disabled">SMB disabled by Night mode</string>
<!-- /Night mode -->

<!-- Protection-->
<string name="unlock_settings">Unlock settings</string>

Expand Down
9 changes: 9 additions & 0 deletions core/utils/src/main/res/values/keys.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@
<string name="key_smscommunicator_settings" translatable="false">smscommunicator_settings</string>
<string name="key_openapssmb_settings" translatable="false">openapssmb_settings</string>
<string name="key_treatmentssafety_settings" translatable="false">treatmentssafety_settings</string>
<!-- Night mode -->
<string name="key_treatment_safety_night_mode_enabled" translatable="false">treatment_safety_night_mode_enabled</string>
<string name="key_treatment_safety_night_mode_bg_offset" translatable="false">treatment_safety_night_mode_bg_offset</string>
<string name="key_treatment_safety_night_mode_start" translatable="false">treatment_safety_night_mode_start</string>
<string name="key_treatment_safety_night_mode_end" translatable="false">treatment_safety_night_mode_end</string>
<string name="key_treatment_safety_night_mode_disable_with_cob" translatable="false">treatment_safety_night_mode_disable_with_cob</string>
<string name="key_treatment_safety_night_mode_disable_with_low_temp_target" translatable="false">treatment_safety_night_mode_disable_with_low_temp_target</string>

<!-- /Night mode -->
<string name="key_loop_settings" translatable="false">loop_settings</string>
<string name="key_virtualpump_settings" translatable="false">virtualpump_settings</string>
<string name="key_pump_settings" translatable="false">pump_settings</string>
Expand Down
3 changes: 3 additions & 0 deletions core/validators/src/main/res/values/validator.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<string name="error_mustbe12hexadidits">Must be 12 characters of ABCDEF0123456789</string>
<string name="error_mustbe8hexadidits">Must be 8 characters of ABCDEF0123456789</string>
<string name="error_mustbe4hexadidits">Must be 4 characters of ABCDEF0123456789</string>
<string name="error_invalid_time">Must be time value in hh:mm (24h) format</string>
<string name="error_not_a_minimum_length">Not a minimum length</string>
<string name="error_pin_not_valid">Pin should be 3 to 6 digits, not same or in series</string>

Expand All @@ -27,4 +28,6 @@
<string name="eighthexanumber" translatable="false">^[A-F0-9]{8}$</string>
<string name="fourhexanumber" translatable="false">^[A-F0-9]{4}$</string>

<string name="time" translatable="false">^\\d{1,2}:\\d{1,2}$</string>

</resources>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package info.nightscout.plugins.aps.openAPSSMB

import android.content.Context
import android.icu.text.SimpleDateFormat
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import dagger.android.HasAndroidInjector
Expand All @@ -17,8 +18,10 @@ import info.nightscout.interfaces.bgQualityCheck.BgQualityCheck
import info.nightscout.interfaces.constraints.Constraint
import info.nightscout.interfaces.constraints.ConstraintsChecker
import info.nightscout.interfaces.constraints.PluginConstraints
import info.nightscout.interfaces.iob.GlucoseStatus
import info.nightscout.interfaces.iob.GlucoseStatusProvider
import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.iob.MealData
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription
Expand All @@ -28,6 +31,7 @@ import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.profiling.Profiler
import info.nightscout.interfaces.stats.TddCalculator
import info.nightscout.interfaces.utils.HardLimits
import info.nightscout.interfaces.utils.MidnightTime
import info.nightscout.interfaces.utils.Round
import info.nightscout.plugins.aps.R
import info.nightscout.plugins.aps.events.EventResetOpenAPSGui
Expand All @@ -38,9 +42,12 @@ import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import org.joda.time.LocalTime
import org.joda.time.format.ISODateTimeFormat
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.floor
import kotlin.time.Duration.Companion.hours

@Singleton
open class OpenAPSSMBPlugin @Inject constructor(
Expand Down Expand Up @@ -88,6 +95,10 @@ open class OpenAPSSMBPlugin @Inject constructor(
override var lastDetermineBasalAdapter: DetermineBasalAdapter? = null
override var lastAutosensResult = AutosensResult()

var profileShared: Profile? = null
var glucoseStatusShared : GlucoseStatus? = null
var mealDataShared : MealData? = null

override fun specialEnableCondition(): Boolean {
return try {
activePlugin.activePump.pumpDescription.isTempBasalCapable
Expand All @@ -110,11 +121,27 @@ open class OpenAPSSMBPlugin @Inject constructor(
preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_enableSMB_after_carbs))?.isVisible = !smbAlwaysEnabled
}

private fun verifyProfileLoaded(allowCurrent : Boolean = false) : Profile? {
if (profileShared == null || !allowCurrent) profileFunction.getProfile().also { profileShared = it }
return profileShared
}

private fun verifyGlucoseStatusLoaded(allowCurrent : Boolean = false) : GlucoseStatus? {
if (glucoseStatusShared == null || !allowCurrent) glucoseStatusProvider.glucoseStatusData.also { glucoseStatusShared = it }
return glucoseStatusShared
}

private fun verifyMealDataLoaded(allowCurrent : Boolean = false) : MealData {
if (mealDataShared == null || !allowCurrent) mealDataShared = iobCobCalculator.getMealDataWithWaitingForCalculationFinish()
return mealDataShared!!
}

override fun invoke(initiator: String, tempBasalFallback: Boolean) {
aapsLogger.debug(LTag.APS, "invoke from $initiator tempBasalFallback: $tempBasalFallback")
lastAPSResult = null
val glucoseStatus = glucoseStatusProvider.glucoseStatusData
val profile = profileFunction.getProfile()
val profile = verifyProfileLoaded()
val glucoseStatus = verifyGlucoseStatusLoaded()
val mealData = verifyMealDataLoaded()
val pump = activePlugin.activePump
if (profile == null) {
rxBus.send(info.nightscout.plugins.aps.events.EventResetOpenAPSGui(rh.gs(info.nightscout.core.ui.R.string.no_profile_set)))
Expand Down Expand Up @@ -258,7 +285,7 @@ open class OpenAPSSMBPlugin @Inject constructor(
activePlugin.activePump.baseBasalRate,
iobArray,
glucoseStatus,
iobCobCalculator.getMealDataWithWaitingForCalculationFinish(),
mealData,
lastAutosensResult.ratio,
isTempTarget,
smbAllowed.value(),
Expand Down Expand Up @@ -336,6 +363,53 @@ open class OpenAPSSMBPlugin @Inject constructor(
override fun isSMBModeEnabled(value: Constraint<Boolean>): Constraint<Boolean> {
val enabled = sp.getBoolean(R.string.key_use_smb, false)
if (!enabled) value.set(false, rh.gs(R.string.smb_disabled_in_preferences), this)
val bgCurrent = verifyGlucoseStatusLoaded(true)?.glucose
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_treatment_safety_night_mode_enabled, false) && bgCurrent != null) {

val currentTimeMillis = System.currentTimeMillis()
val midnight = MidnightTime.calc(currentTimeMillis)
val startHour = sp.getString(info.nightscout.core.utils.R.string.key_treatment_safety_night_mode_start, "22:00")
val start = midnight + LocalTime.parse(startHour, ISODateTimeFormat.timeElementParser()).millisOfDay
val endHour = sp.getString(info.nightscout.core.utils.R.string.key_treatment_safety_night_mode_end, "7:00");
val end = midnight + LocalTime.parse(endHour, ISODateTimeFormat.timeElementParser()).millisOfDay
val bgOffset = sp.getDouble(info.nightscout.core.utils.R.string.key_treatment_safety_night_mode_bg_offset, 27.0)
val active =
if (end > start) currentTimeMillis in start..<end
else (currentTimeMillis in (start - 86400000)..<end || currentTimeMillis in start..<(end + 86400000))

if (!active) return value

if (sp.getBoolean(info.nightscout.core.utils.R.string.key_treatment_safety_night_mode_disable_with_cob, false)) {
val mealData = verifyMealDataLoaded(true)
if (mealData.mealCOB > 0) return value
}

val profile = verifyProfileLoaded(true)
val profileTarget = profile?.getTargetMgdl() ?: 99.0

if (sp.getBoolean(info.nightscout.core.utils.R.string.key_treatment_safety_night_mode_disable_with_low_temp_target, false)) {
var targetBg = profileTarget
var isTempTarget = false
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
if (tempTarget is ValueWrapper.Existing) {
isTempTarget = true
targetBg =
hardLimits.verifyHardLimits(
tempTarget.value.target(),
info.nightscout.core.ui.R.string.temp_target_value,
HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[0].toDouble(),
HardLimits.VERY_HARD_LIMIT_TEMP_TARGET_BG[1].toDouble()
)
}

if (isTempTarget && targetBg < profileTarget) return value
}

if (bgCurrent < profileTarget + bgOffset) {
value.set(false, rh.gs(info.nightscout.core.ui.R.string.treatment_safety_night_mode_smb_disabled), this)
return value
}
}
return value
}

Expand Down
54 changes: 54 additions & 0 deletions plugins/constraints/src/main/res/xml/pref_safety.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,60 @@
validate:floatminNumber="1"
validate:testType="numericRange" />

<androidx.preference.PreferenceScreen
android:key="safety_night_mode"
android:title="@string/treatment_safety_night_mode">

<SwitchPreference
android:defaultValue="false"
android:key="@string/key_treatment_safety_night_mode_enabled"
android:title="@string/treatment_safety_night_mode_enabled" />

<info.nightscout.core.validators.ValidatingEditTextPreference
android:dependency="@string/key_treatment_safety_night_mode_enabled"
android:defaultValue="27"
android:inputType="numberDecimal"
android:title="@string/treatment_safety_night_mode_bg_offset_title"
android:key="@string/key_treatment_safety_night_mode_bg_offset"
android:dialogMessage="@string/treatment_safety_night_mode_bg_offset_description"
validate:floatmaxNumber="270.0"
validate:floatminNumber="0"
validate:testType="bgRange" />

<info.nightscout.core.validators.ValidatingEditTextPreference
android:dependency="@string/key_treatment_safety_night_mode_enabled"
android:defaultValue="23:00"
android:inputType="text"
android:key="@string/key_treatment_safety_night_mode_start"
android:title="@string/treatment_safety_night_mode_start_title"
validate:customRegexp="@string/time"
validate:testErrorString="@string/error_invalid_time"
validate:testType="regexp" />

<info.nightscout.core.validators.ValidatingEditTextPreference
android:dependency="@string/key_treatment_safety_night_mode_enabled"
android:defaultValue="07:00"
android:inputType="text"
android:key="@string/key_treatment_safety_night_mode_end"
android:title="@string/treatment_safety_night_mode_end_title"
validate:customRegexp="@string/time"
validate:testErrorString="@string/error_invalid_time"
validate:testType="regexp" />

<SwitchPreference
android:dependency="@string/key_treatment_safety_night_mode_enabled"
android:defaultValue="false"
android:key="@string/key_treatment_safety_night_mode_disable_with_cob"
android:title="@string/treatment_safety_night_mode_disable_with_cob_title" />

<SwitchPreference
android:dependency="@string/key_treatment_safety_night_mode_enabled"
android:defaultValue="false"
android:key="@string/key_treatment_safety_night_mode_disable_with_low_temp_target"
android:title="@string/treatment_safety_night_mode_disable_with_low_temp_target_title" />

</androidx.preference.PreferenceScreen>

</PreferenceCategory>

</androidx.preference.PreferenceScreen>