Merge pull request #1817 from Philoul/Autotune/TuneWeekDaysClean
Autotune feature : Tune Specific days of the week
This commit is contained in:
commit
70a57ec475
8 changed files with 194 additions and 64 deletions
|
@ -2,7 +2,7 @@ package info.nightscout.interfaces.autotune
|
||||||
|
|
||||||
interface Autotune {
|
interface Autotune {
|
||||||
|
|
||||||
fun aapsAutotune(daysBack: Int, autoSwitch: Boolean, profileToTune: String = "")
|
fun aapsAutotune(daysBack: Int, autoSwitch: Boolean, profileToTune: String = "", weekDays: BooleanArray? = null)
|
||||||
fun atLog(message: String)
|
fun atLog(message: String)
|
||||||
|
|
||||||
var lastRunSuccess: Boolean
|
var lastRunSuccess: Boolean
|
||||||
|
|
|
@ -442,6 +442,7 @@
|
||||||
<string name="autotune_ic_warning">Selected profile has %1$d IC values. Autotune will use %2$.2f g/U</string>
|
<string name="autotune_ic_warning">Selected profile has %1$d IC values. Autotune will use %2$.2f g/U</string>
|
||||||
<string name="autotune_isf_warning">Selected profile has %1$d ISF values. Autotune will use %2$.1f %3$s/U</string>
|
<string name="autotune_isf_warning">Selected profile has %1$d ISF values. Autotune will use %2$.1f %3$s/U</string>
|
||||||
<string name="autotune_error">Error in input data, try to run again autotune or reduce the number of days</string>
|
<string name="autotune_error">Error in input data, try to run again autotune or reduce the number of days</string>
|
||||||
|
<string name="autotune_error_more_days">Error in input data, increase the number of days</string>
|
||||||
<string name="autotune_warning_during_run">Autotune calculation started, please be patient</string>
|
<string name="autotune_warning_during_run">Autotune calculation started, please be patient</string>
|
||||||
<string name="autotune_warning_after_run">Check the results carefully before using it!</string>
|
<string name="autotune_warning_after_run">Check the results carefully before using it!</string>
|
||||||
<string name="autotune_partial_result">Partial result day %1$d / %2$d tuned</string>
|
<string name="autotune_partial_result">Partial result day %1$d / %2$d tuned</string>
|
||||||
|
|
|
@ -30,4 +30,5 @@ dependencies {
|
||||||
|
|
||||||
// APS
|
// APS
|
||||||
api 'org.mozilla:rhino:1.7.14'
|
api 'org.mozilla:rhino:1.7.14'
|
||||||
|
implementation project(path: ':plugins:automation')
|
||||||
}
|
}
|
|
@ -19,6 +19,7 @@ import android.widget.TableRow
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
|
import info.nightscout.automation.elements.InputWeekDay
|
||||||
import info.nightscout.core.profile.ProfileSealed
|
import info.nightscout.core.profile.ProfileSealed
|
||||||
import info.nightscout.core.ui.dialogs.OKDialog
|
import info.nightscout.core.ui.dialogs.OKDialog
|
||||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||||
|
@ -79,6 +80,9 @@ class AutotuneFragment : DaggerFragment() {
|
||||||
private lateinit var profileStore: ProfileStore
|
private lateinit var profileStore: ProfileStore
|
||||||
private var profileName = ""
|
private var profileName = ""
|
||||||
private var profile: ATProfile? = null
|
private var profile: ATProfile? = null
|
||||||
|
private val days get() = autotunePlugin.days
|
||||||
|
private val daysBack get() = SafeParse.stringToInt(binding.tuneDays.text)
|
||||||
|
private val calcDays get() = autotunePlugin.calcDays(daysBack)
|
||||||
|
|
||||||
// This property is only valid between onCreateView and
|
// This property is only valid between onCreateView and
|
||||||
// onDestroyView.
|
// onDestroyView.
|
||||||
|
@ -102,18 +106,34 @@ class AutotuneFragment : DaggerFragment() {
|
||||||
profileFunction.getProfile()?.let { currentProfile ->
|
profileFunction.getProfile()?.let { currentProfile ->
|
||||||
profile = ATProfile(profileStore.getSpecificProfile(profileName)?.let { ProfileSealed.Pure(it) } ?: currentProfile, LocalInsulin(""), injector)
|
profile = ATProfile(profileStore.getSpecificProfile(profileName)?.let { ProfileSealed.Pure(it) } ?: currentProfile, LocalInsulin(""), injector)
|
||||||
}
|
}
|
||||||
|
days.addToLayout(binding.selectWeekDays)
|
||||||
|
days.view?.setOnWeekdaysChangeListener { i: Int, selected: Boolean ->
|
||||||
|
if (autotunePlugin.calculationRunning)
|
||||||
|
days.view?.setSelectedDays(days.getSelectedDays())
|
||||||
|
else {
|
||||||
|
days.set(InputWeekDay.DayOfWeek.fromCalendarInt(i), selected)
|
||||||
|
resetParam(false)
|
||||||
|
updateGui()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.tuneDays.setParams(
|
binding.tuneDays.setParams(
|
||||||
savedInstanceState?.getDouble("tunedays")
|
savedInstanceState?.getDouble("tunedays")
|
||||||
?: defaultValue, 1.0, 30.0, 1.0, DecimalFormat("0"), false, null, textWatcher
|
?: defaultValue, 1.0, 30.0, 1.0, DecimalFormat("0"), false, null, textWatcher
|
||||||
)
|
)
|
||||||
binding.autotuneRun.setOnClickListener {
|
binding.autotuneRun.setOnClickListener {
|
||||||
val daysBack = SafeParse.stringToInt(binding.tuneDays.text)
|
|
||||||
autotunePlugin.lastNbDays = daysBack.toString()
|
autotunePlugin.lastNbDays = daysBack.toString()
|
||||||
log("Run Autotune $profileName, $daysBack days")
|
log("Run Autotune $profileName, $daysBack days")
|
||||||
handler.post { autotunePlugin.aapsAutotune(daysBack, false, profileName) }
|
handler.post { autotunePlugin.aapsAutotune(daysBack, false, profileName) }
|
||||||
updateGui()
|
updateGui()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.showWeekDaysCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
run {
|
||||||
|
binding.selectWeekDays.visibility = isChecked.toVisibility()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.profileList.onItemClickListener = AdapterView.OnItemClickListener { _, _, _, _ ->
|
binding.profileList.onItemClickListener = AdapterView.OnItemClickListener { _, _, _, _ ->
|
||||||
if (!autotunePlugin.calculationRunning) {
|
if (!autotunePlugin.calculationRunning) {
|
||||||
profileName = if (binding.profileList.text.toString() == rh.gs(info.nightscout.core.ui.R.string.active)) "" else binding.profileList.text.toString()
|
profileName = if (binding.profileList.text.toString() == rh.gs(info.nightscout.core.ui.R.string.active)) "" else binding.profileList.text.toString()
|
||||||
|
@ -121,7 +141,7 @@ class AutotuneFragment : DaggerFragment() {
|
||||||
profile = ATProfile(profileStore.getSpecificProfile(profileName)?.let { ProfileSealed.Pure(it) } ?: currentProfile, LocalInsulin(""), injector)
|
profile = ATProfile(profileStore.getSpecificProfile(profileName)?.let { ProfileSealed.Pure(it) } ?: currentProfile, LocalInsulin(""), injector)
|
||||||
}
|
}
|
||||||
autotunePlugin.selectedProfile = profileName
|
autotunePlugin.selectedProfile = profileName
|
||||||
resetParam()
|
resetParam(true)
|
||||||
binding.tuneDays.value = autotunePlugin.lastNbDays.toDouble()
|
binding.tuneDays.value = autotunePlugin.lastNbDays.toDouble()
|
||||||
}
|
}
|
||||||
updateGui()
|
updateGui()
|
||||||
|
@ -282,6 +302,7 @@ class AutotuneFragment : DaggerFragment() {
|
||||||
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
||||||
checkNewDay()
|
checkNewDay()
|
||||||
binding.tuneDays.value = autotunePlugin.lastNbDays.toDouble()
|
binding.tuneDays.value = autotunePlugin.lastNbDays.toDouble()
|
||||||
|
binding.selectWeekDays.visibility = binding.showWeekDaysCheckbox.isChecked.toVisibility()
|
||||||
updateGui()
|
updateGui()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,6 +332,7 @@ class AutotuneFragment : DaggerFragment() {
|
||||||
else {
|
else {
|
||||||
binding.profileList.setText(profileList[0], false)
|
binding.profileList.setText(profileList[0], false)
|
||||||
}
|
}
|
||||||
|
days.view?.setSelectedDays(days.getSelectedDays())
|
||||||
binding.autotuneRun.visibility = View.GONE
|
binding.autotuneRun.visibility = View.GONE
|
||||||
binding.autotuneCheckInputProfile.visibility = View.GONE
|
binding.autotuneCheckInputProfile.visibility = View.GONE
|
||||||
binding.autotuneCopyLocal.visibility = View.GONE
|
binding.autotuneCopyLocal.visibility = View.GONE
|
||||||
|
@ -333,10 +355,13 @@ class AutotuneFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
binding.autotuneRun.visibility = (profile?.isValid == true).toVisibility()
|
if (profile?.isValid == true && calcDays > 0)
|
||||||
|
binding.autotuneRun.visibility = View.VISIBLE
|
||||||
binding.autotuneCheckInputProfile.visibility = View.VISIBLE
|
binding.autotuneCheckInputProfile.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
binding.calcDays.text = calcDays.toString()
|
||||||
|
binding.calcDays.visibility = if (daysBack == calcDays) View.INVISIBLE else View.VISIBLE
|
||||||
binding.tuneLastRun.text = dateUtil.dateAndTimeString(autotunePlugin.lastRun)
|
binding.tuneLastRun.text = dateUtil.dateAndTimeString(autotunePlugin.lastRun)
|
||||||
showResults()
|
showResults()
|
||||||
}
|
}
|
||||||
|
@ -345,10 +370,9 @@ class AutotuneFragment : DaggerFragment() {
|
||||||
val runToday = autotunePlugin.lastRun > MidnightTime.calc(dateUtil.now() - autotunePlugin.autotuneStartHour * 3600 * 1000L) + autotunePlugin.autotuneStartHour * 3600 * 1000L
|
val runToday = autotunePlugin.lastRun > MidnightTime.calc(dateUtil.now() - autotunePlugin.autotuneStartHour * 3600 * 1000L) + autotunePlugin.autotuneStartHour * 3600 * 1000L
|
||||||
if (runToday && autotunePlugin.result != "") {
|
if (runToday && autotunePlugin.result != "") {
|
||||||
binding.tuneWarning.text = rh.gs(info.nightscout.core.ui.R.string.autotune_warning_after_run)
|
binding.tuneWarning.text = rh.gs(info.nightscout.core.ui.R.string.autotune_warning_after_run)
|
||||||
} else if (!runToday || autotunePlugin.result.isEmpty()) { //if new day re-init result, default days, warning and button's visibility
|
} else if (!runToday || autotunePlugin.result.isEmpty()) //if new day re-init result, default days, warning and button's visibility
|
||||||
resetParam(!runToday)
|
resetParam(!runToday)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun addWarnings(): String {
|
private fun addWarnings(): String {
|
||||||
var warning = ""
|
var warning = ""
|
||||||
|
@ -372,10 +396,12 @@ class AutotuneFragment : DaggerFragment() {
|
||||||
return warning
|
return warning
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resetParam(resetDay: Boolean = true) {
|
private fun resetParam(resetDay: Boolean) {
|
||||||
binding.tuneWarning.text = addWarnings()
|
binding.tuneWarning.text = addWarnings()
|
||||||
if (resetDay)
|
if (resetDay) {
|
||||||
autotunePlugin.lastNbDays = sp.getInt(info.nightscout.core.utils.R.string.key_autotune_default_tune_days, 5).toString()
|
autotunePlugin.lastNbDays = sp.getInt(info.nightscout.core.utils.R.string.key_autotune_default_tune_days, 5).toString()
|
||||||
|
days.setAll(true)
|
||||||
|
}
|
||||||
autotunePlugin.result = ""
|
autotunePlugin.result = ""
|
||||||
binding.autotuneResults.removeAllViews()
|
binding.autotuneResults.removeAllViews()
|
||||||
autotunePlugin.tunedProfile = null
|
autotunePlugin.tunedProfile = null
|
||||||
|
|
|
@ -2,6 +2,7 @@ package info.nightscout.plugins.general.autotune
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.automation.elements.InputWeekDay
|
||||||
import info.nightscout.core.extensions.pureProfileFromJson
|
import info.nightscout.core.extensions.pureProfileFromJson
|
||||||
import info.nightscout.core.profile.ProfileSealed
|
import info.nightscout.core.profile.ProfileSealed
|
||||||
import info.nightscout.database.entities.UserEntry
|
import info.nightscout.database.entities.UserEntry
|
||||||
|
@ -37,12 +38,12 @@ import org.json.JSONObject
|
||||||
import java.util.TimeZone
|
import java.util.TimeZone
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* adaptation from oref0 autotune started by philoul on 2020 (complete refactoring of AutotunePlugin initialised by Rumen Georgiev on 1/29/2018.)
|
* adaptation from oref0 autotune developed by philoul on 2022 (complete refactoring of AutotunePlugin initialised by Rumen Georgiev on 1/29/2018.)
|
||||||
*
|
*
|
||||||
* TODO: replace Thread by Worker
|
* TODO: replace Thread by Worker
|
||||||
* TODO: future version: Allow day of the week selection to tune specifics days (training days, working days, WE days)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@ -86,15 +87,29 @@ class AutotunePlugin @Inject constructor(
|
||||||
@Volatile var tunedProfile: ATProfile? = null
|
@Volatile var tunedProfile: ATProfile? = null
|
||||||
private var preppedGlucose: PreppedGlucose? = null
|
private var preppedGlucose: PreppedGlucose? = null
|
||||||
private lateinit var profile: Profile
|
private lateinit var profile: Profile
|
||||||
|
val days = InputWeekDay()
|
||||||
val autotuneStartHour: Int = 4
|
val autotuneStartHour: Int = 4
|
||||||
|
|
||||||
override fun aapsAutotune(daysBack: Int, autoSwitch: Boolean, profileToTune: String) {
|
override fun aapsAutotune(daysBack: Int, autoSwitch: Boolean, profileToTune: String, weekDays: BooleanArray?) {
|
||||||
lastRunSuccess = false
|
lastRunSuccess = false
|
||||||
if (calculationRunning) {
|
if (calculationRunning) {
|
||||||
aapsLogger.debug(LTag.AUTOMATION, "Autotune run detected, Autotune Run Cancelled")
|
aapsLogger.debug(LTag.AUTOMATION, "Autotune run detected, Autotune Run Cancelled")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
calculationRunning = true
|
calculationRunning = true
|
||||||
|
weekDays?.let {
|
||||||
|
for (i in weekDays.indices)
|
||||||
|
days.weekdays[i] = weekDays[i]
|
||||||
|
}
|
||||||
|
val calcDays = calcDays(daysBack)
|
||||||
|
val sb = StringBuilder()
|
||||||
|
sb.append("Selected days: ")
|
||||||
|
var counter = 0
|
||||||
|
for (i in days.getSelectedDays()) {
|
||||||
|
if (counter++ > 0) sb.append(",")
|
||||||
|
sb.append(InputWeekDay.DayOfWeek.fromCalendarInt(i))
|
||||||
|
}
|
||||||
|
log(sb.toString())
|
||||||
tunedProfile = null
|
tunedProfile = null
|
||||||
updateButtonVisibility = View.GONE
|
updateButtonVisibility = View.GONE
|
||||||
var logResult = ""
|
var logResult = ""
|
||||||
|
@ -138,10 +153,24 @@ class AutotunePlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
autotuneFS.exportPumpProfile(pumpProfile)
|
autotuneFS.exportPumpProfile(pumpProfile)
|
||||||
|
|
||||||
|
if (calcDays==0) {
|
||||||
|
result = rh.gs(info.nightscout.core.ui.R.string.autotune_error_more_days)
|
||||||
|
log(result)
|
||||||
|
calculationRunning = false
|
||||||
|
tunedProfile = null
|
||||||
|
autotuneFS.exportResult(result)
|
||||||
|
autotuneFS.exportLogAndZip(lastRun)
|
||||||
|
rxBus.send(EventAutotuneUpdateGui())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var currentCalcDay = 0
|
||||||
for (i in 0 until daysBack) {
|
for (i in 0 until daysBack) {
|
||||||
val from = starttime + i * 24 * 60 * 60 * 1000L // get 24 hours BG values from 4 AM to 4 AM next day
|
val from = starttime + i * 24 * 60 * 60 * 1000L // get 24 hours BG values from 4 AM to 4 AM next day
|
||||||
val to = from + 24 * 60 * 60 * 1000L
|
val to = from + 24 * 60 * 60 * 1000L
|
||||||
log("Tune day " + (i + 1) + " of " + daysBack)
|
if (days.isSet(from)) {
|
||||||
|
currentCalcDay++
|
||||||
|
|
||||||
|
log("Tune day " + (i + 1) + " of " + daysBack + " (" + currentCalcDay + " of " + calcDays + ")")
|
||||||
tunedProfile?.let {
|
tunedProfile?.let {
|
||||||
autotuneIob.initializeData(from, to, it) //autotuneIob contains BG and Treatments data from history (<=> query for ns-treatments and ns-entries)
|
autotuneIob.initializeData(from, to, it) //autotuneIob contains BG and Treatments data from history (<=> query for ns-treatments and ns-entries)
|
||||||
if (autotuneIob.boluses.size == 0) {
|
if (autotuneIob.boluses.size == 0) {
|
||||||
|
@ -156,13 +185,13 @@ class AutotunePlugin @Inject constructor(
|
||||||
autotuneFS.exportEntries(autotuneIob) //<=> ns-entries.yyyymmdd.json files exported for results compare with oref0 autotune on virtual machine
|
autotuneFS.exportEntries(autotuneIob) //<=> ns-entries.yyyymmdd.json files exported for results compare with oref0 autotune on virtual machine
|
||||||
autotuneFS.exportTreatments(autotuneIob) //<=> ns-treatments.yyyymmdd.json files exported for results compare with oref0 autotune on virtual machine (include treatments ,tempBasal and extended
|
autotuneFS.exportTreatments(autotuneIob) //<=> ns-treatments.yyyymmdd.json files exported for results compare with oref0 autotune on virtual machine (include treatments ,tempBasal and extended
|
||||||
preppedGlucose = autotunePrep.categorize(it) //<=> autotune.yyyymmdd.json files exported for results compare with oref0 autotune on virtual machine
|
preppedGlucose = autotunePrep.categorize(it) //<=> autotune.yyyymmdd.json files exported for results compare with oref0 autotune on virtual machine
|
||||||
preppedGlucose?.let { preppedGlucose ->
|
preppedGlucose?.let { preppedGlucose -> //preppedGlucose and tunedProfile should never be null here
|
||||||
autotuneFS.exportPreppedGlucose(preppedGlucose)
|
autotuneFS.exportPreppedGlucose(preppedGlucose)
|
||||||
tunedProfile = autotuneCore.tuneAllTheThings(preppedGlucose, it, pumpProfile).also { tunedProfile ->
|
tunedProfile = autotuneCore.tuneAllTheThings(preppedGlucose, it, pumpProfile).also { tunedProfile ->
|
||||||
autotuneFS.exportTunedProfile(tunedProfile) //<=> newprofile.yyyymmdd.json files exported for results compare with oref0 autotune on virtual machine
|
autotuneFS.exportTunedProfile(tunedProfile) //<=> newprofile.yyyymmdd.json files exported for results compare with oref0 autotune on virtual machine
|
||||||
if (i < daysBack - 1) {
|
if (currentCalcDay < calcDays) {
|
||||||
log("Partial result for day ${i + 1}".trimIndent())
|
log("Partial result for day ${i + 1}".trimIndent())
|
||||||
result = rh.gs(info.nightscout.core.ui.R.string.autotune_partial_result, i + 1, daysBack)
|
result = rh.gs(info.nightscout.core.ui.R.string.autotune_partial_result, currentCalcDay, calcDays)
|
||||||
rxBus.send(EventAutotuneUpdateGui())
|
rxBus.send(EventAutotuneUpdateGui())
|
||||||
}
|
}
|
||||||
logResult = showResults(tunedProfile, pumpProfile)
|
logResult = showResults(tunedProfile, pumpProfile)
|
||||||
|
@ -185,6 +214,7 @@ class AutotunePlugin @Inject constructor(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
result = rh.gs(info.nightscout.core.ui.R.string.autotune_result, dateUtil.dateAndTimeString(lastRun))
|
result = rh.gs(info.nightscout.core.ui.R.string.autotune_result, dateUtil.dateAndTimeString(lastRun))
|
||||||
if (!detailedLog)
|
if (!detailedLog)
|
||||||
autotuneFS.exportLog(lastRun)
|
autotuneFS.exportLog(lastRun)
|
||||||
|
@ -361,6 +391,9 @@ class AutotunePlugin @Inject constructor(
|
||||||
json.put("missingDays_$i", atProfile.basalUnTuned[i])
|
json.put("missingDays_$i", atProfile.basalUnTuned[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (i in days.weekdays.indices) {
|
||||||
|
json.put(InputWeekDay.DayOfWeek.values()[i].name, days.weekdays[i])
|
||||||
|
}
|
||||||
json.put("result", result)
|
json.put("result", result)
|
||||||
json.put("updateButtonVisibility", updateButtonVisibility)
|
json.put("updateButtonVisibility", updateButtonVisibility)
|
||||||
sp.putString(info.nightscout.core.utils.R.string.key_autotune_last_run, json.toString())
|
sp.putString(info.nightscout.core.utils.R.string.key_autotune_last_run, json.toString())
|
||||||
|
@ -395,6 +428,8 @@ class AutotunePlugin @Inject constructor(
|
||||||
atProfile.basalUnTuned[i] = JsonHelper.safeGetInt(json, "missingDays_$i")
|
atProfile.basalUnTuned[i] = JsonHelper.safeGetInt(json, "missingDays_$i")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (i in days.weekdays.indices)
|
||||||
|
days.weekdays[i] = JsonHelper.safeGetBoolean(json, InputWeekDay.DayOfWeek.values()[i].name,true)
|
||||||
result = JsonHelper.safeGetString(json, "result", "")
|
result = JsonHelper.safeGetString(json, "result", "")
|
||||||
updateButtonVisibility = JsonHelper.safeGetInt(json, "updateButtonVisibility")
|
updateButtonVisibility = JsonHelper.safeGetInt(json, "updateButtonVisibility")
|
||||||
lastRunSuccess = true
|
lastRunSuccess = true
|
||||||
|
@ -403,6 +438,18 @@ class AutotunePlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun calcDays(daysBack:Int): Int {
|
||||||
|
var endTime = MidnightTime.calc(dateUtil.now()) + autotuneStartHour * 60 * 60 * 1000L
|
||||||
|
if (endTime > dateUtil.now()) endTime -= T.days(1).msecs() // Check if 4 AM is before now
|
||||||
|
val starttime = endTime - daysBack * T.days(1).msecs()
|
||||||
|
var result = 0
|
||||||
|
for (i in 0 until daysBack) {
|
||||||
|
if (days.isSet(starttime + i * T.days(1).msecs()))
|
||||||
|
result++
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
private fun log(message: String) {
|
private fun log(message: String) {
|
||||||
atLog("[Plugin] $message")
|
atLog("[Plugin] $message")
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal|center_vertical"
|
android:layout_gravity="center_horizontal|center_vertical"
|
||||||
android:layout_weight="2"
|
android:layout_weight="3.5"
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
android:paddingStart="5dp"
|
android:paddingStart="5dp"
|
||||||
android:paddingEnd="5dp"
|
android:paddingEnd="5dp"
|
||||||
|
@ -73,25 +73,64 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal|center_vertical"
|
android:layout_gravity="center_horizontal|center_vertical"
|
||||||
android:layout_weight="2"
|
android:layout_weight="3.5"
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
android:paddingStart="5dp"
|
android:paddingStart="5dp"
|
||||||
android:paddingEnd="5dp"
|
android:paddingEnd="5dp"
|
||||||
android:text="@string/autotune_tune_days"
|
android:text="@string/autotune_tune_days"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<info.nightscout.core.ui.elements.NumberPicker
|
<info.nightscout.core.ui.elements.NumberPicker
|
||||||
android:id="@+id/tune_days"
|
android:id="@+id/tune_days"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:layout_marginBottom="2dp"
|
android:layout_marginBottom="2dp"
|
||||||
android:layout_weight="1"
|
|
||||||
android:paddingStart="5dp"
|
android:paddingStart="5dp"
|
||||||
android:paddingEnd="5dp"
|
android:paddingEnd="5dp"
|
||||||
app:customContentDescription="@string/duration_label" />
|
app:customContentDescription="@string/duration_label" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/calc_days"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="start"
|
||||||
|
android:paddingStart="5dp"
|
||||||
|
android:paddingEnd="5dp"
|
||||||
|
android:text="(5)"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:visibility="visible" />
|
||||||
|
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/show_week_days_checkbox"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:paddingStart="5dp"
|
||||||
|
android:paddingEnd="5dp"
|
||||||
|
android:checked="false"
|
||||||
|
android:drawableEnd="@drawable/ic_visibility" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/select_week_days"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import androidx.annotation.DrawableRes
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.automation.elements.InputDuration
|
import info.nightscout.automation.elements.InputDuration
|
||||||
import info.nightscout.automation.elements.InputProfileName
|
import info.nightscout.automation.elements.InputProfileName
|
||||||
|
import info.nightscout.automation.elements.InputWeekDay
|
||||||
import info.nightscout.automation.elements.LabelWithElement
|
import info.nightscout.automation.elements.LabelWithElement
|
||||||
import info.nightscout.automation.elements.LayoutBuilder
|
import info.nightscout.automation.elements.LayoutBuilder
|
||||||
import info.nightscout.interfaces.autotune.Autotune
|
import info.nightscout.interfaces.autotune.Autotune
|
||||||
|
@ -30,6 +31,7 @@ class ActionRunAutotune(injector: HasAndroidInjector) : Action(injector) {
|
||||||
var defaultValue = 0
|
var defaultValue = 0
|
||||||
private var inputProfileName = InputProfileName(rh, activePlugin, "", true)
|
private var inputProfileName = InputProfileName(rh, activePlugin, "", true)
|
||||||
private var daysBack = InputDuration(0, InputDuration.TimeUnit.DAYS)
|
private var daysBack = InputDuration(0, InputDuration.TimeUnit.DAYS)
|
||||||
|
private val days = InputWeekDay().also { it.setAll(true) }
|
||||||
|
|
||||||
override fun friendlyName(): Int = info.nightscout.core.ui.R.string.autotune_run
|
override fun friendlyName(): Int = info.nightscout.core.ui.R.string.autotune_run
|
||||||
override fun shortDescription(): String = resourceHelper.gs(info.nightscout.core.ui.R.string.autotune_profile_name, inputProfileName.value)
|
override fun shortDescription(): String = resourceHelper.gs(info.nightscout.core.ui.R.string.autotune_profile_name, inputProfileName.value)
|
||||||
|
@ -42,7 +44,7 @@ class ActionRunAutotune(injector: HasAndroidInjector) : Action(injector) {
|
||||||
Thread {
|
Thread {
|
||||||
if (!autotunePlugin.calculationRunning) {
|
if (!autotunePlugin.calculationRunning) {
|
||||||
autotunePlugin.atLog("[Automation] Run Autotune $profileName, ${daysBack.value} days, Autoswitch $autoSwitch")
|
autotunePlugin.atLog("[Automation] Run Autotune $profileName, ${daysBack.value} days, Autoswitch $autoSwitch")
|
||||||
autotunePlugin.aapsAutotune(daysBack.value, autoSwitch, profileName)
|
autotunePlugin.aapsAutotune(daysBack.value, autoSwitch, profileName, days.weekdays)
|
||||||
if (!autotunePlugin.lastRunSuccess) {
|
if (!autotunePlugin.lastRunSuccess) {
|
||||||
message = info.nightscout.core.ui.R.string.autotune_run_with_error
|
message = info.nightscout.core.ui.R.string.autotune_run_with_error
|
||||||
aapsLogger.error(LTag.AUTOMATION, "Error during Autotune Run")
|
aapsLogger.error(LTag.AUTOMATION, "Error during Autotune Run")
|
||||||
|
@ -64,6 +66,7 @@ class ActionRunAutotune(injector: HasAndroidInjector) : Action(injector) {
|
||||||
LayoutBuilder()
|
LayoutBuilder()
|
||||||
.add(LabelWithElement(rh, rh.gs(info.nightscout.core.ui.R.string.autotune_select_profile), "", inputProfileName))
|
.add(LabelWithElement(rh, rh.gs(info.nightscout.core.ui.R.string.autotune_select_profile), "", inputProfileName))
|
||||||
.add(LabelWithElement(rh, rh.gs(info.nightscout.core.ui.R.string.autotune_tune_days), "", daysBack))
|
.add(LabelWithElement(rh, rh.gs(info.nightscout.core.ui.R.string.autotune_tune_days), "", daysBack))
|
||||||
|
.add(days)
|
||||||
.build(root)
|
.build(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +76,9 @@ class ActionRunAutotune(injector: HasAndroidInjector) : Action(injector) {
|
||||||
val data = JSONObject()
|
val data = JSONObject()
|
||||||
.put("profileToTune", inputProfileName.value)
|
.put("profileToTune", inputProfileName.value)
|
||||||
.put("tunedays", daysBack.value)
|
.put("tunedays", daysBack.value)
|
||||||
|
for (i in days.weekdays.indices) {
|
||||||
|
data.put(InputWeekDay.DayOfWeek.values()[i].name, days.weekdays[i])
|
||||||
|
}
|
||||||
return JSONObject()
|
return JSONObject()
|
||||||
.put("type", this.javaClass.simpleName)
|
.put("type", this.javaClass.simpleName)
|
||||||
.put("data", data)
|
.put("data", data)
|
||||||
|
@ -81,6 +87,8 @@ class ActionRunAutotune(injector: HasAndroidInjector) : Action(injector) {
|
||||||
|
|
||||||
override fun fromJSON(data: String): Action {
|
override fun fromJSON(data: String): Action {
|
||||||
val o = JSONObject(data)
|
val o = JSONObject(data)
|
||||||
|
for (i in days.weekdays.indices)
|
||||||
|
days.weekdays[i] = JsonHelper.safeGetBoolean(o, InputWeekDay.DayOfWeek.values()[i].name,true)
|
||||||
inputProfileName.value = JsonHelper.safeGetString(o, "profileToTune", "")
|
inputProfileName.value = JsonHelper.safeGetString(o, "profileToTune", "")
|
||||||
defaultValue = JsonHelper.safeGetInt(o, "tunedays")
|
defaultValue = JsonHelper.safeGetInt(o, "tunedays")
|
||||||
if (defaultValue == 0)
|
if (defaultValue == 0)
|
||||||
|
|
|
@ -5,6 +5,8 @@ import androidx.annotation.StringRes
|
||||||
import info.nightscout.automation.ui.WeekdayPicker
|
import info.nightscout.automation.ui.WeekdayPicker
|
||||||
import info.nightscout.automation.R
|
import info.nightscout.automation.R
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
import java.util.Date
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class InputWeekDay : Element() {
|
class InputWeekDay : Element() {
|
||||||
|
|
||||||
|
@ -49,7 +51,7 @@ class InputWeekDay : Element() {
|
||||||
}
|
}
|
||||||
|
|
||||||
val weekdays = BooleanArray(DayOfWeek.values().size)
|
val weekdays = BooleanArray(DayOfWeek.values().size)
|
||||||
|
var view: WeekdayPicker? = null
|
||||||
init {
|
init {
|
||||||
for (day in DayOfWeek.values()) set(day, false)
|
for (day in DayOfWeek.values()) set(day, false)
|
||||||
}
|
}
|
||||||
|
@ -65,6 +67,11 @@ class InputWeekDay : Element() {
|
||||||
|
|
||||||
fun isSet(day: DayOfWeek): Boolean = weekdays[day.ordinal]
|
fun isSet(day: DayOfWeek): Boolean = weekdays[day.ordinal]
|
||||||
|
|
||||||
|
fun isSet(timestamp: Long): Boolean {
|
||||||
|
val scheduledDayOfWeek = Calendar.getInstance().also { it.time = Date(timestamp) }
|
||||||
|
return isSet(DayOfWeek.fromCalendarInt(scheduledDayOfWeek[Calendar.DAY_OF_WEEK]))
|
||||||
|
}
|
||||||
|
|
||||||
fun getSelectedDays(): List<Int> {
|
fun getSelectedDays(): List<Int> {
|
||||||
val selectedDays: MutableList<Int> = ArrayList()
|
val selectedDays: MutableList<Int> = ArrayList()
|
||||||
for (i in weekdays.indices) {
|
for (i in weekdays.indices) {
|
||||||
|
@ -76,11 +83,12 @@ class InputWeekDay : Element() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addToLayout(root: LinearLayout) {
|
override fun addToLayout(root: LinearLayout) {
|
||||||
root.addView(
|
view = WeekdayPicker(root.context).apply {
|
||||||
WeekdayPicker(root.context).apply {
|
|
||||||
setSelectedDays(getSelectedDays())
|
setSelectedDays(getSelectedDays())
|
||||||
setOnWeekdaysChangeListener { i: Int, selected: Boolean -> set(DayOfWeek.fromCalendarInt(i), selected) }
|
setOnWeekdaysChangeListener { i: Int, selected: Boolean -> set(DayOfWeek.fromCalendarInt(i), selected) }
|
||||||
}
|
}
|
||||||
|
root.addView(
|
||||||
|
view
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue