Add fast drop and fast rise alerts

This commit is contained in:
opsb 2020-01-26 18:32:00 +01:00
parent afb0a6efba
commit 9363fb4a81
5 changed files with 82 additions and 29 deletions

View File

@ -17,6 +17,12 @@ enum ConstantsDefaultAlertLevels {
static let high = 170
static let low = 70
// blood glucose fast drop delta alert in mgdl
static let fastdrop = 10
// blood glucose fast rise delta alert in mgdl
static let fastrise = 10
// in minutes, after how many minutes of now reading should alert be raised
static let missedReading = 30

View File

@ -18,6 +18,8 @@ enum ConstantsNotifications {
static let missedReadingAlert = "missedReadingAlert"
/// battery low
static let batteryLow = "batteryLow"
/// fast drop
static let fastdrop = "fastDrop"
}
/// identifiers for alert notifications
@ -34,6 +36,10 @@ enum ConstantsNotifications {
static let missedReadingAlert = "missedReadingAlert"
/// battery low
static let batteryLow = "batteryLow"
/// fast drop
static let fastDropAlert = "fastDropAlert"
/// fast rise
static let fastRiseAlert = "fastRiseAlert"
}
/// identifiers for calibration requests

View File

@ -5,7 +5,7 @@ public enum AlertKind:Int, CaseIterable {
// when adding alertkinds, try to add new cases at the end (ie 7, ...)
// if this is done in the middle ((eg rapid rise alert might seem better positioned after veryhigh), then a database migration would be required, because the rawvalue is stored as Int16 in the coredata, namely the alertkind
// the order of the alerts will also be the order in the settings
case verylow = 0
case low = 1
case high = 2
@ -13,13 +13,15 @@ public enum AlertKind:Int, CaseIterable {
case missedreading = 4
case calibration = 5
case batterylow = 6
case fastdrop = 7
case fastrise = 8
/// example, low alert needs a value = value below which alert needs to fire - there's actually no alert right now that doesn't need a value, in iosxdrip there was the iphonemuted alert, but I removed this here. Function remains, never now it might come back
///
/// probably only useful in UI - named AlertKind and not AlertType because there's already an AlertType which has a different goal
func needsAlertValue() -> Bool {
switch self {
case .low, .high, .verylow,.veryhigh,.missedreading,.calibration,.batterylow:
case .low, .high, .verylow,.veryhigh,.missedreading,.calibration,.batterylow,.fastdrop,.fastrise:
return true
}
}
@ -29,8 +31,8 @@ public enum AlertKind:Int, CaseIterable {
/// will only be useful in UI
func valueNeedsConversionToMmol() -> Bool {
switch self {
case .low, .high, .verylow, .veryhigh:
case .low, .high, .verylow, .veryhigh, .fastdrop, .fastrise:
return true
case .missedreading, .calibration, .batterylow:
return false
@ -59,6 +61,10 @@ public enum AlertKind:Int, CaseIterable {
} else {
return ConstantsDefaultAlertLevels.defaultBatteryAlertLevelMiaoMiao
}
case .fastdrop:
return ConstantsDefaultAlertLevels.fastdrop;
case .fastrise:
return ConstantsDefaultAlertLevels.fastrise;
}
}
@ -80,6 +86,10 @@ public enum AlertKind:Int, CaseIterable {
return "calibration"
case .batterylow:
return "batterylow"
case .fastdrop:
return "fastdrop"
case .fastrise:
return "fastrise"
}
}
@ -131,6 +141,32 @@ public enum AlertKind:Int, CaseIterable {
} else {return (false, nil, nil, nil)}
} else {return (false, nil, nil, nil)}
case .fastdrop:
// if alertEntry not enabled, return false
if !currentAlertEntry.alertType.enabled {return (false, nil, nil, nil)}
if let lastBgReading = lastBgReading, let lastButOneBgReading = lastButOneBgReading {
// first check if calculatedValue > 0.0, never know that it's not been checked by caller
if lastBgReading.calculatedValue == 0.0 {return (false, nil, nil, nil)}
// now do the actual check if alert is applicable or not
if lastButOneBgReading.calculatedValue - lastBgReading.calculatedValue > Double(currentAlertEntry.value) {
return (true, lastBgReading.unitizedDeltaString(previousBgReading: lastButOneBgReading, showUnit: true, highGranularity: true, mgdl: UserDefaults.standard.bloodGlucoseUnitIsMgDl), createAlertTitleForBgReadingAlerts(bgReading: lastBgReading, alertKind: self), nil)
} else {return (false, nil, nil, nil)}
} else {return (false, nil, nil, nil)}
case .fastrise:
// if alertEntry not enabled, return false
if !currentAlertEntry.alertType.enabled {return (false, nil, nil, nil)}
if let lastBgReading = lastBgReading, let lastButOneBgReading = lastButOneBgReading {
// first check if calculatedValue > 0.0, never know that it's not been checked by caller
if lastBgReading.calculatedValue == 0.0 {return (false, nil, nil, nil)}
// now do the actual check if alert is applicable or not
if lastBgReading.calculatedValue - lastButOneBgReading.calculatedValue > Double(currentAlertEntry.value) {
return (true, lastBgReading.unitizedDeltaString(previousBgReading: lastButOneBgReading, showUnit: true, highGranularity: true, mgdl: UserDefaults.standard.bloodGlucoseUnitIsMgDl), createAlertTitleForBgReadingAlerts(bgReading: lastBgReading, alertKind: self), nil)
} else {return (false, nil, nil, nil)}
} else {return (false, nil, nil, nil)}
case .missedreading:
// if no valid lastbgreading then there's definitely no need to plan an alert
guard let lastBgReading = lastBgReading else {return (false, nil, nil, nil)}
@ -267,6 +303,10 @@ public enum AlertKind:Int, CaseIterable {
return ConstantsNotifications.NotificationIdentifiersForCalibration.subsequentCalibrationRequest
case .batterylow:
return ConstantsNotifications.NotificationIdentifiersForAlerts.batteryLow
case .fastdrop:
return ConstantsNotifications.NotificationIdentifiersForAlerts.fastDropAlert
case .fastrise:
return ConstantsNotifications.NotificationIdentifiersForAlerts.fastRiseAlert
}
}
@ -288,6 +328,10 @@ public enum AlertKind:Int, CaseIterable {
return Texts_Alerts.calibrationNeededAlertTitle
case .batterylow:
return Texts_Alerts.batteryLowAlertTitle
case .fastdrop:
return Texts_Alerts.fastDropTitle
case .fastrise:
return Texts_Alerts.fastRiseTitle
}
}
@ -295,8 +339,8 @@ public enum AlertKind:Int, CaseIterable {
/// What is this text ?
func valueUnitText(transmitterType:CGMTransmitterType?) -> String {
switch self {
case .verylow, .low, .high, .veryhigh:
case .verylow, .low, .high, .veryhigh, .fastdrop, .fastrise:
return UserDefaults.standard.bloodGlucoseUnitIsMgDl ? Texts_Common.mgdl:Texts_Common.mmol
case .missedreading:
return Texts_Common.minutes

View File

@ -137,27 +137,16 @@ public class AlertManager:NSObject {
if latestBgReadings.count > 1 {
lastButOneBgREading = latestBgReadings[1]
}
// alerts are checked in order of importance - there should be only one alert raised, except missed reading alert which will always be checked.
// first check very low alert
if (!checkAlertAndFire(alertKind: .verylow, lastBgReading: lastBgReading, lastButOneBgREading: lastButOneBgREading, lastCalibration: lastCalibration, transmitterBatteryInfo: transmitterBatteryInfo)) {
// very low not fired, check low alert - if very low alert snoozed, skip the check for low alert and continue to next step
if getSnoozeParameters(alertKind: AlertKind.verylow).getSnoozeValue().isSnoozed || (!checkAlertAndFire(alertKind: .low, lastBgReading: lastBgReading, lastButOneBgREading: lastButOneBgREading, lastCalibration: lastCalibration, transmitterBatteryInfo: transmitterBatteryInfo)) {
// low not fired, check very high alert
if (!checkAlertAndFire(alertKind: .veryhigh, lastBgReading: lastBgReading, lastButOneBgREading: lastButOneBgREading, lastCalibration: lastCalibration, transmitterBatteryInfo: transmitterBatteryInfo)) {
// very high not fired, check high alert - if very high alert snoozed, skip the check for high alert and continue to next step
if getSnoozeParameters(alertKind: AlertKind.veryhigh).getSnoozeValue().isSnoozed || (!checkAlertAndFire(alertKind: .high, lastBgReading: lastBgReading, lastButOneBgREading: lastButOneBgREading, lastCalibration: lastCalibration, transmitterBatteryInfo: transmitterBatteryInfo)) {
// very high not fired check calibration alert
if (!checkAlertAndFire(alertKind: .calibration, lastBgReading: lastBgReading, lastButOneBgREading: lastButOneBgREading, lastCalibration: lastCalibration, transmitterBatteryInfo: transmitterBatteryInfo)) {
// finally let's check the battery level alert
_ = checkAlertAndFire(alertKind: .batterylow, lastBgReading: lastBgReading, lastButOneBgREading: lastButOneBgREading, lastCalibration: lastCalibration, transmitterBatteryInfo: transmitterBatteryInfo)
}
}
}
}
}
// set missed reading alert, this will be a future planned alert
// TODO original implementation ignores isSnoozed for .calibration and .batterylow
// only raise first alert that's been tripped
let alertsByPreference : [AlertKind] = [.fastdrop, .verylow, .low, .fastrise, .veryhigh, .high, .calibration, .batterylow]
_ = alertsByPreference.first(where: { (alertKind:AlertKind) -> Bool in
let isSnoozed = getSnoozeParameters(alertKind: alertKind).getSnoozeValue().isSnoozed
return !isSnoozed && checkAlertAndFire(alertKind: alertKind, lastBgReading: lastBgReading, lastButOneBgREading: lastButOneBgREading, lastCalibration: lastCalibration, transmitterBatteryInfo: transmitterBatteryInfo)
})
// the missed reading alert will be a future planned alert
_ = checkAlertAndFire(alertKind: .missedreading, lastBgReading: lastBgReading, lastButOneBgREading: lastButOneBgREading, lastCalibration: lastCalibration, transmitterBatteryInfo: transmitterBatteryInfo)
} else {
trace("in checkAlerts, latestBgReadings is older than %{public}@ minutes", log: self.log, category: ConstantsLog.categoryAlertManager, type: .info, maxAgeOfLastBgReadingInSeconds.description)
@ -349,7 +338,7 @@ public class AlertManager:NSObject {
} // if snoozePeriodInMinutes or snoozeTimeStamp is nil (which shouldn't be the case) continue without taking into account the snooze status
case .calibration, .batterylow, .low, .high, .verylow, .veryhigh:
case .calibration, .batterylow, .low, .high, .verylow, .veryhigh, .fastdrop, .fastrise:
trace("in checkAlertAndFire, alert %{public}@ is currently snoozed", log: self.log, category: ConstantsLog.categoryAlertManager, type: .info, alertKind.descriptionForLogging())
return false
}

View File

@ -33,6 +33,14 @@ class Texts_Alerts {
return NSLocalizedString("alerts_batterylow", tableName: filename, bundle: Bundle.main, value: "Battery Low Alert", comment: "transmitter battery low, this is the title of the alert notification, also in alert settings list, for the name of the alert")
}()
static let fastDropTitle: String = {
return NSLocalizedString("alerts_fastdrop", tableName: filename, bundle: Bundle.main, value: "Fast Drop Alert", comment: "When fast drop alert rises, this is the start of the text shown in the title of the alert notification, also in alert settings list, for the name of the alert")
}()
static let fastRiseTitle: String = {
return NSLocalizedString("alerts_fastrise", tableName: filename, bundle: Bundle.main, value: "Fast Rise Alert", comment: "When fast drop alert rises, this is the start of the text shown in the title of the alert notification, also in alert settings list, for the name of the alert")
}()
static let snooze: String = {
return NSLocalizedString("alerts_snooze", tableName: filename, bundle: Bundle.main, value: "Snooze", comment: "Action text for alerts. This is the button that allows to snooze the alert")
}()