Add Pico alarm view model
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
from alarms.alarm_definitions import (
|
||||
BATTERY_SOC_LOW,
|
||||
BATTERY_VOLTAGE_LOW,
|
||||
FRIDGE_ZONE_1_HIGH,
|
||||
FRIDGE_ZONE_2_HIGH,
|
||||
SENSOR_FAILURE,
|
||||
COMMUNICATION_LOST,
|
||||
)
|
||||
|
||||
|
||||
ALARM_LABELS = {
|
||||
BATTERY_SOC_LOW: "Battery SOC Low",
|
||||
BATTERY_VOLTAGE_LOW: "Battery Voltage Low",
|
||||
FRIDGE_ZONE_1_HIGH: "Fridge Zone 1 High Temp",
|
||||
FRIDGE_ZONE_2_HIGH: "Fridge Zone 2 High Temp",
|
||||
COMMUNICATION_LOST: "ESP32 Communication Lost",
|
||||
}
|
||||
|
||||
|
||||
CRITICAL_ALARMS = {
|
||||
BATTERY_SOC_LOW,
|
||||
BATTERY_VOLTAGE_LOW,
|
||||
FRIDGE_ZONE_1_HIGH,
|
||||
FRIDGE_ZONE_2_HIGH,
|
||||
COMMUNICATION_LOST,
|
||||
}
|
||||
|
||||
|
||||
class AlarmViewModel:
|
||||
def __init__(self, alarms):
|
||||
self.alarms = alarms or []
|
||||
|
||||
def count(self):
|
||||
return len(self.alarms)
|
||||
|
||||
def has_alarms(self):
|
||||
return self.count() > 0
|
||||
|
||||
def has_critical(self):
|
||||
return any(self._base_alarm(alarm) in CRITICAL_ALARMS for alarm in self.alarms)
|
||||
|
||||
def should_buzz(self):
|
||||
return self.has_critical()
|
||||
|
||||
def primary_alarm(self):
|
||||
if not self.alarms:
|
||||
return None
|
||||
|
||||
return self.format_alarm(self.alarms[0])
|
||||
|
||||
def as_list(self):
|
||||
return [self.format_alarm(alarm) for alarm in self.alarms]
|
||||
|
||||
def format_alarm(self, alarm):
|
||||
base = self._base_alarm(alarm)
|
||||
|
||||
if base == SENSOR_FAILURE:
|
||||
sensor = alarm.split(":", 1)[1] if ":" in alarm else "unknown"
|
||||
return {
|
||||
"code": alarm,
|
||||
"severity": "warning",
|
||||
"title": "Sensor Failure",
|
||||
"detail": sensor.replace("_", " ").title(),
|
||||
}
|
||||
|
||||
return {
|
||||
"code": alarm,
|
||||
"severity": "critical" if base in CRITICAL_ALARMS else "info",
|
||||
"title": ALARM_LABELS.get(base, alarm),
|
||||
"detail": None,
|
||||
}
|
||||
|
||||
def _base_alarm(self, alarm):
|
||||
return alarm.split(":", 1)[0]
|
||||
@@ -583,3 +583,48 @@ def test_system_view_model():
|
||||
assert vm["wifi_api"] == "Available"
|
||||
assert vm["sensors"] == "3 / 4 OK"
|
||||
assert vm["ignition"] == "Off"
|
||||
|
||||
|
||||
def test_alarm_view_model_no_alarms():
|
||||
from ui.alarm_view_model import AlarmViewModel
|
||||
|
||||
vm = AlarmViewModel([])
|
||||
|
||||
assert vm.count() == 0
|
||||
assert vm.has_alarms() is False
|
||||
assert vm.has_critical() is False
|
||||
assert vm.should_buzz() is False
|
||||
assert vm.primary_alarm() is None
|
||||
assert vm.as_list() == []
|
||||
|
||||
|
||||
def test_alarm_view_model_critical_alarm():
|
||||
from ui.alarm_view_model import AlarmViewModel
|
||||
|
||||
vm = AlarmViewModel(["fridge_zone_1_high"])
|
||||
|
||||
assert vm.count() == 1
|
||||
assert vm.has_alarms() is True
|
||||
assert vm.has_critical() is True
|
||||
assert vm.should_buzz() is True
|
||||
|
||||
primary = vm.primary_alarm()
|
||||
|
||||
assert primary["severity"] == "critical"
|
||||
assert primary["title"] == "Fridge Zone 1 High Temp"
|
||||
|
||||
|
||||
def test_alarm_view_model_sensor_failure():
|
||||
from ui.alarm_view_model import AlarmViewModel
|
||||
|
||||
vm = AlarmViewModel(["sensor_failure:outside"])
|
||||
|
||||
assert vm.has_alarms() is True
|
||||
assert vm.has_critical() is False
|
||||
assert vm.should_buzz() is False
|
||||
|
||||
alarm = vm.primary_alarm()
|
||||
|
||||
assert alarm["severity"] == "warning"
|
||||
assert alarm["title"] == "Sensor Failure"
|
||||
assert alarm["detail"] == "Outside"
|
||||
|
||||
Reference in New Issue
Block a user