Merge branch 'dev' of https://github.com/nightscout/AndroidAPS into dev
This commit is contained in:
commit
a00dea8c0d
77 changed files with 1124 additions and 1075 deletions
|
@ -1,5 +1,6 @@
|
||||||
package info.nightscout.androidaps.activities
|
package info.nightscout.androidaps.activities
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
|
@ -168,7 +169,8 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
||||||
|
|
||||||
binding.basalpctfromtdd.setParams(32.0, 32.0, 37.0, 1.0, DecimalFormat("0"), false, null)
|
binding.basalpctfromtdd.setParams(32.0, 32.0, 37.0, 1.0, DecimalFormat("0"), false, null)
|
||||||
|
|
||||||
binding.tdds.text = getString(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress);
|
@SuppressLint("SetTextI18n")
|
||||||
|
binding.tdds.text = getString(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress)
|
||||||
Thread {
|
Thread {
|
||||||
val tdds = tddCalculator.stats()
|
val tdds = tddCalculator.stats()
|
||||||
runOnUiThread { binding.tdds.text = tdds }
|
runOnUiThread { binding.tdds.text = tdds }
|
||||||
|
|
|
@ -76,7 +76,7 @@ class CalibrationDialog : DialogFragmentWithDate() {
|
||||||
val units = profileFunction.getUnits()
|
val units = profileFunction.getUnits()
|
||||||
val unitLabel = if (units == GlucoseUnit.MMOL) rh.gs(R.string.mmol) else rh.gs(R.string.mgdl)
|
val unitLabel = if (units == GlucoseUnit.MMOL) rh.gs(R.string.mmol) else rh.gs(R.string.mgdl)
|
||||||
val actions: LinkedList<String?> = LinkedList()
|
val actions: LinkedList<String?> = LinkedList()
|
||||||
val bg = binding.bg.value ?: return false
|
val bg = binding.bg.value
|
||||||
actions.add(rh.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(profileFunction, bg) + " " + unitLabel)
|
actions.add(rh.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(profileFunction, bg) + " " + unitLabel)
|
||||||
if (bg > 0) {
|
if (bg > 0) {
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
|
|
|
@ -189,7 +189,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
||||||
|
|
||||||
override fun submit(): Boolean {
|
override fun submit(): Boolean {
|
||||||
if (_binding == null) return false
|
if (_binding == null) return false
|
||||||
val carbs = binding.carbs.value?.toInt() ?: return false
|
val carbs = binding.carbs.value.toInt()
|
||||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
|
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
|
||||||
val units = profileFunction.getUnits()
|
val units = profileFunction.getUnits()
|
||||||
val activityTTDuration = defaultValueHelper.determineActivityTTDuration()
|
val activityTTDuration = defaultValueHelper.determineActivityTTDuration()
|
||||||
|
|
|
@ -79,7 +79,7 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
|
||||||
|
|
||||||
override fun submit(): Boolean {
|
override fun submit(): Boolean {
|
||||||
if (_binding == null) return false
|
if (_binding == null) return false
|
||||||
val insulin = SafeParse.stringToDouble(binding.insulin.text ?: return false)
|
val insulin = SafeParse.stringToDouble(binding.insulin.text)
|
||||||
val durationInMinutes = binding.duration.value.toInt()
|
val durationInMinutes = binding.duration.value.toInt()
|
||||||
val actions: LinkedList<String> = LinkedList()
|
val actions: LinkedList<String> = LinkedList()
|
||||||
val insulinAfterConstraint = constraintChecker.applyExtendedBolusConstraints(Constraint(insulin)).value()
|
val insulinAfterConstraint = constraintChecker.applyExtendedBolusConstraints(Constraint(insulin)).value()
|
||||||
|
|
|
@ -106,7 +106,7 @@ class FillDialog : DialogFragmentWithDate() {
|
||||||
|
|
||||||
override fun submit(): Boolean {
|
override fun submit(): Boolean {
|
||||||
if (_binding == null) return false
|
if (_binding == null) return false
|
||||||
val insulin = SafeParse.stringToDouble(binding.fillInsulinamount.text ?: return false)
|
val insulin = SafeParse.stringToDouble(binding.fillInsulinamount.text)
|
||||||
val actions: LinkedList<String?> = LinkedList()
|
val actions: LinkedList<String?> = LinkedList()
|
||||||
|
|
||||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
|
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
|
||||||
|
|
|
@ -149,7 +149,7 @@ class InsulinDialog : DialogFragmentWithDate() {
|
||||||
override fun submit(): Boolean {
|
override fun submit(): Boolean {
|
||||||
if (_binding == null) return false
|
if (_binding == null) return false
|
||||||
val pumpDescription = activePlugin.activePump.pumpDescription
|
val pumpDescription = activePlugin.activePump.pumpDescription
|
||||||
val insulin = SafeParse.stringToDouble(binding.amount.text ?: return false)
|
val insulin = SafeParse.stringToDouble(binding.amount.text)
|
||||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
|
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
|
||||||
val actions: LinkedList<String?> = LinkedList()
|
val actions: LinkedList<String?> = LinkedList()
|
||||||
val units = profileFunction.getUnits()
|
val units = profileFunction.getUnits()
|
||||||
|
|
|
@ -162,7 +162,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
||||||
?: return false
|
?: return false
|
||||||
|
|
||||||
val actions: LinkedList<String> = LinkedList()
|
val actions: LinkedList<String> = LinkedList()
|
||||||
val duration = binding.duration.value?.toInt() ?: return false
|
val duration = binding.duration.value.toInt()
|
||||||
if (duration > 0L)
|
if (duration > 0L)
|
||||||
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, duration))
|
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, duration))
|
||||||
val profileName = binding.profile.selectedItem.toString()
|
val profileName = binding.profile.selectedItem.toString()
|
||||||
|
|
|
@ -47,8 +47,8 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
||||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||||
super.onSaveInstanceState(savedInstanceState)
|
super.onSaveInstanceState(savedInstanceState)
|
||||||
savedInstanceState.putDouble("duration", binding.duration.value)
|
savedInstanceState.putDouble("duration", binding.duration.value)
|
||||||
savedInstanceState.putDouble("basalpercentinput", binding.basalpercentinput.value)
|
savedInstanceState.putDouble("basalPercentInput", binding.basalPercentInput.value)
|
||||||
savedInstanceState.putDouble("basalabsoluteinput", binding.basalabsoluteinput.value)
|
savedInstanceState.putDouble("basalAbsoluteInput", binding.basalAbsoluteInput.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
@ -67,10 +67,10 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
||||||
val maxTempPercent = pumpDescription.maxTempPercent.toDouble()
|
val maxTempPercent = pumpDescription.maxTempPercent.toDouble()
|
||||||
val tempPercentStep = pumpDescription.tempPercentStep.toDouble()
|
val tempPercentStep = pumpDescription.tempPercentStep.toDouble()
|
||||||
|
|
||||||
binding.basalpercentinput.setParams(savedInstanceState?.getDouble("basalpercentinput")
|
binding.basalPercentInput.setParams(savedInstanceState?.getDouble("basalPercentInput")
|
||||||
?: 100.0, 0.0, maxTempPercent, tempPercentStep, DecimalFormat("0"), true, binding.okcancel.ok)
|
?: 100.0, 0.0, maxTempPercent, tempPercentStep, DecimalFormat("0"), true, binding.okcancel.ok)
|
||||||
|
|
||||||
binding.basalabsoluteinput.setParams(savedInstanceState?.getDouble("basalabsoluteinput")
|
binding.basalAbsoluteInput.setParams(savedInstanceState?.getDouble("basalAbsoluteInput")
|
||||||
?: profile.getBasal(), 0.0, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, DecimalFormat("0.00"), true, binding.okcancel.ok)
|
?: profile.getBasal(), 0.0, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, DecimalFormat("0.00"), true, binding.okcancel.ok)
|
||||||
|
|
||||||
val tempDurationStep = pumpDescription.tempDurationStep.toDouble()
|
val tempDurationStep = pumpDescription.tempDurationStep.toDouble()
|
||||||
|
@ -97,17 +97,17 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
||||||
if (_binding == null) return false
|
if (_binding == null) return false
|
||||||
var percent = 0
|
var percent = 0
|
||||||
var absolute = 0.0
|
var absolute = 0.0
|
||||||
val durationInMinutes = binding.duration.value?.toInt() ?: return false
|
val durationInMinutes = binding.duration.value.toInt()
|
||||||
val profile = profileFunction.getProfile() ?: return false
|
val profile = profileFunction.getProfile() ?: return false
|
||||||
val actions: LinkedList<String> = LinkedList()
|
val actions: LinkedList<String> = LinkedList()
|
||||||
if (isPercentPump) {
|
if (isPercentPump) {
|
||||||
val basalPercentInput = SafeParse.stringToInt(binding.basalpercentinput.text)
|
val basalPercentInput = SafeParse.stringToInt(binding.basalPercentInput.text)
|
||||||
percent = constraintChecker.applyBasalPercentConstraints(Constraint(basalPercentInput), profile).value()
|
percent = constraintChecker.applyBasalPercentConstraints(Constraint(basalPercentInput), profile).value()
|
||||||
actions.add(rh.gs(R.string.tempbasal_label) + ": $percent%")
|
actions.add(rh.gs(R.string.tempbasal_label) + ": $percent%")
|
||||||
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, durationInMinutes))
|
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, durationInMinutes))
|
||||||
if (percent != basalPercentInput) actions.add(rh.gs(R.string.constraintapllied))
|
if (percent != basalPercentInput) actions.add(rh.gs(R.string.constraintapllied))
|
||||||
} else {
|
} else {
|
||||||
val basalAbsoluteInput = SafeParse.stringToDouble(binding.basalabsoluteinput.text)
|
val basalAbsoluteInput = SafeParse.stringToDouble(binding.basalAbsoluteInput.text)
|
||||||
absolute = constraintChecker.applyBasalConstraints(Constraint(basalAbsoluteInput), profile).value()
|
absolute = constraintChecker.applyBasalConstraints(Constraint(basalAbsoluteInput), profile).value()
|
||||||
actions.add(rh.gs(R.string.tempbasal_label) + ": " + rh.gs(R.string.pump_basebasalrate, absolute))
|
actions.add(rh.gs(R.string.tempbasal_label) + ": " + rh.gs(R.string.pump_basebasalrate, absolute))
|
||||||
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, durationInMinutes))
|
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, durationInMinutes))
|
||||||
|
|
|
@ -115,7 +115,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
||||||
override fun submit(): Boolean {
|
override fun submit(): Boolean {
|
||||||
if (_binding == null) return false
|
if (_binding == null) return false
|
||||||
val pumpDescription = activePlugin.activePump.pumpDescription
|
val pumpDescription = activePlugin.activePump.pumpDescription
|
||||||
val insulin = SafeParse.stringToDouble(binding.insulin.text ?: return false)
|
val insulin = SafeParse.stringToDouble(binding.insulin.text)
|
||||||
val carbs = SafeParse.stringToInt(binding.carbs.text)
|
val carbs = SafeParse.stringToInt(binding.carbs.text)
|
||||||
val recordOnlyChecked = binding.recordOnly.isChecked
|
val recordOnlyChecked = binding.recordOnly.isChecked
|
||||||
val actions: LinkedList<String?> = LinkedList()
|
val actions: LinkedList<String?> = LinkedList()
|
||||||
|
@ -139,7 +139,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
||||||
OKDialog.showConfirmation(activity, rh.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
OKDialog.showConfirmation(activity, rh.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||||
val action = when {
|
val action = when {
|
||||||
insulinAfterConstraints.equals(0.0) -> Action.CARBS
|
insulinAfterConstraints.equals(0.0) -> Action.CARBS
|
||||||
carbsAfterConstraints.equals(0) -> Action.BOLUS
|
carbsAfterConstraints == 0 -> Action.BOLUS
|
||||||
else -> Action.TREATMENT
|
else -> Action.TREATMENT
|
||||||
}
|
}
|
||||||
val detailedBolusInfo = DetailedBolusInfo()
|
val detailedBolusInfo = DetailedBolusInfo()
|
||||||
|
|
|
@ -258,10 +258,7 @@ class WizardDialog : DaggerDialogFragment() {
|
||||||
|
|
||||||
val units = profileFunction.getUnits()
|
val units = profileFunction.getUnits()
|
||||||
binding.bgunits.text = units.asText
|
binding.bgunits.text = units.asText
|
||||||
if (units == GlucoseUnit.MGDL)
|
binding.bgInput.step = if (units == GlucoseUnit.MGDL) 1.0 else 0.1
|
||||||
binding.bgInput.setStep(1.0)
|
|
||||||
else
|
|
||||||
binding.bgInput.setStep(0.1)
|
|
||||||
|
|
||||||
// Set BG if not old
|
// Set BG if not old
|
||||||
binding.bgInput.value = iobCobCalculator.ads.actualBg()?.valueToUnits(units) ?: 0.0
|
binding.bgInput.value = iobCobCalculator.ads.actualBg()?.valueToUnits(units) ?: 0.0
|
||||||
|
|
|
@ -109,7 +109,7 @@ class ObjectivesExamDialog : DaggerDialogFragment() {
|
||||||
task.answered = result
|
task.answered = result
|
||||||
if (!result) {
|
if (!result) {
|
||||||
task.disabledTo = dateUtil.now() + T.hours(1).msecs()
|
task.disabledTo = dateUtil.now() + T.hours(1).msecs()
|
||||||
ToastUtils.showToastInUiThread(context, R.string.wronganswer)
|
context?.let { it1 -> ToastUtils.showToastInUiThread(it1, R.string.wronganswer) }
|
||||||
} else task.disabledTo = 0
|
} else task.disabledTo = 0
|
||||||
updateGui()
|
updateGui()
|
||||||
rxBus.send(EventObjectivesUpdateGui())
|
rxBus.send(EventObjectivesUpdateGui())
|
||||||
|
|
|
@ -646,9 +646,9 @@ class OverviewData @Inject constructor(
|
||||||
maxCobValueFound = max(maxCobValueFound, cob.toDouble())
|
maxCobValueFound = max(maxCobValueFound, cob.toDouble())
|
||||||
lastCob = cob
|
lastCob = cob
|
||||||
}
|
}
|
||||||
if (autosensData.failoverToMinAbsorbtionRate) {
|
if (autosensData.failOverToMinAbsorptionRate) {
|
||||||
autosensData.setScale(cobScale)
|
autosensData.scale = cobScale
|
||||||
autosensData.setChartTime(time)
|
autosensData.chartTime = time
|
||||||
minFailOverActiveList.add(autosensData)
|
minFailOverActiveList.add(autosensData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,18 +20,21 @@ class BolusDataPoint @Inject constructor(
|
||||||
|
|
||||||
override fun getX(): Double = data.timestamp.toDouble()
|
override fun getX(): Double = data.timestamp.toDouble()
|
||||||
override fun getY(): Double = if (data.type == Bolus.Type.SMB) defaultValueHelper.determineLowLine() else yValue
|
override fun getY(): Double = if (data.type == Bolus.Type.SMB) defaultValueHelper.determineLowLine() else yValue
|
||||||
override fun getLabel(): String = DecimalFormatter.toPumpSupportedBolus(data.amount, activePlugin.activePump, rh)
|
override val label
|
||||||
override fun getDuration(): Long = 0
|
get() = DecimalFormatter.toPumpSupportedBolus(data.amount, activePlugin.activePump, rh)
|
||||||
override fun getSize(): Float = 2f
|
override val duration = 0L
|
||||||
|
override val size = 2f
|
||||||
|
|
||||||
override fun getShape(): PointsWithLabelGraphSeries.Shape =
|
override val shape
|
||||||
if (data.type == Bolus.Type.SMB) PointsWithLabelGraphSeries.Shape.SMB
|
get() = if (data.type == Bolus.Type.SMB) PointsWithLabelGraphSeries.Shape.SMB else PointsWithLabelGraphSeries.Shape.BOLUS
|
||||||
else PointsWithLabelGraphSeries.Shape.BOLUS
|
|
||||||
|
|
||||||
override fun getColor(): Int =
|
override val color
|
||||||
if (data.type == Bolus.Type.SMB) rh.gc(R.color.tempbasal)
|
get() =
|
||||||
else if (data.isValid) Color.CYAN
|
when {
|
||||||
else rh.gc(android.R.color.holo_red_light)
|
data.type == Bolus.Type.SMB -> rh.gc(R.color.tempbasal)
|
||||||
|
data.isValid -> Color.CYAN
|
||||||
|
else -> rh.gc(android.R.color.holo_red_light)
|
||||||
|
}
|
||||||
|
|
||||||
override fun setY(y: Double) {
|
override fun setY(y: Double) {
|
||||||
yValue = y
|
yValue = y
|
||||||
|
|
|
@ -14,15 +14,11 @@ class CarbsDataPoint @Inject constructor(
|
||||||
|
|
||||||
override fun getX(): Double = data.timestamp.toDouble()
|
override fun getX(): Double = data.timestamp.toDouble()
|
||||||
override fun getY(): Double = yValue
|
override fun getY(): Double = yValue
|
||||||
override fun getLabel(): String = rh.gs(R.string.format_carbs, data.amount.toInt())
|
override val label get() = rh.gs(R.string.format_carbs, data.amount.toInt())
|
||||||
override fun getDuration(): Long = 0
|
override val duration = 0L
|
||||||
override fun getSize(): Float = 2f
|
override val size = 2f
|
||||||
|
override val shape = PointsWithLabelGraphSeries.Shape.CARBS
|
||||||
override fun getShape(): PointsWithLabelGraphSeries.Shape = PointsWithLabelGraphSeries.Shape.CARBS
|
override val color get() = if (data.isValid) rh.gc(R.color.carbs) else rh.gc(android.R.color.holo_red_light)
|
||||||
|
|
||||||
override fun getColor(): Int =
|
|
||||||
if (data.isValid) rh.gc(R.color.carbs)
|
|
||||||
else rh.gc(android.R.color.holo_red_light)
|
|
||||||
|
|
||||||
override fun setY(y: Double) {
|
override fun setY(y: Double) {
|
||||||
yValue = y
|
yValue = y
|
||||||
|
|
|
@ -17,9 +17,9 @@ class EffectiveProfileSwitchDataPoint @Inject constructor(
|
||||||
yValue = y
|
yValue = y
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLabel(): String = data.originalCustomizedName
|
override val label get() = data.originalCustomizedName
|
||||||
override fun getDuration(): Long = 0
|
override val duration = 0L
|
||||||
override fun getShape(): PointsWithLabelGraphSeries.Shape = PointsWithLabelGraphSeries.Shape.PROFILE
|
override val shape = PointsWithLabelGraphSeries.Shape.PROFILE
|
||||||
override fun getSize(): Float = 10f
|
override val size = 10f
|
||||||
override fun getColor(): Int = Color.CYAN
|
override val color = Color.CYAN
|
||||||
}
|
}
|
|
@ -13,11 +13,11 @@ class ExtendedBolusDataPoint @Inject constructor(
|
||||||
|
|
||||||
override fun getX(): Double = data.timestamp.toDouble()
|
override fun getX(): Double = data.timestamp.toDouble()
|
||||||
override fun getY(): Double = yValue
|
override fun getY(): Double = yValue
|
||||||
override fun getLabel(): String = data.toStringTotal()
|
override val label get() = data.toStringTotal()
|
||||||
override fun getDuration(): Long = data.duration
|
override val duration get() = data.duration
|
||||||
override fun getSize(): Float = 10f
|
override val size = 10f
|
||||||
override fun getShape(): PointsWithLabelGraphSeries.Shape = PointsWithLabelGraphSeries.Shape.EXTENDEDBOLUS
|
override val shape = PointsWithLabelGraphSeries.Shape.EXTENDEDBOLUS
|
||||||
override fun getColor(): Int = Color.CYAN
|
override val color = Color.CYAN
|
||||||
|
|
||||||
override fun setY(y: Double) {
|
override fun setY(y: Double) {
|
||||||
yValue = y
|
yValue = y
|
||||||
|
|
|
@ -19,44 +19,36 @@ class GlucoseValueDataPoint @Inject constructor(
|
||||||
fun valueToUnits(units: GlucoseUnit): Double =
|
fun valueToUnits(units: GlucoseUnit): Double =
|
||||||
if (units == GlucoseUnit.MGDL) data.value else data.value * Constants.MGDL_TO_MMOLL
|
if (units == GlucoseUnit.MGDL) data.value else data.value * Constants.MGDL_TO_MMOLL
|
||||||
|
|
||||||
override fun getX(): Double {
|
override fun getX(): Double = data.timestamp.toDouble()
|
||||||
return data.timestamp.toDouble()
|
override fun getY(): Double = valueToUnits(profileFunction.getUnits())
|
||||||
}
|
|
||||||
|
|
||||||
override fun getY(): Double {
|
|
||||||
return valueToUnits(profileFunction.getUnits())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setY(y: Double) {}
|
override fun setY(y: Double) {}
|
||||||
override fun getLabel(): String? = null
|
override val label: String? = null
|
||||||
override fun getDuration(): Long = 0
|
override val duration = 0L
|
||||||
override fun getShape(): PointsWithLabelGraphSeries.Shape =
|
override val shape get() = if (isPrediction) PointsWithLabelGraphSeries.Shape.PREDICTION else PointsWithLabelGraphSeries.Shape.BG
|
||||||
if (isPrediction) PointsWithLabelGraphSeries.Shape.PREDICTION
|
override val size = 1f
|
||||||
else PointsWithLabelGraphSeries.Shape.BG
|
override val color: Int
|
||||||
|
get() {
|
||||||
override fun getSize(): Float = 1f
|
val units = profileFunction.getUnits()
|
||||||
|
val lowLine = defaultValueHelper.determineLowLine()
|
||||||
override fun getColor(): Int {
|
val highLine = defaultValueHelper.determineHighLine()
|
||||||
val units = profileFunction.getUnits()
|
return when {
|
||||||
val lowLine = defaultValueHelper.determineLowLine()
|
isPrediction -> predictionColor
|
||||||
val highLine = defaultValueHelper.determineHighLine()
|
valueToUnits(units) < lowLine -> rh.gc(R.color.low)
|
||||||
return when {
|
valueToUnits(units) > highLine -> rh.gc(R.color.high)
|
||||||
isPrediction -> predictionColor
|
else -> rh.gc(R.color.inrange)
|
||||||
valueToUnits(units) < lowLine -> rh.gc(R.color.low)
|
}
|
||||||
valueToUnits(units) > highLine -> rh.gc(R.color.high)
|
|
||||||
else -> rh.gc(R.color.inrange)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val predictionColor: Int
|
val predictionColor: Int
|
||||||
get() {
|
get() {
|
||||||
return when (data.sourceSensor) {
|
return when (data.sourceSensor) {
|
||||||
GlucoseValue.SourceSensor.IOB_PREDICTION -> rh.gc(R.color.iob)
|
GlucoseValue.SourceSensor.IOB_PREDICTION -> rh.gc(R.color.iob)
|
||||||
GlucoseValue.SourceSensor.COB_PREDICTION -> rh.gc(R.color.cob)
|
GlucoseValue.SourceSensor.COB_PREDICTION -> rh.gc(R.color.cob)
|
||||||
GlucoseValue.SourceSensor.A_COB_PREDICTION -> -0x7f000001 and rh.gc(R.color.cob)
|
GlucoseValue.SourceSensor.A_COB_PREDICTION -> -0x7f000001 and rh.gc(R.color.cob)
|
||||||
GlucoseValue.SourceSensor.UAM_PREDICTION -> rh.gc(R.color.uam)
|
GlucoseValue.SourceSensor.UAM_PREDICTION -> rh.gc(R.color.uam)
|
||||||
GlucoseValue.SourceSensor.ZT_PREDICTION -> rh.gc(R.color.zt)
|
GlucoseValue.SourceSensor.ZT_PREDICTION -> rh.gc(R.color.zt)
|
||||||
else -> R.color.white
|
else -> R.color.white
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,9 @@ class InMemoryGlucoseValueDataPoint @Inject constructor(
|
||||||
override fun getX(): Double = data.timestamp.toDouble()
|
override fun getX(): Double = data.timestamp.toDouble()
|
||||||
override fun getY(): Double = valueToUnits(profileFunction.getUnits())
|
override fun getY(): Double = valueToUnits(profileFunction.getUnits())
|
||||||
override fun setY(y: Double) {}
|
override fun setY(y: Double) {}
|
||||||
override fun getLabel(): String? = null
|
override val label: String? = null
|
||||||
override fun getDuration(): Long = 0
|
override val duration = 0L
|
||||||
override fun getShape(): PointsWithLabelGraphSeries.Shape = PointsWithLabelGraphSeries.Shape.BUCKETED_BG
|
override val shape = PointsWithLabelGraphSeries.Shape.BUCKETED_BG
|
||||||
override fun getSize(): Float = 0.3f
|
override val size = 0.3f
|
||||||
override fun getColor(): Int = rh.gc(R.color.white)
|
override val color get() = rh.gc(R.color.white)
|
||||||
}
|
}
|
|
@ -19,9 +19,7 @@ class TherapyEventDataPoint @Inject constructor(
|
||||||
|
|
||||||
private var yValue = 0.0
|
private var yValue = 0.0
|
||||||
|
|
||||||
override fun getX(): Double {
|
override fun getX(): Double = data.timestamp.toDouble()
|
||||||
return data.timestamp.toDouble()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getY(): Double {
|
override fun getY(): Double {
|
||||||
val units = profileFunction.getUnits()
|
val units = profileFunction.getUnits()
|
||||||
|
@ -46,30 +44,29 @@ class TherapyEventDataPoint @Inject constructor(
|
||||||
yValue = y
|
yValue = y
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLabel(): String? =
|
override val label get() = if (data.note.isNullOrBlank().not()) data.note else translator.translate(data.type)
|
||||||
if (data.note.isNullOrBlank().not()) data.note
|
override val duration get() = data.duration
|
||||||
else translator.translate(data.type)
|
override val shape
|
||||||
|
get() =
|
||||||
|
when {
|
||||||
|
data.type == TherapyEvent.Type.NS_MBG -> PointsWithLabelGraphSeries.Shape.MBG
|
||||||
|
data.type == TherapyEvent.Type.FINGER_STICK_BG_VALUE -> PointsWithLabelGraphSeries.Shape.BGCHECK
|
||||||
|
data.type == TherapyEvent.Type.ANNOUNCEMENT -> PointsWithLabelGraphSeries.Shape.ANNOUNCEMENT
|
||||||
|
data.type == TherapyEvent.Type.APS_OFFLINE -> PointsWithLabelGraphSeries.Shape.OPENAPSOFFLINE
|
||||||
|
data.type == TherapyEvent.Type.EXERCISE -> PointsWithLabelGraphSeries.Shape.EXERCISE
|
||||||
|
duration > 0 -> PointsWithLabelGraphSeries.Shape.GENERALWITHDURATION
|
||||||
|
else -> PointsWithLabelGraphSeries.Shape.GENERAL
|
||||||
|
}
|
||||||
|
|
||||||
override fun getDuration(): Long = data.duration
|
override val size get() = if (rh.gb(R.bool.isTablet)) 12.0f else 10.0f
|
||||||
override fun getShape(): PointsWithLabelGraphSeries.Shape =
|
override val color
|
||||||
when {
|
get() =
|
||||||
data.type == TherapyEvent.Type.NS_MBG -> PointsWithLabelGraphSeries.Shape.MBG
|
when (data.type) {
|
||||||
data.type == TherapyEvent.Type.FINGER_STICK_BG_VALUE -> PointsWithLabelGraphSeries.Shape.BGCHECK
|
TherapyEvent.Type.ANNOUNCEMENT -> rh.gc(R.color.notificationAnnouncement)
|
||||||
data.type == TherapyEvent.Type.ANNOUNCEMENT -> PointsWithLabelGraphSeries.Shape.ANNOUNCEMENT
|
TherapyEvent.Type.NS_MBG -> Color.RED
|
||||||
data.type == TherapyEvent.Type.APS_OFFLINE -> PointsWithLabelGraphSeries.Shape.OPENAPSOFFLINE
|
TherapyEvent.Type.FINGER_STICK_BG_VALUE -> Color.RED
|
||||||
data.type == TherapyEvent.Type.EXERCISE -> PointsWithLabelGraphSeries.Shape.EXERCISE
|
TherapyEvent.Type.EXERCISE -> Color.BLUE
|
||||||
duration > 0 -> PointsWithLabelGraphSeries.Shape.GENERALWITHDURATION
|
TherapyEvent.Type.APS_OFFLINE -> Color.GRAY and -0x7f000001
|
||||||
else -> PointsWithLabelGraphSeries.Shape.GENERAL
|
else -> Color.GRAY
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSize(): Float = if (rh.gb(R.bool.isTablet)) 12.0f else 10.0f
|
|
||||||
override fun getColor(): Int =
|
|
||||||
when (data.type) {
|
|
||||||
TherapyEvent.Type.ANNOUNCEMENT -> rh.gc(R.color.notificationAnnouncement)
|
|
||||||
TherapyEvent.Type.NS_MBG -> Color.RED
|
|
||||||
TherapyEvent.Type.FINGER_STICK_BG_VALUE -> Color.RED
|
|
||||||
TherapyEvent.Type.EXERCISE -> Color.BLUE
|
|
||||||
TherapyEvent.Type.APS_OFFLINE -> Color.GRAY and -0x7f000001
|
|
||||||
else -> Color.GRAY
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -664,13 +664,15 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
IobTotal bolusIob = iobCobCalculator.calculateIobFromBolus().round();
|
IobTotal bolusIob = iobCobCalculator.calculateIobFromBolus().round();
|
||||||
IobTotal basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round();
|
IobTotal basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round();
|
||||||
|
|
||||||
iobSum = DecimalFormatter.INSTANCE.to2Decimal(bolusIob.iob + basalIob.basaliob);
|
iobSum = DecimalFormatter.INSTANCE.to2Decimal(bolusIob.getIob() + basalIob.getBasaliob());
|
||||||
iobDetail = "(" + DecimalFormatter.INSTANCE.to2Decimal(bolusIob.iob) + "|" + DecimalFormatter.INSTANCE.to2Decimal(basalIob.basaliob) + ")";
|
iobDetail =
|
||||||
|
"(" + DecimalFormatter.INSTANCE.to2Decimal(bolusIob.getIob()) + "|" + DecimalFormatter.INSTANCE.to2Decimal(basalIob.getBasaliob()) + ")";
|
||||||
cobString = iobCobCalculator.getCobInfo(false, "WatcherUpdaterService").generateCOBString();
|
cobString = iobCobCalculator.getCobInfo(false, "WatcherUpdaterService").generateCOBString();
|
||||||
currentBasal = generateBasalString();
|
currentBasal = generateBasalString();
|
||||||
|
|
||||||
//bgi
|
//bgi
|
||||||
double bgi = -(bolusIob.activity + basalIob.activity) * 5 * Profile.Companion.fromMgdlToUnits(profile.getIsfMgdl(), profileFunction.getUnits());
|
double bgi =
|
||||||
|
-(bolusIob.getActivity() + basalIob.getActivity()) * 5 * Profile.Companion.fromMgdlToUnits(profile.getIsfMgdl(), profileFunction.getUnits());
|
||||||
bgiString = "" + ((bgi >= 0) ? "+" : "") + DecimalFormatter.INSTANCE.to1Decimal(bgi);
|
bgiString = "" + ((bgi >= 0) ? "+" : "") + DecimalFormatter.INSTANCE.to1Decimal(bgi);
|
||||||
|
|
||||||
status = generateStatusString(profile, currentBasal, iobSum, iobDetail, bgiString);
|
status = generateStatusString(profile, currentBasal, iobSum, iobDetail, bgiString);
|
||||||
|
|
|
@ -209,12 +209,12 @@ class IobCobOref1Thread internal constructor(
|
||||||
// figure out how many carbs that represents
|
// figure out how many carbs that represents
|
||||||
// but always assume at least 3mg/dL/5m (default) absorption per active treatment
|
// but always assume at least 3mg/dL/5m (default) absorption per active treatment
|
||||||
val ci = max(deviation, totalMinCarbsImpact)
|
val ci = max(deviation, totalMinCarbsImpact)
|
||||||
if (ci != deviation) autosensData.failoverToMinAbsorbtionRate = true
|
if (ci != deviation) autosensData.failOverToMinAbsorptionRate = true
|
||||||
autosensData.absorbed = ci * profile.getIc(bgTime) / sens
|
autosensData.absorbed = ci * profile.getIc(bgTime) / sens
|
||||||
// and add that to the running total carbsAbsorbed
|
// and add that to the running total carbsAbsorbed
|
||||||
autosensData.cob = max(previous.cob - autosensData.absorbed, 0.0)
|
autosensData.cob = max(previous.cob - autosensData.absorbed, 0.0)
|
||||||
autosensData.mealCarbs = previous.mealCarbs
|
autosensData.mealCarbs = previous.mealCarbs
|
||||||
autosensData.substractAbosorbedCarbs()
|
autosensData.deductAbsorbedCarbs()
|
||||||
autosensData.usedMinCarbsImpact = totalMinCarbsImpact
|
autosensData.usedMinCarbsImpact = totalMinCarbsImpact
|
||||||
autosensData.absorbing = previous.absorbing
|
autosensData.absorbing = previous.absorbing
|
||||||
autosensData.mealStartCounter = previous.mealStartCounter
|
autosensData.mealStartCounter = previous.mealStartCounter
|
||||||
|
|
|
@ -10,7 +10,6 @@ import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.events.Event
|
import info.nightscout.androidaps.events.Event
|
||||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.PluginType
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
@ -218,11 +217,11 @@ class IobCobThread @Inject internal constructor(
|
||||||
// figure out how many carbs that represents
|
// figure out how many carbs that represents
|
||||||
// but always assume at least 3mg/dL/5m (default) absorption per active treatment
|
// but always assume at least 3mg/dL/5m (default) absorption per active treatment
|
||||||
val ci = max(deviation, totalMinCarbsImpact)
|
val ci = max(deviation, totalMinCarbsImpact)
|
||||||
if (ci != deviation) autosensData.failoverToMinAbsorbtionRate = true
|
if (ci != deviation) autosensData.failOverToMinAbsorptionRate = true
|
||||||
autosensData.absorbed = ci * profile.getIc(bgTime) / sens
|
autosensData.absorbed = ci * profile.getIc(bgTime) / sens
|
||||||
// and add that to the running total carbsAbsorbed
|
// and add that to the running total carbsAbsorbed
|
||||||
autosensData.cob = max(previous.cob - autosensData.absorbed, 0.0)
|
autosensData.cob = max(previous.cob - autosensData.absorbed, 0.0)
|
||||||
autosensData.substractAbosorbedCarbs()
|
autosensData.deductAbsorbedCarbs()
|
||||||
autosensData.usedMinCarbsImpact = totalMinCarbsImpact
|
autosensData.usedMinCarbsImpact = totalMinCarbsImpact
|
||||||
}
|
}
|
||||||
val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()
|
val isAAPSOrWeighted = sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()
|
||||||
|
|
|
@ -65,7 +65,7 @@ class LocalProfileFragment : DaggerFragment() {
|
||||||
override fun afterTextChanged(s: Editable) {}
|
override fun afterTextChanged(s: Editable) {}
|
||||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||||
localProfilePlugin.currentProfile()?.dia = SafeParse.stringToDouble(binding.dia.text.toString())
|
localProfilePlugin.currentProfile()?.dia = SafeParse.stringToDouble(binding.dia.text)
|
||||||
localProfilePlugin.currentProfile()?.name = binding.name.text.toString()
|
localProfilePlugin.currentProfile()?.name = binding.name.text.toString()
|
||||||
doEdit()
|
doEdit()
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
|
import info.nightscout.androidaps.interfaces.CommandQueue
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
@ -18,7 +19,7 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
|
||||||
class QueueThread internal constructor(
|
class QueueThread internal constructor(
|
||||||
private val queue: CommandQueueImplementation,
|
private val queue: CommandQueue,
|
||||||
context: Context,
|
context: Context,
|
||||||
private val aapsLogger: AAPSLogger,
|
private val aapsLogger: AAPSLogger,
|
||||||
private val rxBus: RxBus,
|
private val rxBus: RxBus,
|
||||||
|
|
|
@ -32,7 +32,7 @@ class CommandBolus(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String {
|
override fun status(): String {
|
||||||
return (if (detailedBolusInfo.insulin > 0) "BOLUS " + rh.gs(R.string.formatinsulinunits, detailedBolusInfo.insulin) else "") +
|
return (if (detailedBolusInfo.insulin > 0) rh.gs(R.string.bolus_u_min, detailedBolusInfo.insulin) else "") +
|
||||||
if (detailedBolusInfo.carbs > 0) "CARBS " + rh.gs(R.string.format_carbs, detailedBolusInfo.carbs.toInt()) else ""
|
if (detailedBolusInfo.carbs > 0) rh.gs(R.string.carbs_g, detailedBolusInfo.carbs.toInt()) else ""
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.queue.commands
|
package info.nightscout.androidaps.queue.commands
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
|
@ -19,5 +20,5 @@ class CommandCancelExtendedBolus constructor(
|
||||||
callback?.result(r)?.run()
|
callback?.result(r)?.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "CANCEL EXTENDEDBOLUS"
|
override fun status(): String = rh.gs(R.string.uel_cancel_extended_bolus)
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.queue.commands
|
package info.nightscout.androidaps.queue.commands
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
|
@ -20,5 +21,5 @@ class CommandCancelTempBasal(
|
||||||
callback?.result(r)?.run()
|
callback?.result(r)?.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "CANCEL TEMPBASAL"
|
override fun status(): String = rh.gs(R.string.uel_accepts_temp_basal)
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.queue.commands
|
package info.nightscout.androidaps.queue.commands
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
|
@ -21,5 +22,5 @@ class CommandExtendedBolus constructor(
|
||||||
callback?.result(r)?.run()
|
callback?.result(r)?.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "EXTENDEDBOLUS $insulin U $durationInMinutes min"
|
override fun status(): String = rh.gs(R.string.extended_bolus_u_min, insulin, durationInMinutes)
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.queue.commands
|
package info.nightscout.androidaps.queue.commands
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
|
@ -23,5 +24,5 @@ class CommandInsightSetTBROverNotification constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("SpellCheckingInspection")
|
@Suppress("SpellCheckingInspection")
|
||||||
override fun status(): String = "INSIGHTSETTBROVERNOTIFICATION"
|
override fun status(): String = rh.gs(R.string.insight_set_tbr_over_notification)
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.queue.commands
|
package info.nightscout.androidaps.queue.commands
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.Dana
|
import info.nightscout.androidaps.interfaces.Dana
|
||||||
import info.nightscout.androidaps.interfaces.Diaconn
|
import info.nightscout.androidaps.interfaces.Diaconn
|
||||||
|
@ -32,5 +33,5 @@ class CommandLoadEvents(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "LOAD EVENTS"
|
override fun status(): String = rh.gs(R.string.load_events)
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.queue.commands
|
package info.nightscout.androidaps.queue.commands
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.Dana
|
import info.nightscout.androidaps.interfaces.Dana
|
||||||
import info.nightscout.androidaps.interfaces.Diaconn
|
import info.nightscout.androidaps.interfaces.Diaconn
|
||||||
|
@ -33,5 +34,5 @@ class CommandLoadHistory(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "LOAD HISTORY $type"
|
override fun status(): String = rh.gs(R.string.load_history, type.toInt())
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.queue.commands
|
package info.nightscout.androidaps.queue.commands
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
|
@ -20,5 +21,5 @@ class CommandLoadTDDs(
|
||||||
callback?.result(r)?.run()
|
callback?.result(r)?.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "LOAD TDDs"
|
override fun status(): String = rh.gs(R.string.load_tdds)
|
||||||
}
|
}
|
|
@ -37,5 +37,5 @@ class CommandSMBBolus(
|
||||||
callback?.result(r)?.run()
|
callback?.result(r)?.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "SMB BOLUS ${rh.gs(R.string.formatinsulinunits, detailedBolusInfo.insulin)}"
|
override fun status(): String = rh.gs(R.string.smb_bolus_u, detailedBolusInfo.insulin)
|
||||||
}
|
}
|
|
@ -45,5 +45,5 @@ class CommandSetProfile constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "SET PROFILE"
|
override fun status(): String = rh.gs(R.string.set_profile)
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.queue.commands
|
package info.nightscout.androidaps.queue.commands
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.Dana
|
import info.nightscout.androidaps.interfaces.Dana
|
||||||
import info.nightscout.androidaps.interfaces.Diaconn
|
import info.nightscout.androidaps.interfaces.Diaconn
|
||||||
|
@ -30,5 +31,5 @@ class CommandSetUserSettings(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "SET USER SETTINGS"
|
override fun status(): String = rh.gs(R.string.set_user_settings)
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.queue.commands
|
package info.nightscout.androidaps.queue.commands
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
|
@ -21,5 +22,5 @@ class CommandStartPump(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "START PUMP"
|
override fun status(): String = rh.gs(R.string.start_pump)
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.queue.commands
|
package info.nightscout.androidaps.queue.commands
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
|
@ -21,5 +22,5 @@ class CommandStopPump(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "STOP PUMP"
|
override fun status(): String = rh.gs(R.string.stop_pump)
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.queue.commands
|
package info.nightscout.androidaps.queue.commands
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
import info.nightscout.androidaps.interfaces.Profile
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.PumpSync
|
import info.nightscout.androidaps.interfaces.PumpSync
|
||||||
|
@ -26,5 +27,5 @@ class CommandTempBasalAbsolute(
|
||||||
callback?.result(r)?.run()
|
callback?.result(r)?.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "TEMP BASAL $absoluteRate U/h $durationInMinutes min"
|
override fun status(): String = rh.gs(R.string.temp_basal_absolute, absoluteRate, durationInMinutes)
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.queue.commands
|
package info.nightscout.androidaps.queue.commands
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.Profile
|
import info.nightscout.androidaps.interfaces.Profile
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.PumpSync
|
import info.nightscout.androidaps.interfaces.PumpSync
|
||||||
|
@ -30,5 +31,5 @@ class CommandTempBasalPercent(
|
||||||
callback?.result(r)?.run()
|
callback?.result(r)?.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun status(): String = "TEMP BASAL $percent% $durationInMinutes min"
|
override fun status(): String = rh.gs(R.string.temp_basal_percent, percent, durationInMinutes)
|
||||||
}
|
}
|
|
@ -5,10 +5,7 @@ import android.util.AttributeSet
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
|
||||||
class NumberPickerVertical : NumberPicker {
|
class NumberPickerVertical(context: Context, attrs: AttributeSet? = null) : NumberPicker(context, attrs) {
|
||||||
|
|
||||||
constructor(context: Context?) : super(context)
|
|
||||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
|
|
||||||
|
|
||||||
override fun inflate(context: Context) {
|
override fun inflate(context: Context) {
|
||||||
LayoutInflater.from(context).inflate(R.layout.number_picker_layout_vertical, this, true)
|
LayoutInflater.from(context).inflate(R.layout.number_picker_layout_vertical, this, true)
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||||
android:id="@+id/basalpercentinput"
|
android:id="@+id/basal_percent_input"
|
||||||
android:layout_width="130dp"
|
android:layout_width="130dp"
|
||||||
android:layout_height="40dp" />
|
android:layout_height="40dp" />
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||||
android:id="@+id/basalabsoluteinput"
|
android:id="@+id/basal_absolute_input"
|
||||||
android:layout_width="130dp"
|
android:layout_width="130dp"
|
||||||
android:layout_height="40dp" />
|
android:layout_height="40dp" />
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import dagger.android.AndroidInjector
|
import dagger.android.AndroidInjector
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.TestBaseWithProfile
|
import info.nightscout.androidaps.TestBaseWithProfile
|
||||||
import info.nightscout.androidaps.TestPumpPlugin
|
import info.nightscout.androidaps.TestPumpPlugin
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
|
@ -21,6 +22,7 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
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.ArgumentMatchers
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito
|
import org.mockito.Mockito
|
||||||
|
|
||||||
|
@ -41,6 +43,7 @@ class QueueThreadTest : TestBaseWithProfile() {
|
||||||
}
|
}
|
||||||
if (it is CommandTempBasalAbsolute) {
|
if (it is CommandTempBasalAbsolute) {
|
||||||
it.activePlugin = activePlugin
|
it.activePlugin = activePlugin
|
||||||
|
it.rh = rh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,6 +78,7 @@ class QueueThreadTest : TestBaseWithProfile() {
|
||||||
val percentageConstraint = Constraint(0)
|
val percentageConstraint = Constraint(0)
|
||||||
Mockito.`when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject()))
|
Mockito.`when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject()))
|
||||||
.thenReturn(percentageConstraint)
|
.thenReturn(percentageConstraint)
|
||||||
|
Mockito.`when`(rh.gs(ArgumentMatchers.eq(R.string.temp_basal_absolute), anyObject(), anyObject())).thenReturn("TEMP BASAL %1\$.2f U/h %2\$d min")
|
||||||
|
|
||||||
sut = QueueThread(commandQueue, context, aapsLogger, rxBus, activePlugin, rh, sp)
|
sut = QueueThread(commandQueue, context, aapsLogger, rxBus, activePlugin, rh, sp)
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ class EditEventDialog : DialogFragmentWithDate() {
|
||||||
// check for title
|
// check for title
|
||||||
val title = binding.inputEventTitle.text?.toString() ?: return false
|
val title = binding.inputEventTitle.text?.toString() ?: return false
|
||||||
if (title.isEmpty()) {
|
if (title.isEmpty()) {
|
||||||
ToastUtils.showToastInUiThread(context, R.string.automation_missing_task_name)
|
context?.let { ToastUtils.showToastInUiThread(it, R.string.automation_missing_task_name) }
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
event.title = title
|
event.title = title
|
||||||
|
@ -137,12 +137,12 @@ class EditEventDialog : DialogFragmentWithDate() {
|
||||||
// check for at least one trigger
|
// check for at least one trigger
|
||||||
val con = event.trigger
|
val con = event.trigger
|
||||||
if (con.size() == 0 && !event.userAction) {
|
if (con.size() == 0 && !event.userAction) {
|
||||||
ToastUtils.showToastInUiThread(context, R.string.automation_missing_trigger)
|
context?.let { ToastUtils.showToastInUiThread(it, R.string.automation_missing_trigger) }
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// check for at least one action
|
// check for at least one action
|
||||||
if (event.actions.isEmpty()) {
|
if (event.actions.isEmpty()) {
|
||||||
ToastUtils.showToastInUiThread(context, R.string.automation_missing_action)
|
context?.let { ToastUtils.showToastInUiThread(it, R.string.automation_missing_action) }
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// store
|
// store
|
||||||
|
|
|
@ -9,7 +9,7 @@ buildscript {
|
||||||
rxkotlin_version = '2.4.0'
|
rxkotlin_version = '2.4.0'
|
||||||
room_version = '2.3.0'
|
room_version = '2.3.0'
|
||||||
lifecycle_version = '2.3.1'
|
lifecycle_version = '2.3.1'
|
||||||
dagger_version = '2.40.1'
|
dagger_version = '2.40.2'
|
||||||
coroutinesVersion = '1.4.1'
|
coroutinesVersion = '1.4.1'
|
||||||
activityVersion = '1.3.1'
|
activityVersion = '1.3.1'
|
||||||
fragmentktx_version = '1.3.6'
|
fragmentktx_version = '1.3.6'
|
||||||
|
|
|
@ -10,18 +10,18 @@ import org.json.JSONObject
|
||||||
@Suppress("SpellCheckingInspection")
|
@Suppress("SpellCheckingInspection")
|
||||||
class IobTotal(val time: Long) : DataPointWithLabelInterface {
|
class IobTotal(val time: Long) : DataPointWithLabelInterface {
|
||||||
|
|
||||||
@JvmField var iob = 0.0
|
var iob = 0.0
|
||||||
@JvmField var activity = 0.0
|
var activity = 0.0
|
||||||
@JvmField var bolussnooze = 0.0
|
var bolussnooze = 0.0
|
||||||
@JvmField var basaliob = 0.0
|
var basaliob = 0.0
|
||||||
@JvmField var netbasalinsulin = 0.0
|
var netbasalinsulin = 0.0
|
||||||
@JvmField var hightempinsulin = 0.0
|
var hightempinsulin = 0.0
|
||||||
|
|
||||||
// oref1
|
// oref1
|
||||||
@JvmField var lastBolusTime: Long = 0
|
var lastBolusTime: Long = 0
|
||||||
var iobWithZeroTemp: IobTotal? = null
|
var iobWithZeroTemp: IobTotal? = null
|
||||||
@JvmField var netInsulin = 0.0 // for calculations from temp basals only
|
var netInsulin = 0.0 // for calculations from temp basals only
|
||||||
@JvmField var extendedBolusInsulin = 0.0 // total insulin for extended bolus
|
var extendedBolusInsulin = 0.0 // total insulin for extended bolus
|
||||||
fun copy(): IobTotal {
|
fun copy(): IobTotal {
|
||||||
val i = IobTotal(time)
|
val i = IobTotal(time)
|
||||||
i.iob = iob
|
i.iob = iob
|
||||||
|
@ -104,36 +104,14 @@ class IobTotal(val time: Long) : DataPointWithLabelInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DataPoint interface
|
// DataPoint interface
|
||||||
private var color = 0
|
override var color = 0
|
||||||
override fun getX(): Double {
|
override fun getX(): Double = time.toDouble()
|
||||||
return time.toDouble()
|
override fun getY(): Double = iob
|
||||||
}
|
|
||||||
|
|
||||||
override fun getY(): Double {
|
|
||||||
return iob
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setY(y: Double) {}
|
override fun setY(y: Double) {}
|
||||||
|
override val label = ""
|
||||||
override fun getLabel(): String {
|
override val duration = 0L
|
||||||
return ""
|
override val shape = PointsWithLabelGraphSeries.Shape.IOBPREDICTION
|
||||||
}
|
override val size = 0.5f
|
||||||
|
|
||||||
override fun getDuration(): Long {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getShape(): PointsWithLabelGraphSeries.Shape {
|
|
||||||
return PointsWithLabelGraphSeries.Shape.IOBPREDICTION
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getSize(): Float {
|
|
||||||
return 0.5f
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getColor(): Int {
|
|
||||||
return color
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setColor(color: Int): IobTotal {
|
fun setColor(color: Int): IobTotal {
|
||||||
this.color = color
|
this.color = color
|
||||||
|
|
|
@ -164,7 +164,7 @@ class ProfileViewerDialog : DaggerDialogFragment() {
|
||||||
binding.date.text = date
|
binding.date.text = date
|
||||||
binding.ic.text = it.getIcList(rh, dateUtil)
|
binding.ic.text = it.getIcList(rh, dateUtil)
|
||||||
binding.isf.text = it.getIsfList(rh, dateUtil)
|
binding.isf.text = it.getIsfList(rh, dateUtil)
|
||||||
binding.basal.text = it.getBasalList(rh, dateUtil)
|
binding.basal.text = "∑ " + rh.gs(R.string.formatinsulinunits, it.baseBasalSum()) + "\n" + it.getBasalList(rh, dateUtil)
|
||||||
binding.target.text = it.getTargetList(rh, dateUtil)
|
binding.target.text = it.getTargetList(rh, dateUtil)
|
||||||
binding.basalGraph.show(it)
|
binding.basalGraph.show(it)
|
||||||
|
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.aps.openAPSSMB;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by mike on 10.12.2017.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class SMBDefaults {
|
|
||||||
// CALCULATED OR FROM PREFS
|
|
||||||
|
|
||||||
// max_iob: 0 // if max_iob is not provided, will default to zero
|
|
||||||
// max_daily_safety_multiplier:3
|
|
||||||
// current_basal_safety_multiplier:4
|
|
||||||
// autosens_max:1.2
|
|
||||||
// autosens_min:0.7
|
|
||||||
|
|
||||||
// USED IN AUTOSENS
|
|
||||||
public final static boolean rewind_resets_autosens = true; // reset autosensitivity to neutral for awhile after each pump rewind
|
|
||||||
|
|
||||||
// USED IN TARGETS
|
|
||||||
// by default the higher end of the target range is used only for avoiding bolus wizard overcorrections
|
|
||||||
// use wide_bg_target_range: true to force neutral temps over a wider range of eventualBGs
|
|
||||||
public final static boolean wide_bg_target_range = false; // by default use only the low end of the pump's BG target range as OpenAPS target
|
|
||||||
|
|
||||||
// USED IN AUTOTUNE
|
|
||||||
public final static double autotune_isf_adjustmentFraction = 1.0; // keep autotune ISF closer to pump ISF via a weighted average of fullNewISF and pumpISF. 1.0 allows full adjustment, 0 is no adjustment from pump ISF.
|
|
||||||
public final static double remainingCarbsFraction = 1.0; // fraction of carbs we'll assume will absorb over 4h if we don't yet see carb absorption
|
|
||||||
|
|
||||||
// USED IN DETERMINE_BASAL
|
|
||||||
public final static boolean low_temptarget_lowers_sensitivity = false; // lower sensitivity for temptargets <= 99.
|
|
||||||
public final static boolean high_temptarget_raises_sensitivity = false; // raise sensitivity for temptargets >= 111. synonym for exercise_mode
|
|
||||||
public final static boolean sensitivity_raises_target = true; // raise BG target when autosens detects sensitivity
|
|
||||||
public final static boolean resistance_lowers_target = false; // lower BG target when autosens detects resistance
|
|
||||||
public final static boolean adv_target_adjustments = false; // lower target automatically when BG and eventualBG are high
|
|
||||||
public final static boolean exercise_mode = false; // when true, > 105 mg/dL high temp target adjusts sensitivityRatio for exercise_mode. This majorly changes the behavior of high temp targets from before. synonmym for high_temptarget_raises_sensitivity
|
|
||||||
public final static int half_basal_exercise_target = 160; // when temptarget is 160 mg/dL *and* exercise_mode=true, run 50% basal at this level (120 = 75%; 140 = 60%)
|
|
||||||
// create maxCOB and default it to 120 because that's the most a typical body can absorb over 4 hours.
|
|
||||||
// (If someone enters more carbs or stacks more; OpenAPS will just truncate dosing based on 120.
|
|
||||||
// Essentially, this just limits AMA/SMB as a safety cap against excessive COB entry)
|
|
||||||
public final static int maxCOB = 120;
|
|
||||||
//public final static boolean skip_neutral_temps = true; // ***** default false in oref1 ***** if true, don't set neutral temps
|
|
||||||
// unsuspend_if_no_temp:false // if true, pump will un-suspend after a zero temp finishes
|
|
||||||
// bolussnooze_dia_divisor:2 // bolus snooze decays after 1/2 of DIA
|
|
||||||
public final static double min_5m_carbimpact = 8d; // mg/dL per 5m (8 mg/dL/5m corresponds to 24g/hr at a CSF of 4 mg/dL/g (x/5*60/4))
|
|
||||||
public final static int remainingCarbsCap = 90; // max carbs we'll assume will absorb over 4h if we don't yet see carb absorption
|
|
||||||
// WARNING: use SMB with caution: it can and will automatically bolus up to max_iob worth of extra insulin
|
|
||||||
// enableUAM:true // enable detection of unannounced meal carb absorption
|
|
||||||
public final static boolean A52_risk_enable = false;
|
|
||||||
//public final static boolean enableSMB_with_COB = true; // ***** default false in oref1 ***** enable supermicrobolus while COB is positive
|
|
||||||
//public final static boolean enableSMB_with_temptarget = true; // ***** default false in oref1 ***** enable supermicrobolus for eating soon temp targets
|
|
||||||
// *** WARNING *** DO NOT USE enableSMB_always or enableSMB_after_carbs with xDrip+, Libre, or similar
|
|
||||||
// xDrip+, LimiTTer, etc. do not properly filter out high-noise SGVs
|
|
||||||
// Using SMB overnight with such data sources risks causing a dangerous overdose of insulin
|
|
||||||
// if the CGM sensor reads falsely high and doesn't come down as actual BG does
|
|
||||||
// public final static boolean enableSMB_always = false; // always enable supermicrobolus (unless disabled by high temptarget)
|
|
||||||
// *** WARNING *** DO NOT USE enableSMB_always or enableSMB_after_carbs with xDrip+, Libre, or similar
|
|
||||||
//public final static boolean enableSMB_after_carbs = false; // enable supermicrobolus for 6h after carbs, even with 0 COB
|
|
||||||
//public final static boolean allowSMB_with_high_temptarget = false; // allow supermicrobolus (if otherwise enabled) even with high temp targets
|
|
||||||
public final static int SMBInterval = 3; // minimum interval between SMBs, in minutes. (limited between 1 and 10 min)
|
|
||||||
public final static int maxSMBBasalMinutes = 30; // maximum minutes of basal that can be delivered as a single SMB with uncovered COB
|
|
||||||
public final static int maxUAMSMBBasalMinutes = 30; // maximum minutes of basal that can be delivered as a single SMB when IOB exceeds COB
|
|
||||||
// curve:"rapid-acting" // Supported curves: "bilinear", "rapid-acting" (Novolog, Novorapid, Humalog, Apidra) and "ultra-rapid" (Fiasp)
|
|
||||||
// useCustomPeakTime:false // allows changing insulinPeakTime
|
|
||||||
// insulinPeakTime:75 // number of minutes after a bolus activity peaks. defaults to 55m for Fiasp if useCustomPeakTime: false
|
|
||||||
public final static int carbsReqThreshold = 1; // grams of carbsReq to trigger a pushover
|
|
||||||
// offline_hotspot:false // enabled an offline-only local wifi hotspot if no Internet available
|
|
||||||
public final static double bolus_increment = 0.1; // minimum bolus that can be delivered as an SMB
|
|
||||||
}
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package info.nightscout.androidaps.plugins.aps.openAPSSMB
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
object SMBDefaults {
|
||||||
|
|
||||||
|
// CALCULATED OR FROM PREFS
|
||||||
|
// max_iob: 0 // if max_iob is not provided, will default to zero
|
||||||
|
// max_daily_safety_multiplier:3
|
||||||
|
// current_basal_safety_multiplier:4
|
||||||
|
// autosens_max:1.2
|
||||||
|
// autosens_min:0.7
|
||||||
|
// USED IN AUTOSENS
|
||||||
|
// const val rewind_resets_autosens = true // reset autosensitivity to neutral for awhile after each pump rewind
|
||||||
|
|
||||||
|
// USED IN TARGETS
|
||||||
|
// by default the higher end of the target range is used only for avoiding bolus wizard overcorrections
|
||||||
|
// use wide_bg_target_range: true to force neutral temps over a wider range of eventualBGs
|
||||||
|
// const val wide_bg_target_range = false // by default use only the low end of the pump's BG target range as OpenAPS target
|
||||||
|
|
||||||
|
// USED IN AUTOTUNE
|
||||||
|
// const val autotune_isf_adjustmentFraction = 1.0 // keep autotune ISF closer to pump ISF via a weighted average of fullNewISF and pumpISF. 1.0 allows full adjustment, 0 is no adjustment from pump ISF.
|
||||||
|
// const val remainingCarbsFraction = 1.0 // fraction of carbs we'll assume will absorb over 4h if we don't yet see carb absorption
|
||||||
|
|
||||||
|
// USED IN DETERMINE_BASAL
|
||||||
|
// const val low_temptarget_lowers_sensitivity = false // lower sensitivity for temptargets <= 99.
|
||||||
|
const val high_temptarget_raises_sensitivity = false // raise sensitivity for temptargets >= 111. synonym for exercise_mode
|
||||||
|
const val sensitivity_raises_target = true // raise BG target when autosens detects sensitivity
|
||||||
|
const val resistance_lowers_target = false // lower BG target when autosens detects resistance
|
||||||
|
const val adv_target_adjustments = false // lower target automatically when BG and eventualBG are high
|
||||||
|
const val exercise_mode = false // when true, > 105 mg/dL high temp target adjusts sensitivityRatio for exercise_mode. This majorly changes the behavior of high temp targets from before. synonym for high_temptarget_raises_sensitivity
|
||||||
|
const val half_basal_exercise_target = 160 // when temptarget is 160 mg/dL *and* exercise_mode=true, run 50% basal at this level (120 = 75%; 140 = 60%)
|
||||||
|
|
||||||
|
// create maxCOB and default it to 120 because that's the most a typical body can absorb over 4 hours.
|
||||||
|
// (If someone enters more carbs or stacks more; OpenAPS will just truncate dosing based on 120.
|
||||||
|
// Essentially, this just limits AMA/SMB as a safety cap against excessive COB entry)
|
||||||
|
const val maxCOB = 120
|
||||||
|
|
||||||
|
//public final static boolean skip_neutral_temps = true; // ***** default false in oref1 ***** if true, don't set neutral temps
|
||||||
|
// un-suspend_if_no_temp:false // if true, pump will un-suspend after a zero temp finishes
|
||||||
|
// bolussnooze_dia_divisor:2 // bolus snooze decays after 1/2 of DIA
|
||||||
|
const val min_5m_carbimpact = 8.0 // mg/dL per 5m (8 mg/dL/5m corresponds to 24g/hr at a CSF of 4 mg/dL/g (x/5*60/4))
|
||||||
|
const val remainingCarbsCap = 90 // max carbs we'll assume will absorb over 4h if we don't yet see carb absorption
|
||||||
|
|
||||||
|
// WARNING: use SMB with caution: it can and will automatically bolus up to max_iob worth of extra insulin
|
||||||
|
// enableUAM:true // enable detection of unannounced meal carb absorption
|
||||||
|
const val A52_risk_enable = false
|
||||||
|
|
||||||
|
//public final static boolean enableSMB_with_COB = true; // ***** default false in oref1 ***** enable supermicrobolus while COB is positive
|
||||||
|
//public final static boolean enableSMB_with_temptarget = true; // ***** default false in oref1 ***** enable supermicrobolus for eating soon temp targets
|
||||||
|
// *** WARNING *** DO NOT USE enableSMB_always or enableSMB_after_carbs with xDrip+, Libre, or similar
|
||||||
|
// xDrip+, LimiTTer, etc. do not properly filter out high-noise SGVs
|
||||||
|
// Using SMB overnight with such data sources risks causing a dangerous overdose of insulin
|
||||||
|
// if the CGM sensor reads falsely high and doesn't come down as actual BG does
|
||||||
|
// public final static boolean enableSMB_always = false; // always enable supermicrobolus (unless disabled by high temptarget)
|
||||||
|
// *** WARNING *** DO NOT USE enableSMB_always or enableSMB_after_carbs with xDrip+, Libre, or similar
|
||||||
|
//public final static boolean enableSMB_after_carbs = false; // enable supermicrobolus for 6h after carbs, even with 0 COB
|
||||||
|
//public final static boolean allowSMB_with_high_temptarget = false; // allow supermicrobolus (if otherwise enabled) even with high temp targets
|
||||||
|
const val SMBInterval = 3 // minimum interval between SMBs, in minutes. (limited between 1 and 10 min)
|
||||||
|
const val maxSMBBasalMinutes = 30 // maximum minutes of basal that can be delivered as a single SMB with uncovered COB
|
||||||
|
const val maxUAMSMBBasalMinutes = 30 // maximum minutes of basal that can be delivered as a single SMB when IOB exceeds COB
|
||||||
|
|
||||||
|
// curve:"rapid-acting" // Supported curves: "bilinear", "rapid-acting" (Novolog, Novorapid, Humalog, Apidra) and "ultra-rapid" (Fiasp)
|
||||||
|
// useCustomPeakTime:false // allows changing insulinPeakTime
|
||||||
|
// insulinPeakTime:75 // number of minutes after a bolus activity peaks. defaults to 55m for Fiasp if useCustomPeakTime: false
|
||||||
|
const val carbsReqThreshold = 1 // grams of carbsReq to trigger a pushover
|
||||||
|
|
||||||
|
// offline_hotspot:false // enabled an offline-only local wifi hotspot if no Internet available
|
||||||
|
// const val bolus_increment = 0.1 // minimum bolus that can be delivered as an SMB
|
||||||
|
}
|
|
@ -1,58 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.general.overview.graphExtensions;
|
|
||||||
/**
|
|
||||||
* GraphView
|
|
||||||
* Copyright (C) 2014 Jonas Gehring
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License,
|
|
||||||
* with the "Linking Exception", which can be found at the license.txt
|
|
||||||
* file in this program.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* with the "Linking Exception" along with this program; if not,
|
|
||||||
* write to the author Jonas Gehring <g.jjoe64@gmail.com>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Added by mike
|
|
||||||
*/
|
|
||||||
|
|
||||||
import com.jjoe64.graphview.series.DataPointInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* interface of data points. Implement this in order
|
|
||||||
* to use your class in {@link com.jjoe64.graphview.series.Series}.
|
|
||||||
*
|
|
||||||
* You can also use the default implementation {@link com.jjoe64.graphview.series.DataPoint} so
|
|
||||||
* you do not have to implement it for yourself.
|
|
||||||
*
|
|
||||||
* @author jjoe64
|
|
||||||
*/
|
|
||||||
public interface DataPointWithLabelInterface extends DataPointInterface{
|
|
||||||
/**
|
|
||||||
* @return the x value
|
|
||||||
*/
|
|
||||||
double getX();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the y value
|
|
||||||
*/
|
|
||||||
double getY();
|
|
||||||
void setY(double y);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the label value
|
|
||||||
*/
|
|
||||||
String getLabel();
|
|
||||||
|
|
||||||
long getDuration();
|
|
||||||
PointsWithLabelGraphSeries.Shape getShape();
|
|
||||||
float getSize();
|
|
||||||
int getColor();
|
|
||||||
}
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.overview.graphExtensions
|
||||||
|
|
||||||
|
import com.jjoe64.graphview.series.DataPointInterface
|
||||||
|
|
||||||
|
interface DataPointWithLabelInterface : DataPointInterface {
|
||||||
|
|
||||||
|
override fun getX(): Double
|
||||||
|
override fun getY(): Double
|
||||||
|
fun setY(y: Double)
|
||||||
|
|
||||||
|
val label: String?
|
||||||
|
val duration: Long
|
||||||
|
val shape: PointsWithLabelGraphSeries.Shape?
|
||||||
|
val size: Float
|
||||||
|
val color: Int
|
||||||
|
}
|
|
@ -347,7 +347,7 @@ class AutosensDataStore {
|
||||||
synchronized(dataLock) {
|
synchronized(dataLock) {
|
||||||
var i = autosensDataTable.size() - 1
|
var i = autosensDataTable.size() - 1
|
||||||
while (i >= 0 && count < valuesToProcess) {
|
while (i >= 0 && count < valuesToProcess) {
|
||||||
if (autosensDataTable.valueAt(i).failoverToMinAbsorbtionRate) sum++
|
if (autosensDataTable.valueAt(i).failOverToMinAbsorptionRate) sum++
|
||||||
count++
|
count++
|
||||||
i--
|
i--
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,203 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.iob.iobCobCalculator.data;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.Constants;
|
|
||||||
import info.nightscout.androidaps.core.R;
|
|
||||||
import info.nightscout.androidaps.interfaces.Profile;
|
|
||||||
import info.nightscout.androidaps.database.entities.Carbs;
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil;
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
|
||||||
|
|
||||||
public class AutosensData implements DataPointWithLabelInterface {
|
|
||||||
|
|
||||||
@Inject AAPSLogger aapsLogger;
|
|
||||||
@Inject SP sp;
|
|
||||||
@Inject ResourceHelper rh;
|
|
||||||
@Inject ProfileFunction profileFunction;
|
|
||||||
@Inject DateUtil dateUtil;
|
|
||||||
|
|
||||||
public AutosensData(HasAndroidInjector injector) {
|
|
||||||
injector.androidInjector().inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setChartTime(long chartTime) {
|
|
||||||
this.chartTime = chartTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CarbsInPast {
|
|
||||||
long time;
|
|
||||||
double carbs;
|
|
||||||
public double min5minCarbImpact;
|
|
||||||
double remaining;
|
|
||||||
|
|
||||||
public CarbsInPast(Carbs t, boolean isAAPSOrWeighted) {
|
|
||||||
time = t.getTimestamp();
|
|
||||||
carbs = t.getAmount();
|
|
||||||
remaining = t.getAmount();
|
|
||||||
Profile profile = profileFunction.getProfile(t.getTimestamp());
|
|
||||||
if (isAAPSOrWeighted && profile != null) {
|
|
||||||
double maxAbsorptionHours = sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME);
|
|
||||||
double sens = profile.getIsfMgdl(t.getTimestamp());
|
|
||||||
double ic = profile.getIc(t.getTimestamp());
|
|
||||||
min5minCarbImpact = t.getAmount() / (maxAbsorptionHours * 60 / 5) * sens / ic;
|
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "Min 5m carbs impact for " + carbs + "g @" + dateUtil.dateAndTimeString(t.getTimestamp()) + " for " + maxAbsorptionHours + "h calculated to " + min5minCarbImpact + " ISF: " + sens + " IC: " + ic);
|
|
||||||
} else {
|
|
||||||
min5minCarbImpact = sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CarbsInPast(CarbsInPast other) {
|
|
||||||
this.time = other.time;
|
|
||||||
this.carbs = other.carbs;
|
|
||||||
this.min5minCarbImpact = other.min5minCarbImpact;
|
|
||||||
this.remaining = other.remaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format(Locale.ENGLISH, "CarbsInPast: time: %s carbs: %.02f min5minCI: %.02f remaining: %.2f", dateUtil.dateAndTimeString(time), carbs, min5minCarbImpact, remaining);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public long time = 0L;
|
|
||||||
public double bg = 0; // mgdl
|
|
||||||
private long chartTime;
|
|
||||||
public String pastSensitivity = "";
|
|
||||||
public double deviation = 0d;
|
|
||||||
public boolean validDeviation = false;
|
|
||||||
public List<CarbsInPast> activeCarbsList = new ArrayList<>();
|
|
||||||
public double absorbed = 0d;
|
|
||||||
public double carbsFromBolus = 0d;
|
|
||||||
public double cob = 0;
|
|
||||||
public double bgi = 0d;
|
|
||||||
public double delta = 0d;
|
|
||||||
public double avgDelta = 0d;
|
|
||||||
public double avgDeviation = 0d;
|
|
||||||
|
|
||||||
public AutosensResult autosensResult = new AutosensResult();
|
|
||||||
public double slopeFromMaxDeviation = 0;
|
|
||||||
public double slopeFromMinDeviation = 999;
|
|
||||||
public double usedMinCarbsImpact = 0d;
|
|
||||||
public boolean failoverToMinAbsorbtionRate = false;
|
|
||||||
|
|
||||||
// Oref1
|
|
||||||
public boolean absorbing = false;
|
|
||||||
public double mealCarbs = 0;
|
|
||||||
public int mealStartCounter = 999;
|
|
||||||
public String type = "";
|
|
||||||
public boolean uam = false;
|
|
||||||
public List<Double> extraDeviation = new ArrayList<>();
|
|
||||||
|
|
||||||
@NonNull @Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format(Locale.ENGLISH, "AutosensData: %s pastSensitivity=%s delta=%.02f avgDelta=%.02f bgi=%.02f deviation=%.02f avgDeviation=%.02f absorbed=%.02f carbsFromBolus=%.02f cob=%.02f autosensRatio=%.02f slopeFromMaxDeviation=%.02f slopeFromMinDeviation=%.02f activeCarbsList=%s",
|
|
||||||
dateUtil.dateAndTimeString(time), pastSensitivity, delta, avgDelta, bgi, deviation, avgDeviation, absorbed, carbsFromBolus, cob, autosensResult.getRatio(), slopeFromMaxDeviation, slopeFromMinDeviation, activeCarbsList.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<CarbsInPast> cloneCarbsList() {
|
|
||||||
List<CarbsInPast> newActiveCarbsList = new ArrayList<>();
|
|
||||||
|
|
||||||
for (CarbsInPast c : activeCarbsList) {
|
|
||||||
newActiveCarbsList.add(new CarbsInPast(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
return newActiveCarbsList;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove carbs older than timeframe
|
|
||||||
public void removeOldCarbs(long toTime, boolean isAAPSOrWeighted) {
|
|
||||||
double maxAbsorptionHours;
|
|
||||||
if (isAAPSOrWeighted) {
|
|
||||||
maxAbsorptionHours = sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME);
|
|
||||||
} else {
|
|
||||||
maxAbsorptionHours = sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < activeCarbsList.size(); i++) {
|
|
||||||
CarbsInPast c = activeCarbsList.get(i);
|
|
||||||
if (c.time + maxAbsorptionHours * 60 * 60 * 1000L < toTime) {
|
|
||||||
activeCarbsList.remove(i--);
|
|
||||||
if (c.remaining > 0)
|
|
||||||
cob -= c.remaining;
|
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "Removing carbs at " + dateUtil.dateAndTimeString(toTime) + " after " + maxAbsorptionHours + "h > " + c.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void substractAbosorbedCarbs() {
|
|
||||||
double ac = absorbed;
|
|
||||||
for (int i = 0; i < activeCarbsList.size() && ac > 0; i++) {
|
|
||||||
CarbsInPast c = activeCarbsList.get(i);
|
|
||||||
if (c.remaining > 0) {
|
|
||||||
double sub = Math.min(ac, c.remaining);
|
|
||||||
c.remaining -= sub;
|
|
||||||
ac -= sub;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------- DataPointWithLabelInterface ------
|
|
||||||
|
|
||||||
private Scale scale;
|
|
||||||
|
|
||||||
public void setScale(Scale scale) {
|
|
||||||
this.scale = scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getX() {
|
|
||||||
return chartTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getY() {
|
|
||||||
return scale.transform(cob);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setY(double y) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getLabel() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getDuration() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PointsWithLabelGraphSeries.Shape getShape() {
|
|
||||||
return PointsWithLabelGraphSeries.Shape.COBFAILOVER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getSize() {
|
|
||||||
return 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getColor() {
|
|
||||||
return rh.gc(R.color.cob);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
package info.nightscout.androidaps.plugins.iob.iobCobCalculator.data
|
||||||
|
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.Constants
|
||||||
|
import info.nightscout.androidaps.core.R
|
||||||
|
import info.nightscout.androidaps.database.entities.Carbs
|
||||||
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
class AutosensData(injector: HasAndroidInjector) : DataPointWithLabelInterface {
|
||||||
|
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
@Inject lateinit var rh: ResourceHelper
|
||||||
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
|
|
||||||
|
inner class CarbsInPast {
|
||||||
|
|
||||||
|
var time: Long
|
||||||
|
var carbs: Double
|
||||||
|
var min5minCarbImpact = 0.0
|
||||||
|
var remaining: Double
|
||||||
|
|
||||||
|
constructor(t: Carbs, isAAPSOrWeighted: Boolean) {
|
||||||
|
time = t.timestamp
|
||||||
|
carbs = t.amount
|
||||||
|
remaining = t.amount
|
||||||
|
val profile = profileFunction.getProfile(t.timestamp)
|
||||||
|
if (isAAPSOrWeighted && profile != null) {
|
||||||
|
val maxAbsorptionHours = sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME)
|
||||||
|
val sens = profile.getIsfMgdl(t.timestamp)
|
||||||
|
val ic = profile.getIc(t.timestamp)
|
||||||
|
min5minCarbImpact = t.amount / (maxAbsorptionHours * 60 / 5) * sens / ic
|
||||||
|
aapsLogger.debug(
|
||||||
|
LTag.AUTOSENS,
|
||||||
|
"""Min 5m carbs impact for ${carbs}g @${dateUtil.dateAndTimeString(t.timestamp)} for ${maxAbsorptionHours}h calculated to $min5minCarbImpact ISF: $sens IC: $ic"""
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
min5minCarbImpact = sp.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal constructor(other: CarbsInPast) {
|
||||||
|
time = other.time
|
||||||
|
carbs = other.carbs
|
||||||
|
min5minCarbImpact = other.min5minCarbImpact
|
||||||
|
remaining = other.remaining
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String =
|
||||||
|
String.format(Locale.ENGLISH, "CarbsInPast: time: %s carbs: %.02f min5minCI: %.02f remaining: %.2f", dateUtil.dateAndTimeString(time), carbs, min5minCarbImpact, remaining)
|
||||||
|
}
|
||||||
|
|
||||||
|
var time = 0L
|
||||||
|
var bg = 0.0 // mgdl
|
||||||
|
var chartTime: Long = 0
|
||||||
|
var pastSensitivity = ""
|
||||||
|
var deviation = 0.0
|
||||||
|
var validDeviation = false
|
||||||
|
var activeCarbsList: MutableList<CarbsInPast> = ArrayList()
|
||||||
|
var absorbed = 0.0
|
||||||
|
var carbsFromBolus = 0.0
|
||||||
|
var cob = 0.0
|
||||||
|
var bgi = 0.0
|
||||||
|
var delta = 0.0
|
||||||
|
var avgDelta = 0.0
|
||||||
|
var avgDeviation = 0.0
|
||||||
|
var autosensResult = AutosensResult()
|
||||||
|
var slopeFromMaxDeviation = 0.0
|
||||||
|
var slopeFromMinDeviation = 999.0
|
||||||
|
var usedMinCarbsImpact = 0.0
|
||||||
|
var failOverToMinAbsorptionRate = false
|
||||||
|
|
||||||
|
// Oref1
|
||||||
|
var absorbing = false
|
||||||
|
var mealCarbs = 0.0
|
||||||
|
var mealStartCounter = 999
|
||||||
|
var type = ""
|
||||||
|
var uam = false
|
||||||
|
var extraDeviation: MutableList<Double> = ArrayList()
|
||||||
|
override fun toString(): String {
|
||||||
|
return String.format(
|
||||||
|
Locale.ENGLISH,
|
||||||
|
"AutosensData: %s pastSensitivity=%s delta=%.02f avgDelta=%.02f bgi=%.02f deviation=%.02f avgDeviation=%.02f absorbed=%.02f carbsFromBolus=%.02f cob=%.02f autosensRatio=%.02f slopeFromMaxDeviation=%.02f slopeFromMinDeviation=%.02f activeCarbsList=%s",
|
||||||
|
dateUtil.dateAndTimeString(time),
|
||||||
|
pastSensitivity,
|
||||||
|
delta,
|
||||||
|
avgDelta,
|
||||||
|
bgi,
|
||||||
|
deviation,
|
||||||
|
avgDeviation,
|
||||||
|
absorbed,
|
||||||
|
carbsFromBolus,
|
||||||
|
cob,
|
||||||
|
autosensResult.ratio,
|
||||||
|
slopeFromMaxDeviation,
|
||||||
|
slopeFromMinDeviation,
|
||||||
|
activeCarbsList.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cloneCarbsList(): MutableList<CarbsInPast> {
|
||||||
|
val newActiveCarbsList: MutableList<CarbsInPast> = ArrayList()
|
||||||
|
for (c in activeCarbsList) {
|
||||||
|
newActiveCarbsList.add(CarbsInPast(c))
|
||||||
|
}
|
||||||
|
return newActiveCarbsList
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove carbs older than timeframe
|
||||||
|
fun removeOldCarbs(toTime: Long, isAAPSOrWeighted: Boolean) {
|
||||||
|
val maxAbsorptionHours: Double =
|
||||||
|
if (isAAPSOrWeighted) sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME)
|
||||||
|
else sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME)
|
||||||
|
var i = 0
|
||||||
|
while (i < activeCarbsList.size) {
|
||||||
|
val c = activeCarbsList[i]
|
||||||
|
if (c.time + maxAbsorptionHours * 60 * 60 * 1000L < toTime) {
|
||||||
|
activeCarbsList.removeAt(i--)
|
||||||
|
if (c.remaining > 0) cob -= c.remaining
|
||||||
|
aapsLogger.debug(LTag.AUTOSENS, "Removing carbs at " + dateUtil.dateAndTimeString(toTime) + " after " + maxAbsorptionHours + "h > " + c.toString())
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deductAbsorbedCarbs() {
|
||||||
|
var ac = absorbed
|
||||||
|
var i = 0
|
||||||
|
while (i < activeCarbsList.size && ac > 0) {
|
||||||
|
val c = activeCarbsList[i]
|
||||||
|
if (c.remaining > 0) {
|
||||||
|
val sub = min(ac, c.remaining)
|
||||||
|
c.remaining -= sub
|
||||||
|
ac -= sub
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------- DataPointWithLabelInterface ------
|
||||||
|
var scale: Scale? = null
|
||||||
|
|
||||||
|
override fun getX(): Double = chartTime.toDouble()
|
||||||
|
override fun getY(): Double = scale!!.transform(cob)
|
||||||
|
|
||||||
|
override fun setY(y: Double) {}
|
||||||
|
override val label: String? = null
|
||||||
|
override val duration = 0L
|
||||||
|
override val shape = PointsWithLabelGraphSeries.Shape.COBFAILOVER
|
||||||
|
override val size = 0.5f
|
||||||
|
override val color get() = rh.gc(R.color.cob)
|
||||||
|
|
||||||
|
init {
|
||||||
|
injector.androidInjector().inject(this)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,108 +0,0 @@
|
||||||
package info.nightscout.androidaps.utils;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.media.MediaPlayer;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes;
|
|
||||||
import androidx.appcompat.view.ContextThemeWrapper;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.core.R;
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
|
||||||
|
|
||||||
|
|
||||||
public class ToastUtils {
|
|
||||||
|
|
||||||
private static Toast lastToast = null;
|
|
||||||
|
|
||||||
public static class Long {
|
|
||||||
|
|
||||||
public static void warnToast(final Context ctx, final String string) {
|
|
||||||
graphicalToast(ctx, string, R.drawable.ic_toast_warn, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void infoToast(final Context ctx, final String string) {
|
|
||||||
graphicalToast(ctx, string, R.drawable.ic_toast_info, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void okToast(final Context ctx, final String string) {
|
|
||||||
graphicalToast(ctx, string, R.drawable.ic_toast_check, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void errorToast(final Context ctx, final String string) {
|
|
||||||
graphicalToast(ctx, string, R.drawable.ic_toast_error, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void showToastInUiThread(final Context ctx, final int stringId) {
|
|
||||||
showToastInUiThread(ctx, ctx.getString(stringId));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void warnToast(final Context ctx, final String string) {
|
|
||||||
graphicalToast(ctx, string, R.drawable.ic_toast_warn, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void infoToast(final Context ctx, final String string) {
|
|
||||||
graphicalToast(ctx, string, R.drawable.ic_toast_info, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void okToast(final Context ctx, final String string) {
|
|
||||||
graphicalToast(ctx, string, R.drawable.ic_toast_check, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void errorToast(final Context ctx, final String string) {
|
|
||||||
graphicalToast(ctx, string, R.drawable.ic_toast_error, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void graphicalToast(final Context ctx, final String string, @DrawableRes int iconId) {
|
|
||||||
graphicalToast(ctx, string, iconId, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
|
||||||
public static void graphicalToast(final Context ctx, final String string, @DrawableRes int iconId, boolean isShort) {
|
|
||||||
Handler mainThread = new Handler(Looper.getMainLooper());
|
|
||||||
mainThread.post(() -> {
|
|
||||||
View toastRoot = LayoutInflater.from(new ContextThemeWrapper(ctx, R.style.AppTheme)).inflate(R.layout.toast, null);
|
|
||||||
TextView toastMessage = toastRoot.findViewById(android.R.id.message);
|
|
||||||
toastMessage.setText(string);
|
|
||||||
|
|
||||||
ImageView toastIcon = toastRoot.findViewById(android.R.id.icon);
|
|
||||||
toastIcon.setImageResource(iconId);
|
|
||||||
|
|
||||||
if (lastToast != null) lastToast.cancel();
|
|
||||||
lastToast = new Toast(ctx);
|
|
||||||
lastToast.setDuration(isShort ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG);
|
|
||||||
lastToast.setView(toastRoot);
|
|
||||||
lastToast.show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void showToastInUiThread(final Context ctx, final String string) {
|
|
||||||
Handler mainThread = new Handler(Looper.getMainLooper());
|
|
||||||
mainThread.post(() -> Toast.makeText(ctx, string, Toast.LENGTH_SHORT).show());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void showToastInUiThread(final Context ctx, final RxBus rxBus,
|
|
||||||
final String string, int soundID) {
|
|
||||||
|
|
||||||
showToastInUiThread(ctx, string);
|
|
||||||
playSound(ctx, soundID);
|
|
||||||
Notification notification = new Notification(Notification.TOAST_ALARM, string, Notification.URGENT);
|
|
||||||
rxBus.send(new EventNewNotification(notification));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void playSound(final Context ctx, final int soundID) {
|
|
||||||
final MediaPlayer soundMP = MediaPlayer.create(ctx, soundID);
|
|
||||||
soundMP.start();
|
|
||||||
soundMP.setOnCompletionListener(MediaPlayer::release);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
package info.nightscout.androidaps.utils
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.media.MediaPlayer
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.appcompat.view.ContextThemeWrapper
|
||||||
|
import info.nightscout.androidaps.core.R
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||||
|
|
||||||
|
object ToastUtils {
|
||||||
|
|
||||||
|
private var lastToast: Toast? = null
|
||||||
|
fun showToastInUiThread(ctx: Context, stringId: Int) {
|
||||||
|
showToastInUiThread(ctx, ctx.getString(stringId))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun warnToast(ctx: Context?, string: String?) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_warn, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun infoToast(ctx: Context?, string: String?) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_info, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun okToast(ctx: Context?, string: String?) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_check, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun errorToast(ctx: Context?, string: String?) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_error, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun graphicalToast(ctx: Context?, string: String?, @DrawableRes iconId: Int) {
|
||||||
|
graphicalToast(ctx, string, iconId, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("InflateParams")
|
||||||
|
fun graphicalToast(ctx: Context?, string: String?, @DrawableRes iconId: Int, isShort: Boolean) {
|
||||||
|
val mainThread = Handler(Looper.getMainLooper())
|
||||||
|
mainThread.post {
|
||||||
|
val toastRoot = LayoutInflater.from(ContextThemeWrapper(ctx, R.style.AppTheme)).inflate(R.layout.toast, null)
|
||||||
|
val toastMessage = toastRoot.findViewById<TextView>(android.R.id.message)
|
||||||
|
toastMessage.text = string
|
||||||
|
val toastIcon = toastRoot.findViewById<ImageView>(android.R.id.icon)
|
||||||
|
toastIcon.setImageResource(iconId)
|
||||||
|
lastToast?.cancel()
|
||||||
|
lastToast = Toast(ctx)
|
||||||
|
lastToast?.duration = if (isShort) Toast.LENGTH_SHORT else Toast.LENGTH_LONG
|
||||||
|
lastToast?.view = toastRoot
|
||||||
|
lastToast?.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showToastInUiThread(ctx: Context?, string: String?) {
|
||||||
|
val mainThread = Handler(Looper.getMainLooper())
|
||||||
|
mainThread.post { Toast.makeText(ctx, string, Toast.LENGTH_SHORT).show() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showToastInUiThread(
|
||||||
|
ctx: Context?, rxBus: RxBus,
|
||||||
|
string: String?, soundID: Int
|
||||||
|
) {
|
||||||
|
showToastInUiThread(ctx, string)
|
||||||
|
playSound(ctx, soundID)
|
||||||
|
val notification = Notification(Notification.TOAST_ALARM, string!!, Notification.URGENT)
|
||||||
|
rxBus.send(EventNewNotification(notification))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun playSound(ctx: Context?, soundID: Int) {
|
||||||
|
val soundMP = MediaPlayer.create(ctx, soundID)
|
||||||
|
soundMP.start()
|
||||||
|
soundMP.setOnCompletionListener { obj: MediaPlayer -> obj.release() }
|
||||||
|
}
|
||||||
|
|
||||||
|
object Long {
|
||||||
|
|
||||||
|
fun warnToast(ctx: Context?, string: String) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_warn, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun infoToast(ctx: Context?, string: String) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_info, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun okToast(ctx: Context?, string: String) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_check, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun errorToast(ctx: Context?, string: String) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_error, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,16 +13,16 @@ class MinutesNumberPicker constructor(context: Context, attrs: AttributeSet? = n
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateEditText() {
|
override fun updateEditText() {
|
||||||
if (value == 0.0 && !allowZero) editText.setText("")
|
if (currentValue == 0.0 && !allowZero) editText?.setText("")
|
||||||
else {
|
else {
|
||||||
if (focused) editText.setText(DecimalFormat("0").format(value))
|
if (focused) editText?.setText(DecimalFormat("0").format(currentValue))
|
||||||
else {
|
else {
|
||||||
val hours = (value / 60).toInt()
|
val hours = (currentValue / 60).toInt()
|
||||||
val minutes = (value - hours * 60).toInt()
|
val minutes = (currentValue - hours * 60).toInt()
|
||||||
val formatted =
|
val formatted =
|
||||||
if (hours != 0) String.format(context.getString(R.string.format_hour_minute), hours, minutes)
|
if (hours != 0) String.format(context.getString(R.string.format_hour_minute), hours, minutes)
|
||||||
else DecimalFormat("0").format(value)
|
else DecimalFormat("0").format(currentValue)
|
||||||
editText.setText(formatted)
|
editText?.setText(formatted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,343 +0,0 @@
|
||||||
package info.nightscout.androidaps.utils.ui;
|
|
||||||
|
|
||||||
import android.app.Service;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.text.Editable;
|
|
||||||
import android.text.TextWatcher;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.inputmethod.InputMethodManager;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.core.R;
|
|
||||||
import info.nightscout.androidaps.utils.SafeParse;
|
|
||||||
import info.nightscout.androidaps.utils.ToastUtils;
|
|
||||||
|
|
||||||
public class NumberPicker extends LinearLayout implements View.OnKeyListener,
|
|
||||||
View.OnTouchListener, View.OnClickListener {
|
|
||||||
|
|
||||||
public interface OnValueChangedListener {
|
|
||||||
void onValueChanged(double value);
|
|
||||||
}
|
|
||||||
|
|
||||||
EditText editText;
|
|
||||||
Button minusButton;
|
|
||||||
Button plusButton;
|
|
||||||
|
|
||||||
double value = 0;
|
|
||||||
double minValue = 0d;
|
|
||||||
double maxValue = 1d;
|
|
||||||
double step = 1d;
|
|
||||||
NumberFormat formatter;
|
|
||||||
boolean allowZero = false;
|
|
||||||
TextWatcher textWatcher = null;
|
|
||||||
|
|
||||||
Button okButton = null;
|
|
||||||
|
|
||||||
protected Boolean focused = false;
|
|
||||||
|
|
||||||
private Handler mHandler;
|
|
||||||
private ScheduledExecutorService mUpdater;
|
|
||||||
private OnValueChangedListener mOnValueChangedListener;
|
|
||||||
|
|
||||||
private class UpdateCounterTask implements Runnable {
|
|
||||||
private final boolean mInc;
|
|
||||||
private int repeated = 0;
|
|
||||||
private int multiplier = 1;
|
|
||||||
|
|
||||||
private final int doubleLimit = 5;
|
|
||||||
|
|
||||||
UpdateCounterTask(boolean inc) {
|
|
||||||
mInc = inc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
Message msg = new Message();
|
|
||||||
if (repeated % doubleLimit == 0) multiplier *= 2;
|
|
||||||
repeated++;
|
|
||||||
msg.arg1 = multiplier;
|
|
||||||
msg.arg2 = repeated;
|
|
||||||
if (mInc) {
|
|
||||||
msg.what = MSG_INC;
|
|
||||||
} else {
|
|
||||||
msg.what = MSG_DEC;
|
|
||||||
}
|
|
||||||
mHandler.sendMessage(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int MSG_INC = 0;
|
|
||||||
private static final int MSG_DEC = 1;
|
|
||||||
|
|
||||||
public NumberPicker(Context context) {
|
|
||||||
super(context, null);
|
|
||||||
this.initialize(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public NumberPicker(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
|
|
||||||
this.initialize(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void inflate(Context context) {
|
|
||||||
LayoutInflater.from(context).inflate(R.layout.number_picker_layout, this, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void initialize(Context context) {
|
|
||||||
// set layout view
|
|
||||||
inflate(context);
|
|
||||||
|
|
||||||
// init ui components
|
|
||||||
minusButton = findViewById(R.id.decrement);
|
|
||||||
minusButton.setId(View.generateViewId());
|
|
||||||
plusButton = findViewById(R.id.increment);
|
|
||||||
plusButton.setId(View.generateViewId());
|
|
||||||
editText = findViewById(R.id.display);
|
|
||||||
editText.setId(View.generateViewId());
|
|
||||||
|
|
||||||
mHandler = new Handler(msg -> {
|
|
||||||
switch (msg.what) {
|
|
||||||
case MSG_INC:
|
|
||||||
inc(msg.arg1);
|
|
||||||
return true;
|
|
||||||
case MSG_DEC:
|
|
||||||
dec(msg.arg1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
minusButton.setOnTouchListener(this);
|
|
||||||
minusButton.setOnKeyListener(this);
|
|
||||||
minusButton.setOnClickListener(this);
|
|
||||||
plusButton.setOnTouchListener(this);
|
|
||||||
plusButton.setOnKeyListener(this);
|
|
||||||
plusButton.setOnClickListener(this);
|
|
||||||
setTextWatcher(new TextWatcher() {
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
if (focused) value = SafeParse.stringToDouble(editText.getText().toString());
|
|
||||||
callValueChangedListener();
|
|
||||||
if (okButton != null) {
|
|
||||||
if (value > maxValue || value < minValue)
|
|
||||||
okButton.setVisibility(INVISIBLE);
|
|
||||||
else
|
|
||||||
okButton.setVisibility(VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
editText.setOnFocusChangeListener((v, hasFocus) -> {
|
|
||||||
focused = hasFocus;
|
|
||||||
if (!focused) getValue(); // check min/max
|
|
||||||
updateEditText();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTag(Object tag) {
|
|
||||||
editText.setTag(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnValueChangedListener(OnValueChangedListener onValueChangedListener) {
|
|
||||||
mOnValueChangedListener = onValueChangedListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTextWatcher(TextWatcher textWatcher) {
|
|
||||||
this.textWatcher = textWatcher;
|
|
||||||
editText.addTextChangedListener(textWatcher);
|
|
||||||
editText.setOnFocusChangeListener((v, hasFocus) -> {
|
|
||||||
if (!hasFocus) {
|
|
||||||
value = SafeParse.stringToDouble(editText.getText().toString());
|
|
||||||
if (value > maxValue) {
|
|
||||||
value = maxValue;
|
|
||||||
ToastUtils.showToastInUiThread(getContext(), getContext().getString(R.string.youareonallowedlimit));
|
|
||||||
updateEditText();
|
|
||||||
if (okButton != null)
|
|
||||||
okButton.setVisibility(VISIBLE);
|
|
||||||
}
|
|
||||||
if (value < minValue) {
|
|
||||||
value = minValue;
|
|
||||||
ToastUtils.showToastInUiThread(getContext(), getContext().getString(R.string.youareonallowedlimit));
|
|
||||||
updateEditText();
|
|
||||||
if (okButton != null)
|
|
||||||
okButton.setVisibility(VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setParams(Double initValue, Double minValue, Double maxValue, Double step, NumberFormat formatter, boolean allowZero, Button okButton, TextWatcher textWatcher) {
|
|
||||||
if (this.textWatcher != null) {
|
|
||||||
editText.removeTextChangedListener(this.textWatcher);
|
|
||||||
}
|
|
||||||
setParams(initValue, minValue, maxValue, step, formatter, allowZero, okButton);
|
|
||||||
this.textWatcher = textWatcher;
|
|
||||||
if (textWatcher != null)
|
|
||||||
editText.addTextChangedListener(textWatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setParams(Double initValue, Double minValue, Double maxValue, Double step, NumberFormat formatter, boolean allowZero, Button okButton) {
|
|
||||||
this.value = initValue;
|
|
||||||
this.minValue = minValue;
|
|
||||||
this.maxValue = maxValue;
|
|
||||||
this.step = step;
|
|
||||||
this.formatter = formatter;
|
|
||||||
this.allowZero = allowZero;
|
|
||||||
callValueChangedListener();
|
|
||||||
this.okButton = okButton;
|
|
||||||
|
|
||||||
editText.setKeyListener(DigitsKeyListenerWithComma.getInstance(minValue < 0, step != Math.rint(step)));
|
|
||||||
|
|
||||||
if (textWatcher != null)
|
|
||||||
editText.removeTextChangedListener(textWatcher);
|
|
||||||
updateEditText();
|
|
||||||
if (textWatcher != null)
|
|
||||||
editText.addTextChangedListener(textWatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(Double value) {
|
|
||||||
if (textWatcher != null)
|
|
||||||
editText.removeTextChangedListener(textWatcher);
|
|
||||||
this.value = value;
|
|
||||||
callValueChangedListener();
|
|
||||||
updateEditText();
|
|
||||||
if (textWatcher != null)
|
|
||||||
editText.addTextChangedListener(textWatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getValue() {
|
|
||||||
if (value > maxValue) {
|
|
||||||
value = maxValue;
|
|
||||||
ToastUtils.showToastInUiThread(getContext(), getContext().getString(R.string.youareonallowedlimit));
|
|
||||||
}
|
|
||||||
if (value < minValue) {
|
|
||||||
value = minValue;
|
|
||||||
ToastUtils.showToastInUiThread(getContext(), getContext().getString(R.string.youareonallowedlimit));
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getText() {
|
|
||||||
return editText.getText().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStep(Double step) {
|
|
||||||
this.step = step;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void inc(int multiplier) {
|
|
||||||
value += step * multiplier;
|
|
||||||
if (value > maxValue) {
|
|
||||||
value = maxValue;
|
|
||||||
callValueChangedListener();
|
|
||||||
ToastUtils.showToastInUiThread(getContext(), getContext().getString(R.string.youareonallowedlimit));
|
|
||||||
stopUpdating();
|
|
||||||
}
|
|
||||||
updateEditText();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dec(int multiplier) {
|
|
||||||
value -= step * multiplier;
|
|
||||||
if (value < minValue) {
|
|
||||||
value = minValue;
|
|
||||||
callValueChangedListener();
|
|
||||||
ToastUtils.showToastInUiThread(getContext(), getContext().getString(R.string.youareonallowedlimit));
|
|
||||||
stopUpdating();
|
|
||||||
}
|
|
||||||
updateEditText();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void updateEditText() {
|
|
||||||
if (value == 0d && !allowZero)
|
|
||||||
editText.setText("");
|
|
||||||
else
|
|
||||||
editText.setText(formatter.format(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void callValueChangedListener() {
|
|
||||||
if (mOnValueChangedListener != null)
|
|
||||||
mOnValueChangedListener.onValueChanged(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startUpdating(boolean inc) {
|
|
||||||
if (mUpdater != null) {
|
|
||||||
//log.debug("Another executor is still active");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mUpdater = Executors.newSingleThreadScheduledExecutor();
|
|
||||||
mUpdater.scheduleAtFixedRate(new UpdateCounterTask(inc), 200, 200,
|
|
||||||
TimeUnit.MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopUpdating() {
|
|
||||||
if (mUpdater != null) {
|
|
||||||
mUpdater.shutdownNow();
|
|
||||||
mUpdater = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (mUpdater == null) {
|
|
||||||
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Service.INPUT_METHOD_SERVICE);
|
|
||||||
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
|
|
||||||
editText.clearFocus();
|
|
||||||
if (v == plusButton) {
|
|
||||||
inc(1);
|
|
||||||
} else {
|
|
||||||
dec(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
|
||||||
boolean isKeyOfInterest = keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER;
|
|
||||||
boolean isReleased = event.getAction() == KeyEvent.ACTION_UP;
|
|
||||||
boolean isPressed = event.getAction() == KeyEvent.ACTION_DOWN
|
|
||||||
&& event.getAction() != KeyEvent.ACTION_MULTIPLE;
|
|
||||||
|
|
||||||
if (isKeyOfInterest && isReleased) {
|
|
||||||
stopUpdating();
|
|
||||||
} else if (isKeyOfInterest && isPressed) {
|
|
||||||
startUpdating(v == plusButton);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
|
||||||
boolean isReleased = event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL;
|
|
||||||
boolean isPressed = event.getAction() == MotionEvent.ACTION_DOWN;
|
|
||||||
|
|
||||||
if (isReleased) {
|
|
||||||
stopUpdating();
|
|
||||||
} else if (isPressed) {
|
|
||||||
startUpdating(v == plusButton);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,295 @@
|
||||||
|
package info.nightscout.androidaps.utils.ui
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.os.Message
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.TextWatcher
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.view.View
|
||||||
|
import android.view.View.OnFocusChangeListener
|
||||||
|
import android.view.View.OnTouchListener
|
||||||
|
import android.view.inputmethod.InputMethodManager
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import info.nightscout.androidaps.core.R
|
||||||
|
import info.nightscout.androidaps.utils.SafeParse
|
||||||
|
import info.nightscout.androidaps.utils.ToastUtils
|
||||||
|
import java.text.NumberFormat
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.ScheduledExecutorService
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import kotlin.math.round
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs), View.OnKeyListener, OnTouchListener, View.OnClickListener {
|
||||||
|
|
||||||
|
fun interface OnValueChangedListener {
|
||||||
|
|
||||||
|
fun onValueChanged(value: Double)
|
||||||
|
}
|
||||||
|
|
||||||
|
var editText: EditText? = null
|
||||||
|
private var minusButton: Button? = null
|
||||||
|
private var plusButton: Button? = null
|
||||||
|
var currentValue = 0.0
|
||||||
|
var minValue = 0.0
|
||||||
|
var maxValue = 1.0
|
||||||
|
var step = 1.0
|
||||||
|
var formatter: NumberFormat? = null
|
||||||
|
var allowZero = false
|
||||||
|
private var watcher: TextWatcher? = null
|
||||||
|
var okButton: Button? = null
|
||||||
|
protected var focused = false
|
||||||
|
private var mUpdater: ScheduledExecutorService? = null
|
||||||
|
private var mOnValueChangedListener: OnValueChangedListener? = null
|
||||||
|
|
||||||
|
private var mHandler: Handler = Handler(Looper.getMainLooper(), Handler.Callback { msg: Message ->
|
||||||
|
when (msg.what) {
|
||||||
|
MSG_INC -> {
|
||||||
|
inc(msg.arg1)
|
||||||
|
return@Callback true
|
||||||
|
}
|
||||||
|
|
||||||
|
MSG_DEC -> {
|
||||||
|
dec(msg.arg1)
|
||||||
|
return@Callback true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
|
||||||
|
private inner class UpdateCounterTask(private val mInc: Boolean) : Runnable {
|
||||||
|
|
||||||
|
private var repeated = 0
|
||||||
|
private var multiplier = 1
|
||||||
|
private val doubleLimit = 5
|
||||||
|
override fun run() {
|
||||||
|
val msg = Message()
|
||||||
|
if (repeated % doubleLimit == 0) multiplier *= 2
|
||||||
|
repeated++
|
||||||
|
msg.arg1 = multiplier
|
||||||
|
msg.arg2 = repeated
|
||||||
|
if (mInc) {
|
||||||
|
msg.what = MSG_INC
|
||||||
|
} else {
|
||||||
|
msg.what = MSG_DEC
|
||||||
|
}
|
||||||
|
mHandler.sendMessage(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun inflate(context: Context) {
|
||||||
|
LayoutInflater.from(context).inflate(R.layout.number_picker_layout, this, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun initialize(context: Context) {
|
||||||
|
// set layout view
|
||||||
|
inflate(context)
|
||||||
|
|
||||||
|
// init ui components
|
||||||
|
minusButton = findViewById(R.id.decrement)
|
||||||
|
minusButton?.id = generateViewId()
|
||||||
|
plusButton = findViewById(R.id.increment)
|
||||||
|
plusButton?.id = generateViewId()
|
||||||
|
editText = findViewById(R.id.display)
|
||||||
|
editText?.id = generateViewId()
|
||||||
|
minusButton?.setOnTouchListener(this)
|
||||||
|
minusButton?.setOnKeyListener(this)
|
||||||
|
minusButton?.setOnClickListener(this)
|
||||||
|
plusButton?.setOnTouchListener(this)
|
||||||
|
plusButton?.setOnKeyListener(this)
|
||||||
|
plusButton?.setOnClickListener(this)
|
||||||
|
setTextWatcher(object : TextWatcher {
|
||||||
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||||
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
|
||||||
|
override fun afterTextChanged(s: Editable) {
|
||||||
|
if (focused) currentValue = SafeParse.stringToDouble(editText?.text.toString())
|
||||||
|
callValueChangedListener()
|
||||||
|
okButton?.visibility = if (currentValue > maxValue || currentValue < minValue) INVISIBLE else VISIBLE
|
||||||
|
}
|
||||||
|
})
|
||||||
|
editText?.setOnFocusChangeListener { _: View?, hasFocus: Boolean ->
|
||||||
|
focused = hasFocus
|
||||||
|
if (!focused) value // check min/max
|
||||||
|
updateEditText()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setTag(tag: Any) {
|
||||||
|
editText?.tag = tag
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOnValueChangedListener(onValueChangedListener: OnValueChangedListener?) {
|
||||||
|
mOnValueChangedListener = onValueChangedListener
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTextWatcher(textWatcher: TextWatcher) {
|
||||||
|
watcher = textWatcher
|
||||||
|
editText?.addTextChangedListener(textWatcher)
|
||||||
|
editText?.onFocusChangeListener = OnFocusChangeListener { _: View?, hasFocus: Boolean ->
|
||||||
|
if (!hasFocus) {
|
||||||
|
currentValue = SafeParse.stringToDouble(editText?.text.toString())
|
||||||
|
if (currentValue > maxValue) {
|
||||||
|
currentValue = maxValue
|
||||||
|
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
|
||||||
|
updateEditText()
|
||||||
|
okButton?.visibility = VISIBLE
|
||||||
|
}
|
||||||
|
if (currentValue < minValue) {
|
||||||
|
currentValue = minValue
|
||||||
|
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
|
||||||
|
updateEditText()
|
||||||
|
okButton?.visibility = VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setParams(initValue: Double, minValue: Double, maxValue: Double, step: Double, formatter: NumberFormat?, allowZero: Boolean, okButton: Button?, textWatcher: TextWatcher?) {
|
||||||
|
if (watcher != null) {
|
||||||
|
editText?.removeTextChangedListener(watcher)
|
||||||
|
}
|
||||||
|
setParams(initValue, minValue, maxValue, step, formatter, allowZero, okButton)
|
||||||
|
watcher = textWatcher
|
||||||
|
if (textWatcher != null) editText?.addTextChangedListener(textWatcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setParams(initValue: Double, minValue: Double, maxValue: Double, step: Double, formatter: NumberFormat?, allowZero: Boolean, okButton: Button?) {
|
||||||
|
currentValue = initValue
|
||||||
|
this.minValue = minValue
|
||||||
|
this.maxValue = maxValue
|
||||||
|
this.step = step
|
||||||
|
this.formatter = formatter
|
||||||
|
this.allowZero = allowZero
|
||||||
|
callValueChangedListener()
|
||||||
|
this.okButton = okButton
|
||||||
|
editText?.keyListener = DigitsKeyListenerWithComma.getInstance(minValue < 0, step != round(step))
|
||||||
|
if (watcher != null) editText?.removeTextChangedListener(watcher)
|
||||||
|
updateEditText()
|
||||||
|
if (watcher != null) editText?.addTextChangedListener(watcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
var value: Double
|
||||||
|
get() {
|
||||||
|
if (currentValue > maxValue) {
|
||||||
|
currentValue = maxValue
|
||||||
|
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
|
||||||
|
}
|
||||||
|
if (currentValue < minValue) {
|
||||||
|
currentValue = minValue
|
||||||
|
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
|
||||||
|
}
|
||||||
|
return currentValue
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
if (watcher != null) editText?.removeTextChangedListener(watcher)
|
||||||
|
currentValue = value
|
||||||
|
callValueChangedListener()
|
||||||
|
updateEditText()
|
||||||
|
if (watcher != null) editText?.addTextChangedListener(watcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
val text: String
|
||||||
|
get() = editText?.text.toString()
|
||||||
|
|
||||||
|
private fun inc(multiplier: Int) {
|
||||||
|
currentValue += step * multiplier
|
||||||
|
if (currentValue > maxValue) {
|
||||||
|
currentValue = maxValue
|
||||||
|
callValueChangedListener()
|
||||||
|
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
|
||||||
|
stopUpdating()
|
||||||
|
}
|
||||||
|
updateEditText()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dec(multiplier: Int) {
|
||||||
|
currentValue -= step * multiplier
|
||||||
|
if (currentValue < minValue) {
|
||||||
|
currentValue = minValue
|
||||||
|
callValueChangedListener()
|
||||||
|
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
|
||||||
|
stopUpdating()
|
||||||
|
}
|
||||||
|
updateEditText()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun updateEditText() {
|
||||||
|
if (currentValue == 0.0 && !allowZero) editText?.setText("") else editText?.setText(formatter?.format(currentValue))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun callValueChangedListener() {
|
||||||
|
mOnValueChangedListener?.onValueChanged(currentValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startUpdating(inc: Boolean) {
|
||||||
|
if (mUpdater != null) {
|
||||||
|
//log.debug("Another executor is still active");
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mUpdater = Executors.newSingleThreadScheduledExecutor()
|
||||||
|
mUpdater?.scheduleAtFixedRate(
|
||||||
|
UpdateCounterTask(inc), 200, 200,
|
||||||
|
TimeUnit.MILLISECONDS
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopUpdating() {
|
||||||
|
mUpdater?.shutdownNow()
|
||||||
|
mUpdater = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(v: View) {
|
||||||
|
if (mUpdater == null) {
|
||||||
|
val imm = context.getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
|
imm.hideSoftInputFromWindow(editText?.windowToken, 0)
|
||||||
|
editText?.clearFocus()
|
||||||
|
if (v === plusButton) {
|
||||||
|
inc(1)
|
||||||
|
} else {
|
||||||
|
dec(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onKey(v: View, keyCode: Int, event: KeyEvent): Boolean {
|
||||||
|
val isKeyOfInterest = keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER
|
||||||
|
val isReleased = event.action == KeyEvent.ACTION_UP
|
||||||
|
val isPressed = (event.action == KeyEvent.ACTION_DOWN)
|
||||||
|
if (isKeyOfInterest && isReleased) {
|
||||||
|
stopUpdating()
|
||||||
|
} else if (isKeyOfInterest && isPressed) {
|
||||||
|
startUpdating(v === plusButton)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
||||||
|
val isReleased = event.action == MotionEvent.ACTION_UP || event.action == MotionEvent.ACTION_CANCEL
|
||||||
|
val isPressed = event.action == MotionEvent.ACTION_DOWN
|
||||||
|
if (isReleased) {
|
||||||
|
stopUpdating()
|
||||||
|
} else if (isPressed) {
|
||||||
|
startUpdating(v === plusButton)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val MSG_INC = 0
|
||||||
|
private const val MSG_DEC = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
initialize(context)
|
||||||
|
}
|
||||||
|
}
|
|
@ -504,7 +504,22 @@
|
||||||
<string name="basal_value">Basal value</string>
|
<string name="basal_value">Basal value</string>
|
||||||
<string name="nsclient_version_does_not_match">NSClient version doesn\'t match to AndroidAPS. Please update.</string>
|
<string name="nsclient_version_does_not_match">NSClient version doesn\'t match to AndroidAPS. Please update.</string>
|
||||||
|
|
||||||
<!-- readStatus reasons -->
|
<!-- Command Queue + readStatus reasons -->
|
||||||
|
<string name="bolus_u_min">BOLUS %1$.2f U</string>
|
||||||
|
<string name="carbs_g">CARBS %1$d g</string>
|
||||||
|
<string name="extended_bolus_u_min">EXTENDED BOLUS %1$.2f U %2$d min</string>
|
||||||
|
<string name="load_events">LOAD EVENTS</string>
|
||||||
|
<string name="load_history">LOAD HISTORY %1$d</string>
|
||||||
|
<string name="load_tdds">LOAD TDDs</string>
|
||||||
|
<string name="set_profile">SET PROFILE</string>
|
||||||
|
<string name="set_user_settings">SET USER SETTINGS</string>
|
||||||
|
<string name="smb_bolus_u">SMB BOLUS %1$.2f U</string>
|
||||||
|
<string name="start_pump">START PUMP</string>
|
||||||
|
<string name="stop_pump">STOP PUMP</string>
|
||||||
|
<string name="temp_basal_absolute">TEMP BASAL %1$.2f U/h %2$d min</string>
|
||||||
|
<string name="temp_basal_percent">TEMP BASAL %1$d%% %2$d min</string>
|
||||||
|
<string name="insight_set_tbr_over_notification">INSIGHT SET TBR OVER NOTIFICATION</string>
|
||||||
|
<string name="read_status" comment="10 characters max for READSTATUS translation">READSTATUS %1$s</string>
|
||||||
<string name="keepalive_status_outdated" comment="26 characters max for translation">KeepAlive. Status outdated.</string>
|
<string name="keepalive_status_outdated" comment="26 characters max for translation">KeepAlive. Status outdated.</string>
|
||||||
<string name="keepalive_basal_outdated" comment="26 characters max for translation">KeepAlive. Basal outdated.</string>
|
<string name="keepalive_basal_outdated" comment="26 characters max for translation">KeepAlive. Basal outdated.</string>
|
||||||
<string name="sms" comment="26 characters max for translation">SMS</string>
|
<string name="sms" comment="26 characters max for translation">SMS</string>
|
||||||
|
@ -520,7 +535,6 @@
|
||||||
<string name="bolus_ok" comment="26 characters max for translation">Bolus OK</string>
|
<string name="bolus_ok" comment="26 characters max for translation">Bolus OK</string>
|
||||||
<string name="pump_paired" comment="26 characters max for translation">Pump paired</string>
|
<string name="pump_paired" comment="26 characters max for translation">Pump paired</string>
|
||||||
<string name="insight_refresh_button" comment="26 characters max for translation">Insight Refresh Button</string>
|
<string name="insight_refresh_button" comment="26 characters max for translation">Insight Refresh Button</string>
|
||||||
<string name="read_status" comment="10 characters max for READSTATUS translation">READSTATUS %1$s</string>
|
|
||||||
|
|
||||||
<plurals name="days">
|
<plurals name="days">
|
||||||
<item quantity="one">%1$d day</item>
|
<item quantity="one">%1$d day</item>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package info.nightscout.androidaps.danaRKorean.comm
|
package info.nightscout.androidaps.danaRKorean.comm
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.dana.DanaPump
|
||||||
import info.nightscout.androidaps.danar.R
|
import info.nightscout.androidaps.danar.R
|
||||||
import info.nightscout.androidaps.danar.comm.MessageBase
|
import info.nightscout.androidaps.danar.comm.MessageBase
|
||||||
import info.nightscout.androidaps.events.EventRebuildTabs
|
import info.nightscout.androidaps.events.EventRebuildTabs
|
||||||
|
|
|
@ -207,10 +207,12 @@ public abstract class AbstractDanaRExecutionService extends DaggerService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ToastUtils.showToastInUiThread(context.getApplicationContext(), rh.gs(R.string.nobtadapter));
|
ToastUtils.INSTANCE.showToastInUiThread(context.getApplicationContext(),
|
||||||
|
rh.gs(R.string.nobtadapter));
|
||||||
}
|
}
|
||||||
if (mBTDevice == null) {
|
if (mBTDevice == null) {
|
||||||
ToastUtils.showToastInUiThread(context.getApplicationContext(), rh.gs(R.string.devicenotfound));
|
ToastUtils.INSTANCE.showToastInUiThread(context.getApplicationContext(),
|
||||||
|
rh.gs(R.string.devicenotfound));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,17 @@ import info.nightscout.androidaps.dana.DanaPump
|
||||||
import info.nightscout.androidaps.danars.encryption.BleEncryption
|
import info.nightscout.androidaps.danars.encryption.BleEncryption
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
class DanaRSPacketGeneralInitialScreenInformation(
|
class DanaRSPacketGeneralInitialScreenInformation(
|
||||||
injector: HasAndroidInjector
|
injector: HasAndroidInjector
|
||||||
) : DanaRSPacket(injector) {
|
) : DanaRSPacket(injector) {
|
||||||
|
|
||||||
@Inject lateinit var danaPump: DanaPump
|
@Inject lateinit var danaPump: DanaPump
|
||||||
|
|
||||||
|
var isTempBasalInProgress = false
|
||||||
|
var isExtendedInProgress = false
|
||||||
|
var isDualBolusInProgress = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
opCode = BleEncryption.DANAR_PACKET__OPCODE_REVIEW__INITIAL_SCREEN_INFORMATION
|
opCode = BleEncryption.DANAR_PACKET__OPCODE_REVIEW__INITIAL_SCREEN_INFORMATION
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "New message")
|
aapsLogger.debug(LTag.PUMPCOMM, "New message")
|
||||||
|
@ -22,42 +27,22 @@ class DanaRSPacketGeneralInitialScreenInformation(
|
||||||
failed = true
|
failed = true
|
||||||
return
|
return
|
||||||
} else failed = false
|
} else failed = false
|
||||||
var dataIndex = DATA_START
|
val status = intFromBuff(data, 0, 1)
|
||||||
var dataSize = 1
|
|
||||||
val status = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
danaPump.pumpSuspended = status and 0x01 == 0x01
|
danaPump.pumpSuspended = status and 0x01 == 0x01
|
||||||
val isTempBasalInProgress = status and 0x10 == 0x10
|
isTempBasalInProgress = status and 0x10 == 0x10
|
||||||
val isExtendedInProgress = status and 0x04 == 0x04
|
isExtendedInProgress = status and 0x04 == 0x04
|
||||||
val isDualBolusInProgress = status and 0x08 == 0x08
|
isDualBolusInProgress = status and 0x08 == 0x08
|
||||||
dataIndex += dataSize
|
danaPump.dailyTotalUnits = intFromBuff(data, 1, 2) / 100.0
|
||||||
dataSize = 2
|
danaPump.maxDailyTotalUnits = intFromBuff(data, 3, 2) / 100
|
||||||
danaPump.dailyTotalUnits = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0
|
danaPump.reservoirRemainingUnits = intFromBuff(data, 5, 2) / 100.0
|
||||||
dataIndex += dataSize
|
danaPump.currentBasal = intFromBuff(data, 7, 2) / 100.0
|
||||||
dataSize = 2
|
val tempBasalPercent = intFromBuff(data, 9, 1)
|
||||||
danaPump.maxDailyTotalUnits = (byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0).toInt()
|
danaPump.batteryRemaining = intFromBuff(data, 10, 1)
|
||||||
dataIndex += dataSize
|
val extendedBolusAbsoluteRate = intFromBuff(data, 11, 2) / 100.0
|
||||||
dataSize = 2
|
danaPump.iob = intFromBuff(data, 13, 2) / 100.0
|
||||||
danaPump.reservoirRemainingUnits = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 2
|
|
||||||
danaPump.currentBasal = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 1
|
|
||||||
val tempBasalPercent = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 1
|
|
||||||
danaPump.batteryRemaining = byteArrayToInt(getBytes(data, dataIndex, dataSize))
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 2
|
|
||||||
val extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0
|
|
||||||
dataIndex += dataSize
|
|
||||||
dataSize = 2
|
|
||||||
danaPump.iob = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100.0
|
|
||||||
if (data.size >= 18) {
|
if (data.size >= 18) {
|
||||||
//protocol 10+
|
//protocol 10+
|
||||||
dataIndex += dataSize
|
danaPump.errorState = DanaPump.ErrorState[intFromBuff(data, 15, 1)]
|
||||||
dataSize = 1
|
|
||||||
danaPump.errorState = DanaPump.ErrorState[byteArrayToInt(getBytes(data, dataIndex, dataSize))]
|
|
||||||
?: DanaPump.ErrorState.NONE
|
?: DanaPump.ErrorState.NONE
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "ErrorState: " + danaPump.errorState.name)
|
aapsLogger.debug(LTag.PUMPCOMM, "ErrorState: " + danaPump.errorState.name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,7 +338,9 @@ class DanaRSService : DaggerService() {
|
||||||
|
|
||||||
fun tempBasal(percent: Int, durationInHours: Int): Boolean {
|
fun tempBasal(percent: Int, durationInHours: Int): Boolean {
|
||||||
if (!isConnected) return false
|
if (!isConnected) return false
|
||||||
if (danaPump.isTempBasalInProgress) {
|
val status = DanaRSPacketGeneralInitialScreenInformation(injector)
|
||||||
|
sendMessage(status)
|
||||||
|
if (status.isTempBasalInProgress) {
|
||||||
rxBus.send(EventPumpStatusChanged(rh.gs(R.string.stoppingtempbasal)))
|
rxBus.send(EventPumpStatusChanged(rh.gs(R.string.stoppingtempbasal)))
|
||||||
sendMessage(DanaRSPacketBasalSetCancelTemporaryBasal(injector))
|
sendMessage(DanaRSPacketBasalSetCancelTemporaryBasal(injector))
|
||||||
SystemClock.sleep(500)
|
SystemClock.sleep(500)
|
||||||
|
@ -348,6 +350,7 @@ class DanaRSService : DaggerService() {
|
||||||
sendMessage(msgTBR)
|
sendMessage(msgTBR)
|
||||||
SystemClock.sleep(200)
|
SystemClock.sleep(200)
|
||||||
loadEvents()
|
loadEvents()
|
||||||
|
SystemClock.sleep(4500)
|
||||||
val tbr = pumpSync.expectedPumpState().temporaryBasal
|
val tbr = pumpSync.expectedPumpState().temporaryBasal
|
||||||
danaPump.fromTemporaryBasal(tbr)
|
danaPump.fromTemporaryBasal(tbr)
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
|
||||||
|
@ -355,7 +358,9 @@ class DanaRSService : DaggerService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun highTempBasal(percent: Int): Boolean {
|
fun highTempBasal(percent: Int): Boolean {
|
||||||
if (danaPump.isTempBasalInProgress) {
|
val status = DanaRSPacketGeneralInitialScreenInformation(injector)
|
||||||
|
sendMessage(status)
|
||||||
|
if (status.isTempBasalInProgress) {
|
||||||
rxBus.send(EventPumpStatusChanged(rh.gs(R.string.stoppingtempbasal)))
|
rxBus.send(EventPumpStatusChanged(rh.gs(R.string.stoppingtempbasal)))
|
||||||
sendMessage(DanaRSPacketBasalSetCancelTemporaryBasal(injector))
|
sendMessage(DanaRSPacketBasalSetCancelTemporaryBasal(injector))
|
||||||
SystemClock.sleep(500)
|
SystemClock.sleep(500)
|
||||||
|
@ -364,6 +369,7 @@ class DanaRSService : DaggerService() {
|
||||||
val msgTBR = DanaRSPacketAPSBasalSetTemporaryBasal(injector, percent)
|
val msgTBR = DanaRSPacketAPSBasalSetTemporaryBasal(injector, percent)
|
||||||
sendMessage(msgTBR)
|
sendMessage(msgTBR)
|
||||||
loadEvents()
|
loadEvents()
|
||||||
|
SystemClock.sleep(4500)
|
||||||
val tbr = pumpSync.expectedPumpState().temporaryBasal
|
val tbr = pumpSync.expectedPumpState().temporaryBasal
|
||||||
danaPump.fromTemporaryBasal(tbr)
|
danaPump.fromTemporaryBasal(tbr)
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
|
||||||
|
@ -375,7 +381,9 @@ class DanaRSService : DaggerService() {
|
||||||
aapsLogger.error(LTag.PUMPCOMM, "Wrong duration param")
|
aapsLogger.error(LTag.PUMPCOMM, "Wrong duration param")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (danaPump.isTempBasalInProgress) {
|
val status = DanaRSPacketGeneralInitialScreenInformation(injector)
|
||||||
|
sendMessage(status)
|
||||||
|
if (status.isTempBasalInProgress) {
|
||||||
rxBus.send(EventPumpStatusChanged(rh.gs(R.string.stoppingtempbasal)))
|
rxBus.send(EventPumpStatusChanged(rh.gs(R.string.stoppingtempbasal)))
|
||||||
sendMessage(DanaRSPacketBasalSetCancelTemporaryBasal(injector))
|
sendMessage(DanaRSPacketBasalSetCancelTemporaryBasal(injector))
|
||||||
SystemClock.sleep(500)
|
SystemClock.sleep(500)
|
||||||
|
@ -384,6 +392,7 @@ class DanaRSService : DaggerService() {
|
||||||
val msgTBR = DanaRSPacketAPSBasalSetTemporaryBasal(injector, percent)
|
val msgTBR = DanaRSPacketAPSBasalSetTemporaryBasal(injector, percent)
|
||||||
sendMessage(msgTBR)
|
sendMessage(msgTBR)
|
||||||
loadEvents()
|
loadEvents()
|
||||||
|
SystemClock.sleep(4500)
|
||||||
val tbr = pumpSync.expectedPumpState().temporaryBasal
|
val tbr = pumpSync.expectedPumpState().temporaryBasal
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "Expected TBR found: $tbr")
|
aapsLogger.debug(LTag.PUMPCOMM, "Expected TBR found: $tbr")
|
||||||
danaPump.fromTemporaryBasal(tbr)
|
danaPump.fromTemporaryBasal(tbr)
|
||||||
|
@ -397,6 +406,7 @@ class DanaRSService : DaggerService() {
|
||||||
val msgCancel = DanaRSPacketBasalSetCancelTemporaryBasal(injector)
|
val msgCancel = DanaRSPacketBasalSetCancelTemporaryBasal(injector)
|
||||||
sendMessage(msgCancel)
|
sendMessage(msgCancel)
|
||||||
loadEvents()
|
loadEvents()
|
||||||
|
SystemClock.sleep(4500)
|
||||||
val tbr = pumpSync.expectedPumpState().temporaryBasal
|
val tbr = pumpSync.expectedPumpState().temporaryBasal
|
||||||
danaPump.fromTemporaryBasal(tbr)
|
danaPump.fromTemporaryBasal(tbr)
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
|
||||||
|
@ -410,6 +420,7 @@ class DanaRSService : DaggerService() {
|
||||||
sendMessage(msgExtended)
|
sendMessage(msgExtended)
|
||||||
SystemClock.sleep(200)
|
SystemClock.sleep(200)
|
||||||
loadEvents()
|
loadEvents()
|
||||||
|
SystemClock.sleep(4500)
|
||||||
val eb = pumpSync.expectedPumpState().extendedBolus
|
val eb = pumpSync.expectedPumpState().extendedBolus
|
||||||
danaPump.fromExtendedBolus(eb)
|
danaPump.fromExtendedBolus(eb)
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
|
||||||
|
@ -422,6 +433,7 @@ class DanaRSService : DaggerService() {
|
||||||
val msgStop = DanaRSPacketBolusSetExtendedBolusCancel(injector)
|
val msgStop = DanaRSPacketBolusSetExtendedBolusCancel(injector)
|
||||||
sendMessage(msgStop)
|
sendMessage(msgStop)
|
||||||
loadEvents()
|
loadEvents()
|
||||||
|
SystemClock.sleep(4500)
|
||||||
val eb = pumpSync.expectedPumpState().extendedBolus
|
val eb = pumpSync.expectedPumpState().extendedBolus
|
||||||
danaPump.fromExtendedBolus(eb)
|
danaPump.fromExtendedBolus(eb)
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTING))
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.common.queue.command
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.queue.commands.CustomCommand
|
||||||
|
|
||||||
|
class CommandDisableSuspendAlerts: CustomCommand {
|
||||||
|
|
||||||
|
override val statusDescription: String
|
||||||
|
get() = "DISABLE SUSPEND ALERTS"
|
||||||
|
}
|
|
@ -502,7 +502,10 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
// prevent setBasal requests
|
// prevent setBasal requests
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// TODO: what do we have to answer here if delivery is suspended?
|
if (podStateManager.isSuspended) {
|
||||||
|
// set new basal profile failed midway
|
||||||
|
return false
|
||||||
|
}
|
||||||
val running = podStateManager.basalProgram
|
val running = podStateManager.basalProgram
|
||||||
val equal = (mapProfileToBasalProgram(profile) == running)
|
val equal = (mapProfileToBasalProgram(profile) == running)
|
||||||
aapsLogger.info(LTag.PUMP, "set: $equal. profile=$profile, running=$running")
|
aapsLogger.info(LTag.PUMP, "set: $equal. profile=$profile, running=$running")
|
||||||
|
@ -1089,8 +1092,6 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
return when (customCommand) {
|
return when (customCommand) {
|
||||||
is CommandSilenceAlerts ->
|
is CommandSilenceAlerts ->
|
||||||
silenceAlerts()
|
silenceAlerts()
|
||||||
is CommandSuspendDelivery ->
|
|
||||||
suspendDelivery()
|
|
||||||
is CommandResumeDelivery ->
|
is CommandResumeDelivery ->
|
||||||
resumeDelivery()
|
resumeDelivery()
|
||||||
is CommandDeactivatePod ->
|
is CommandDeactivatePod ->
|
||||||
|
@ -1101,7 +1102,8 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
updateAlertConfiguration()
|
updateAlertConfiguration()
|
||||||
is CommandPlayTestBeep ->
|
is CommandPlayTestBeep ->
|
||||||
playTestBeep()
|
playTestBeep()
|
||||||
|
is CommandDisableSuspendAlerts ->
|
||||||
|
disableSuspendAlerts()
|
||||||
else -> {
|
else -> {
|
||||||
aapsLogger.warn(LTag.PUMP, "Unsupported custom command: " + customCommand.javaClass.name)
|
aapsLogger.warn(LTag.PUMP, "Unsupported custom command: " + customCommand.javaClass.name)
|
||||||
PumpEnactResult(injector).success(false).enacted(false).comment(
|
PumpEnactResult(injector).success(false).enacted(false).comment(
|
||||||
|
@ -1124,27 +1126,28 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
} ?: PumpEnactResult(injector).success(false).enacted(false).comment("No active alerts") // TODO i18n
|
} ?: PumpEnactResult(injector).success(false).enacted(false).comment("No active alerts") // TODO i18n
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun suspendDelivery(): PumpEnactResult {
|
private fun disableSuspendAlerts(): PumpEnactResult {
|
||||||
return executeProgrammingCommand(
|
val alerts = listOf(
|
||||||
historyEntry = history.createRecord(OmnipodCommandType.SUSPEND_DELIVERY),
|
AlertConfiguration(
|
||||||
command = omnipodManager.suspendDelivery(hasBasalBeepEnabled())
|
AlertType.SUSPEND_ENDED,
|
||||||
.filter { podEvent -> podEvent.isCommandSent() }
|
enabled = false,
|
||||||
.map {
|
durationInMinutes = 0,
|
||||||
pumpSyncTempBasal(
|
autoOff = false,
|
||||||
0.0,
|
AlertTrigger.TimerTrigger(
|
||||||
PodConstants.MAX_POD_LIFETIME.toMinutes(),
|
0
|
||||||
PumpSync.TemporaryBasalType.PUMP_SUSPEND
|
),
|
||||||
)
|
BeepType.FOUR_TIMES_BIP_BEEP,
|
||||||
}
|
BeepRepetitionType.EVERY_MINUTE_AND_EVERY_15_MIN
|
||||||
.ignoreElements(),
|
),
|
||||||
pre = observeDeliveryActive(),
|
)
|
||||||
).doFinally {
|
val ret = executeProgrammingCommand(
|
||||||
notifyOnUnconfirmed(
|
historyEntry = history.createRecord(OmnipodCommandType.CONFIGURE_ALERTS),
|
||||||
Notification.PUMP_ERROR,
|
command = omnipodManager.programAlerts(alerts).ignoreElements(),
|
||||||
"Unconfirmed suspendDelivery command. Please refresh pod status",
|
).toPumpEnactResult()
|
||||||
R.raw.boluserror
|
if (ret.success && ret.enacted) {
|
||||||
)
|
podStateManager.suspendAlertsEnabled = false
|
||||||
}.toPumpEnactResult()
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeDeliveryActive(): Completable = Completable.defer {
|
private fun observeDeliveryActive(): Completable = Completable.defer {
|
||||||
|
@ -1249,7 +1252,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
expiryAlertDelay.toMinutes().toShort()
|
expiryAlertDelay.toMinutes().toShort()
|
||||||
),
|
),
|
||||||
BeepType.FOUR_TIMES_BIP_BEEP,
|
BeepType.FOUR_TIMES_BIP_BEEP,
|
||||||
BeepRepetitionType.XXX2
|
BeepRepetitionType.EVERY_MINUTE_AND_EVERY_15_MIN
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return executeProgrammingCommand(
|
return executeProgrammingCommand(
|
||||||
|
@ -1369,9 +1372,11 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
)
|
)
|
||||||
podStateManager.tempBasal = null
|
podStateManager.tempBasal = null
|
||||||
rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED))
|
rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_SUSPENDED))
|
||||||
|
rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE))
|
||||||
|
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS))
|
||||||
|
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TIME_OUT_OF_SYNC))
|
||||||
|
commandQueue.customCommand(CommandDisableSuspendAlerts(), null)
|
||||||
}
|
}
|
||||||
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS))
|
|
||||||
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TIME_OUT_OF_SYNC))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OmnipodCommandType.SET_BASAL_PROFILE -> {
|
OmnipodCommandType.SET_BASAL_PROFILE -> {
|
||||||
|
@ -1394,6 +1399,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
|
||||||
rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE))
|
rxBus.send(EventDismissNotification(Notification.FAILED_UPDATE_PROFILE))
|
||||||
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS))
|
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TBR_ALERTS))
|
||||||
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TIME_OUT_OF_SYNC))
|
rxBus.send(EventDismissNotification(Notification.OMNIPOD_TIME_OUT_OF_SYNC))
|
||||||
|
commandQueue.customCommand(CommandDisableSuspendAlerts(), null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,10 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definitio
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_ALERT_HOURS
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_ALERT_HOURS
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_ALERT_HOURS_DURATION
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_ALERT_HOURS_DURATION
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_IMMINENT_ALERT_HOURS
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_EXPIRATION_IMMINENT_ALERT_HOURS
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.PodConstants.Companion.POD_PULSE_BOLUS_UNITS
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.*
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.*
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.state.OmnipodDashPodStateManager
|
||||||
|
import info.nightscout.androidaps.utils.Round
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.functions.Action
|
import io.reactivex.functions.Action
|
||||||
|
@ -281,7 +283,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
.setNonce(NONCE)
|
.setNonce(NONCE)
|
||||||
.setNumberOfUnits(podStateManager.firstPrimeBolusVolume!! * PodConstants.POD_PULSE_BOLUS_UNITS)
|
.setNumberOfUnits(Round.roundTo(podStateManager.firstPrimeBolusVolume!! * PodConstants.POD_PULSE_BOLUS_UNITS, POD_PULSE_BOLUS_UNITS))
|
||||||
.setDelayBetweenPulsesInEighthSeconds(podStateManager.primePulseRate!!.toByte())
|
.setDelayBetweenPulsesInEighthSeconds(podStateManager.primePulseRate!!.toByte())
|
||||||
.setProgramReminder(ProgramReminder(atStart = false, atEnd = false, atInterval = 0))
|
.setProgramReminder(ProgramReminder(atStart = false, atEnd = false, atInterval = 0))
|
||||||
.build(),
|
.build(),
|
||||||
|
@ -383,7 +385,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
)
|
)
|
||||||
observables.add(
|
observables.add(
|
||||||
observeSendProgramBolusCommand(
|
observeSendProgramBolusCommand(
|
||||||
podStateManager.secondPrimeBolusVolume!! * PodConstants.POD_PULSE_BOLUS_UNITS,
|
Round.roundTo(podStateManager.secondPrimeBolusVolume!! * PodConstants.POD_PULSE_BOLUS_UNITS, PodConstants.POD_PULSE_BOLUS_UNITS),
|
||||||
podStateManager.primePulseRate!!.toByte(),
|
podStateManager.primePulseRate!!.toByte(),
|
||||||
confirmationBeeps = false,
|
confirmationBeeps = false,
|
||||||
completionBeeps = false
|
completionBeeps = false
|
||||||
|
@ -437,7 +439,7 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
userExpiryAlertDelay.toMinutes().toShort()
|
userExpiryAlertDelay.toMinutes().toShort()
|
||||||
),
|
),
|
||||||
BeepType.FOUR_TIMES_BIP_BEEP,
|
BeepType.FOUR_TIMES_BIP_BEEP,
|
||||||
BeepRepetitionType.XXX2
|
BeepRepetitionType.EVERY_MINUTE_AND_EVERY_15_MIN
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -502,8 +504,29 @@ class OmnipodDashManagerImpl @Inject constructor(
|
||||||
return Observable.concat(
|
return Observable.concat(
|
||||||
observePodRunning,
|
observePodRunning,
|
||||||
observeConnectToPod,
|
observeConnectToPod,
|
||||||
observeSendStopDeliveryCommand(StopDeliveryCommand.DeliveryType.ALL, hasBasalBeepEnabled)
|
observeSuspendDeliveryCommand(hasBasalBeepEnabled)
|
||||||
).interceptPodEvents()
|
).doOnComplete {
|
||||||
|
podStateManager.suspendAlertsEnabled = true
|
||||||
|
}.interceptPodEvents()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeSuspendDeliveryCommand(hasBasalBeepEnabled: Boolean): Observable<PodEvent> {
|
||||||
|
return Observable.defer {
|
||||||
|
val beepType = if (!hasBasalBeepEnabled)
|
||||||
|
BeepType.SILENT
|
||||||
|
else
|
||||||
|
BeepType.LONG_SINGLE_BEEP
|
||||||
|
|
||||||
|
bleManager.sendCommand(
|
||||||
|
SuspendDeliveryCommand.Builder()
|
||||||
|
.setSequenceNumber(podStateManager.messageSequenceNumber)
|
||||||
|
.setUniqueId(podStateManager.uniqueId!!.toInt())
|
||||||
|
.setNonce(NONCE)
|
||||||
|
.setBeepType(beepType)
|
||||||
|
.build(),
|
||||||
|
DefaultStatusResponse::class
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeSendProgramTempBasalCommand(rate: Double, durationInMinutes: Short, tempBasalBeeps: Boolean): Observable<PodEvent> {
|
private fun observeSendProgramTempBasalCommand(rate: Double, durationInMinutes: Short, tempBasalBeeps: Boolean): Observable<PodEvent> {
|
||||||
|
|
|
@ -38,6 +38,18 @@ class ProgramAlertsCommand private constructor(
|
||||||
return appendCrc(byteBuffer.array())
|
return appendCrc(byteBuffer.array())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val encodedWithoutHeaderAndCRC32: ByteArray
|
||||||
|
get() {
|
||||||
|
val byteBuffer: ByteBuffer = ByteBuffer.allocate(getLength().toInt())
|
||||||
|
.put(commandType.value)
|
||||||
|
.put(getBodyLength())
|
||||||
|
.putInt(nonce)
|
||||||
|
for (configuration in alertConfigurations) {
|
||||||
|
byteBuffer.put(configuration.encoded)
|
||||||
|
}
|
||||||
|
return byteBuffer.array()
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "ProgramAlertsCommand{" +
|
return "ProgramAlertsCommand{" +
|
||||||
"alertConfigurations=" + alertConfigurations +
|
"alertConfigurations=" + alertConfigurations +
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.CommandType
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.NonceEnabledCommand
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command.base.builder.NonceEnabledCommandBuilder
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.*
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
// StopDelivery.ALL followed by ProgramAlerts
|
||||||
|
class SuspendDeliveryCommand private constructor(
|
||||||
|
uniqueId: Int,
|
||||||
|
sequenceNumber: Short,
|
||||||
|
multiCommandFlag: Boolean,
|
||||||
|
private val beepType: BeepType,
|
||||||
|
nonce: Int
|
||||||
|
) : NonceEnabledCommand(CommandType.STOP_DELIVERY, uniqueId, sequenceNumber, multiCommandFlag, nonce) {
|
||||||
|
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
val alerts = listOf(
|
||||||
|
AlertConfiguration(
|
||||||
|
AlertType.SUSPEND_ENDED,
|
||||||
|
enabled = true,
|
||||||
|
durationInMinutes = 0,
|
||||||
|
autoOff = false,
|
||||||
|
AlertTrigger.TimerTrigger(
|
||||||
|
20
|
||||||
|
),
|
||||||
|
BeepType.FOUR_TIMES_BIP_BEEP,
|
||||||
|
BeepRepetitionType.EVERY_MINUTE_AND_EVERY_15_MIN
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val programAlerts = ProgramAlertsCommand.Builder()
|
||||||
|
.setNonce(nonce)
|
||||||
|
.setUniqueId(uniqueId)
|
||||||
|
.setAlertConfigurations(alerts)
|
||||||
|
.setSequenceNumber(sequenceNumber)
|
||||||
|
.setMultiCommandFlag(false)
|
||||||
|
.build()
|
||||||
|
.encodedWithoutHeaderAndCRC32
|
||||||
|
|
||||||
|
val byteBuffer = ByteBuffer.allocate(LENGTH + HEADER_LENGTH + programAlerts.size)
|
||||||
|
.put(encodeHeader(uniqueId, sequenceNumber, (LENGTH + programAlerts.size).toShort(), multiCommandFlag))
|
||||||
|
.put(commandType.value)
|
||||||
|
.put(BODY_LENGTH)
|
||||||
|
.putInt(nonce)
|
||||||
|
.put((beepType.value.toInt() shl 4 or DeliveryType.ALL.encoded[0].toInt()).toByte())
|
||||||
|
.put(programAlerts)
|
||||||
|
.array()
|
||||||
|
|
||||||
|
return appendCrc(
|
||||||
|
byteBuffer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "SuspendDeliveryCommand{" +
|
||||||
|
"deliveryType=" + DeliveryType.ALL +
|
||||||
|
", beepType=" + beepType +
|
||||||
|
", nonce=" + nonce +
|
||||||
|
", commandType=" + commandType +
|
||||||
|
", uniqueId=" + uniqueId +
|
||||||
|
", sequenceNumber=" + sequenceNumber +
|
||||||
|
", multiCommandFlag=" + multiCommandFlag +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class DeliveryType(
|
||||||
|
private val basal: Boolean,
|
||||||
|
private val tempBasal: Boolean,
|
||||||
|
private val bolus: Boolean
|
||||||
|
) : Encodable {
|
||||||
|
|
||||||
|
BASAL(true, false, false), TEMP_BASAL(false, true, false), BOLUS(false, false, true), ALL(true, true, true);
|
||||||
|
|
||||||
|
override val encoded: ByteArray
|
||||||
|
get() {
|
||||||
|
val bitSet = BitSet(8)
|
||||||
|
bitSet[0] = basal
|
||||||
|
bitSet[1] = tempBasal
|
||||||
|
bitSet[2] = bolus
|
||||||
|
return bitSet.toByteArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Builder : NonceEnabledCommandBuilder<Builder, SuspendDeliveryCommand>() {
|
||||||
|
private var beepType: BeepType? = BeepType.LONG_SINGLE_BEEP
|
||||||
|
|
||||||
|
fun setBeepType(beepType: BeepType): Builder {
|
||||||
|
this.beepType = beepType
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildCommand(): SuspendDeliveryCommand {
|
||||||
|
requireNotNull(beepType) { "beepType can not be null" }
|
||||||
|
|
||||||
|
return SuspendDeliveryCommand(
|
||||||
|
uniqueId!!,
|
||||||
|
sequenceNumber!!,
|
||||||
|
multiCommandFlag,
|
||||||
|
beepType!!,
|
||||||
|
nonce!!
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val LENGTH: Short = 7
|
||||||
|
private const val BODY_LENGTH: Byte = 5
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,8 +6,8 @@ enum class BeepRepetitionType(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
XXX(0x01.toByte()), // Used in lump of coal alert, LOW_RESERVOIR
|
XXX(0x01.toByte()), // Used in lump of coal alert, LOW_RESERVOIR
|
||||||
XXX2(0x03.toByte()), // Used in USER_SET_EXPIRATION
|
EVERY_MINUTE_AND_EVERY_15_MIN(0x03.toByte()), // Used in USER_SET_EXPIRATION, suspend delivery
|
||||||
XXX3(0x05.toByte()), // published system expiration alert
|
XXX3(0x05.toByte()), // published system expiration alert
|
||||||
XXX4(0x06.toByte()), // Used in imminent pod expiration alert, suspend in progress
|
XXX4(0x06.toByte()), // Used in imminent pod expiration alert, suspend in progress. No repeat?
|
||||||
XXX5(0x08.toByte()); // Lump of coal alert
|
XXX5(0x08.toByte()); // Lump of coal alert
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,7 @@ interface OmnipodDashPodStateManager {
|
||||||
var basalProgram: BasalProgram?
|
var basalProgram: BasalProgram?
|
||||||
val activeCommand: ActiveCommand?
|
val activeCommand: ActiveCommand?
|
||||||
val lastBolus: LastBolus?
|
val lastBolus: LastBolus?
|
||||||
|
var suspendAlertsEnabled: Boolean
|
||||||
|
|
||||||
fun increaseMessageSequenceNumber()
|
fun increaseMessageSequenceNumber()
|
||||||
fun increaseEapAkaSequenceNumber(): ByteArray
|
fun increaseEapAkaSequenceNumber(): ByteArray
|
||||||
|
|
|
@ -16,6 +16,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.DefaultStatusResponse
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.DefaultStatusResponse
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.SetUniqueIdResponse
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.SetUniqueIdResponse
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.VersionResponse
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.response.VersionResponse
|
||||||
|
import info.nightscout.androidaps.utils.Round
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.Maybe
|
import io.reactivex.Maybe
|
||||||
|
@ -224,6 +225,13 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
store()
|
store()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override var suspendAlertsEnabled: Boolean
|
||||||
|
get() = podState.suspendAlertsEnabled
|
||||||
|
set(enabled) {
|
||||||
|
podState.suspendAlertsEnabled = enabled
|
||||||
|
store()
|
||||||
|
}
|
||||||
|
|
||||||
override val lastStatusResponseReceived: Long
|
override val lastStatusResponseReceived: Long
|
||||||
get() = podState.lastStatusResponseReceived
|
get() = podState.lastStatusResponseReceived
|
||||||
|
|
||||||
|
@ -340,7 +348,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
|
|
||||||
private fun updateLastBolusFromResponse(bolusPulsesRemaining: Short) {
|
private fun updateLastBolusFromResponse(bolusPulsesRemaining: Short) {
|
||||||
podState.lastBolus?.run {
|
podState.lastBolus?.run {
|
||||||
val remainingUnits = bolusPulsesRemaining.toDouble() * PodConstants.POD_PULSE_BOLUS_UNITS
|
val remainingUnits = Round.roundTo(bolusPulsesRemaining * PodConstants.POD_PULSE_BOLUS_UNITS, PodConstants.POD_PULSE_BOLUS_UNITS)
|
||||||
this.bolusUnitsRemaining = remainingUnits
|
this.bolusUnitsRemaining = remainingUnits
|
||||||
if (remainingUnits == 0.0) {
|
if (remainingUnits == 0.0) {
|
||||||
this.deliveryComplete = true
|
this.deliveryComplete = true
|
||||||
|
@ -713,6 +721,7 @@ class OmnipodDashPodStateManagerImpl @Inject constructor(
|
||||||
var timeZoneOffset: Int? = null
|
var timeZoneOffset: Int? = null
|
||||||
var timeZoneUpdated: Long? = null
|
var timeZoneUpdated: Long? = null
|
||||||
var alarmSynced: Boolean = false
|
var alarmSynced: Boolean = false
|
||||||
|
var suspendAlertsEnabled: Boolean = false
|
||||||
|
|
||||||
var bleVersion: SoftwareVersion? = null
|
var bleVersion: SoftwareVersion? = null
|
||||||
var firmwareVersion: SoftwareVersion? = null
|
var firmwareVersion: SoftwareVersion? = null
|
||||||
|
|
|
@ -439,6 +439,10 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
R.string.omnipod_common_alert_expiration_advisory
|
R.string.omnipod_common_alert_expiration_advisory
|
||||||
AlertType.AUTO_OFF ->
|
AlertType.AUTO_OFF ->
|
||||||
R.string.omnipod_common_alert_shutdown_imminent
|
R.string.omnipod_common_alert_shutdown_imminent
|
||||||
|
AlertType.SUSPEND_IN_PROGRESS ->
|
||||||
|
R.string.omnipod_common_alert_delivery_suspended
|
||||||
|
AlertType.SUSPEND_ENDED ->
|
||||||
|
R.string.omnipod_common_alert_delivery_suspended
|
||||||
else ->
|
else ->
|
||||||
R.string.omnipod_common_alert_unknown_alert
|
R.string.omnipod_common_alert_unknown_alert
|
||||||
}
|
}
|
||||||
|
@ -629,16 +633,8 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
|
|
||||||
private fun updateSuspendDeliveryButton() {
|
private fun updateSuspendDeliveryButton() {
|
||||||
// If the Pod is currently suspended, we show the Resume delivery button instead.
|
// If the Pod is currently suspended, we show the Resume delivery button instead.
|
||||||
if (isSuspendDeliveryButtonEnabled() &&
|
// disable the 'suspendDelivery' button.
|
||||||
podStateManager.isPodRunning &&
|
buttonBinding.buttonSuspendDelivery.visibility = View.GONE
|
||||||
(!podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(CommandSuspendDelivery::class.java))
|
|
||||||
) {
|
|
||||||
buttonBinding.buttonSuspendDelivery.visibility = View.VISIBLE
|
|
||||||
buttonBinding.buttonSuspendDelivery.isEnabled =
|
|
||||||
podStateManager.isPodRunning && !podStateManager.isSuspended && isQueueEmpty()
|
|
||||||
} else {
|
|
||||||
buttonBinding.buttonSuspendDelivery.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateSetTimeButton() {
|
private fun updateSetTimeButton() {
|
||||||
|
@ -654,10 +650,6 @@ class OmnipodDashOverviewFragment : DaggerFragment() {
|
||||||
return sp.getBoolean(R.string.omnipod_common_preferences_automatically_silence_alerts, false)
|
return sp.getBoolean(R.string.omnipod_common_preferences_automatically_silence_alerts, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isSuspendDeliveryButtonEnabled(): Boolean {
|
|
||||||
return sp.getBoolean(R.string.key_omnipod_common_suspend_delivery_button_enabled, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun displayErrorDialog(title: String, message: String, withSound: Boolean) {
|
private fun displayErrorDialog(title: String, message: String, withSound: Boolean) {
|
||||||
context?.let {
|
context?.let {
|
||||||
ErrorHelperActivity.runAlarm(it, message, title, if (withSound) R.raw.boluserror else 0)
|
ErrorHelperActivity.runAlarm(it, message, title, if (withSound) R.raw.boluserror else 0)
|
||||||
|
|
|
@ -47,4 +47,5 @@
|
||||||
<string name="omnipod_common_history_tbr_value">Rate: %1$.2f U, duration: %2$d minutes</string>
|
<string name="omnipod_common_history_tbr_value">Rate: %1$.2f U, duration: %2$d minutes</string>
|
||||||
<string name="omnipod_common_history_bolus_value">%1$.2f U</string>
|
<string name="omnipod_common_history_bolus_value">%1$.2f U</string>
|
||||||
<string name="dash_bolusdelivering">Delivering %1$.2f U</string>
|
<string name="dash_bolusdelivering">Delivering %1$.2f U</string>
|
||||||
|
<string name="omnipod_common_alert_delivery_suspended">Insulin delivery is suspended</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -105,11 +105,6 @@
|
||||||
android:title="@string/omnipod_common_preferences_category_other"
|
android:title="@string/omnipod_common_preferences_category_other"
|
||||||
app:initialExpandedChildrenCount="0">
|
app:initialExpandedChildrenCount="0">
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="@string/key_omnipod_common_suspend_delivery_button_enabled"
|
|
||||||
android:title="@string/omnipod_common_preferences_suspend_delivery_button_enabled" />
|
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:key="@string/key_omnipod_common_time_change_event_enabled"
|
android:key="@string/key_omnipod_common_time_change_event_enabled"
|
||||||
|
|
|
@ -85,7 +85,7 @@ class ProgramAlertsCommandTest {
|
||||||
false,
|
false,
|
||||||
AlertTrigger.TimerTrigger(4079.toShort()),
|
AlertTrigger.TimerTrigger(4079.toShort()),
|
||||||
BeepType.FOUR_TIMES_BIP_BEEP,
|
BeepType.FOUR_TIMES_BIP_BEEP,
|
||||||
BeepRepetitionType.XXX2
|
BeepRepetitionType.EVERY_MINUTE_AND_EVERY_15_MIN
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.command
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.definition.BeepType
|
||||||
|
import org.apache.commons.codec.DecoderException
|
||||||
|
import org.apache.commons.codec.binary.Hex
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class SuspendDeliveryCommandTest {
|
||||||
|
@Test @Throws(DecoderException::class) fun testSuspendDelivery() {
|
||||||
|
val encoded = SuspendDeliveryCommand.Builder()
|
||||||
|
.setUniqueId(37879811)
|
||||||
|
.setSequenceNumber(0.toShort())
|
||||||
|
.setNonce(1229869870)
|
||||||
|
.setBeepType(BeepType.LONG_SINGLE_BEEP)
|
||||||
|
.build()
|
||||||
|
.encoded
|
||||||
|
Assert.assertArrayEquals(Hex.decodeHex("0242000300131f05494e532e67190a494e532e680000140302811f"), encoded)
|
||||||
|
}
|
||||||
|
}
|
|
@ -85,10 +85,11 @@ public class RileyLinkBLE {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Response Count is " + ByteUtil.shortHexString(characteristic.getValue()));
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Response Count is " + ByteUtil.shortHexString(characteristic.getValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (radioResponseCountNotified != null) {
|
if (characteristic.getUuid().equals(UUID.fromString(GattAttributes.CHARA_RADIO_RESPONSE_COUNT))) {
|
||||||
radioResponseCountNotified.run();
|
if (radioResponseCountNotified != null) {
|
||||||
|
radioResponseCountNotified.run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
orangeLink.onCharacteristicChanged(characteristic);
|
orangeLink.onCharacteristicChanged(characteristic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue