use crate::config::Alerts;
const MS_PER_MIN: i64 = 60_000;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Alert {
UrgentLow,
Low,
InRange,
High,
UrgentHigh,
Stale,
}
impl Alert {
pub fn is_alerting(self) -> bool {
!matches!(self, Alert::InRange)
}
pub fn is_urgent(self) -> bool {
matches!(self, Alert::UrgentLow | Alert::UrgentHigh | Alert::Stale)
}
pub fn label(self) -> &'static str {
match self {
Alert::UrgentLow => "URGENT LOW",
Alert::Low => "LOW",
Alert::InRange => "in range",
Alert::High => "HIGH",
Alert::UrgentHigh => "URGENT HIGH",
Alert::Stale => "SENSOR GAP — no recent readings",
}
}
pub fn class(self) -> &'static str {
match self {
Alert::UrgentLow => "urgent-low",
Alert::Low => "low",
Alert::InRange => "in-range",
Alert::High => "high",
Alert::UrgentHigh => "urgent-high",
Alert::Stale => "stale",
}
}
pub fn urgency(self) -> &'static str {
match self {
Alert::UrgentLow | Alert::UrgentHigh | Alert::Stale => "critical",
_ => "normal",
}
}
}
pub fn from_value(sgv: f64, a: &Alerts) -> Alert {
if sgv <= a.urgent_low {
Alert::UrgentLow
} else if sgv < a.low {
Alert::Low
} else if sgv >= a.urgent_high {
Alert::UrgentHigh
} else if sgv > a.high {
Alert::High
} else {
Alert::InRange
}
}
pub fn evaluate(sgv: f64, age_ms: i64, a: &Alerts) -> Alert {
if age_ms > a.stale_minutes * MS_PER_MIN {
return Alert::Stale;
}
if sgv <= a.urgent_low {
Alert::UrgentLow
} else if sgv < a.low {
Alert::Low
} else if sgv >= a.urgent_high {
Alert::UrgentHigh
} else if sgv > a.high {
Alert::High
} else {
Alert::InRange
}
}
#[cfg(test)]
mod tests {
use super::*;
fn cfg() -> Alerts {
Alerts::default() }
const FRESH: i64 = 0;
#[test]
fn in_range_midband() {
assert_eq!(evaluate(100.0, FRESH, &cfg()), Alert::InRange);
}
#[test]
fn low_and_urgent_low_boundaries() {
assert_eq!(evaluate(69.0, FRESH, &cfg()), Alert::Low);
assert_eq!(evaluate(55.0, FRESH, &cfg()), Alert::UrgentLow); assert_eq!(evaluate(40.0, FRESH, &cfg()), Alert::UrgentLow);
}
#[test]
fn high_and_urgent_high_boundaries() {
assert_eq!(evaluate(181.0, FRESH, &cfg()), Alert::High);
assert_eq!(evaluate(250.0, FRESH, &cfg()), Alert::UrgentHigh); assert_eq!(evaluate(300.0, FRESH, &cfg()), Alert::UrgentHigh);
}
#[test]
fn stale_overrides_value() {
let sixteen_min = 16 * MS_PER_MIN;
assert_eq!(evaluate(100.0, sixteen_min, &cfg()), Alert::Stale);
}
#[test]
fn is_alerting_only_for_out_of_range() {
assert!(!Alert::InRange.is_alerting());
assert!(Alert::Low.is_alerting());
assert!(Alert::Stale.is_alerting());
}
}