diff --git a/homeassistant/components/alarm_control_panel/significant_change.py b/homeassistant/components/alarm_control_panel/significant_change.py new file mode 100644 index 0000000000000..d33347a67f1db --- /dev/null +++ b/homeassistant/components/alarm_control_panel/significant_change.py @@ -0,0 +1,38 @@ +"""Helper to test significant Alarm Control Panel state changes.""" +from __future__ import annotations + +from typing import Any + +from homeassistant.core import HomeAssistant, callback + +from . import ATTR_CHANGED_BY, ATTR_CODE_ARM_REQUIRED + +SIGNIFICANT_ATTRIBUTES: set[str] = { + ATTR_CHANGED_BY, + ATTR_CODE_ARM_REQUIRED, +} + + +@callback +def async_check_significant_change( + hass: HomeAssistant, + old_state: str, + old_attrs: dict, + new_state: str, + new_attrs: dict, + **kwargs: Any, +) -> bool | None: + """Test if state significantly changed.""" + if old_state != new_state: + return True + + old_attrs_s = set(old_attrs.items()) + new_attrs_s = set(new_attrs.items()) + changed_attrs: set[str] = {item[0] for item in old_attrs_s ^ new_attrs_s} + + for attr_name in changed_attrs: + if attr_name in SIGNIFICANT_ATTRIBUTES: + return True + + # no significant attribute change detected + return False diff --git a/tests/components/alarm_control_panel/test_significant_change.py b/tests/components/alarm_control_panel/test_significant_change.py new file mode 100644 index 0000000000000..d65a1d5cb00c7 --- /dev/null +++ b/tests/components/alarm_control_panel/test_significant_change.py @@ -0,0 +1,51 @@ +"""Test the Alarm Control Panel significant change platform.""" +import pytest + +from homeassistant.components.alarm_control_panel import ( + ATTR_CHANGED_BY, + ATTR_CODE_ARM_REQUIRED, + ATTR_CODE_FORMAT, +) +from homeassistant.components.alarm_control_panel.significant_change import ( + async_check_significant_change, +) + + +async def test_significant_state_change() -> None: + """Detect Alarm Control Panel significant state changes.""" + attrs = {} + assert not async_check_significant_change(None, "on", attrs, "on", attrs) + assert async_check_significant_change(None, "on", attrs, "off", attrs) + + +@pytest.mark.parametrize( + ("old_attrs", "new_attrs", "expected_result"), + [ + ({ATTR_CHANGED_BY: "old_value"}, {ATTR_CHANGED_BY: "old_value"}, False), + ({ATTR_CHANGED_BY: "old_value"}, {ATTR_CHANGED_BY: "new_value"}, True), + ( + {ATTR_CODE_ARM_REQUIRED: "old_value"}, + {ATTR_CODE_ARM_REQUIRED: "new_value"}, + True, + ), + # multiple attributes + ( + {ATTR_CHANGED_BY: "old_value", ATTR_CODE_ARM_REQUIRED: "old_value"}, + {ATTR_CHANGED_BY: "new_value", ATTR_CODE_ARM_REQUIRED: "old_value"}, + True, + ), + # insignificant attributes + ({ATTR_CODE_FORMAT: "old_value"}, {ATTR_CODE_FORMAT: "old_value"}, False), + ({ATTR_CODE_FORMAT: "old_value"}, {ATTR_CODE_FORMAT: "new_value"}, False), + ({"unknown_attr": "old_value"}, {"unknown_attr": "old_value"}, False), + ({"unknown_attr": "old_value"}, {"unknown_attr": "new_value"}, False), + ], +) +async def test_significant_atributes_change( + old_attrs: dict, new_attrs: dict, expected_result: bool +) -> None: + """Detect Humidifier significant attribute changes.""" + assert ( + async_check_significant_change(None, "state", old_attrs, "state", new_attrs) + == expected_result + )