From 2c48f0e4167d37126bfbb9141752c6733b83d4ca Mon Sep 17 00:00:00 2001 From: Nick Whyte Date: Wed, 16 Aug 2023 21:56:52 +1000 Subject: [PATCH] Fix ness alarm armed_home state appearing as disarmed/armed_away (#94351) * Fix nessclient arm home appearing as arm away * patch arming mode enum and use dynamic access * Revert "patch arming mode enum and use dynamic access" This reverts commit b9cca8e92bcb382abe364381a8cb1674c32d1d2a. * Remove mock enums --- .../components/ness_alarm/__init__.py | 8 ++-- .../ness_alarm/alarm_control_panel.py | 22 ++++++++-- .../components/ness_alarm/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/ness_alarm/test_init.py | 44 +++++++------------ 6 files changed, 43 insertions(+), 37 deletions(-) diff --git a/homeassistant/components/ness_alarm/__init__.py b/homeassistant/components/ness_alarm/__init__.py index c1d97f781af..b5d30219550 100644 --- a/homeassistant/components/ness_alarm/__init__.py +++ b/homeassistant/components/ness_alarm/__init__.py @@ -3,7 +3,7 @@ from collections import namedtuple import datetime import logging -from nessclient import ArmingState, Client +from nessclient import ArmingMode, ArmingState, Client import voluptuous as vol from homeassistant.components.binary_sensor import ( @@ -136,9 +136,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: hass, SIGNAL_ZONE_CHANGED, ZoneChangedData(zone_id=zone_id, state=state) ) - def on_state_change(arming_state: ArmingState): + def on_state_change(arming_state: ArmingState, arming_mode: ArmingMode | None): """Receives and propagates arming state updates.""" - async_dispatcher_send(hass, SIGNAL_ARMING_STATE_CHANGED, arming_state) + async_dispatcher_send( + hass, SIGNAL_ARMING_STATE_CHANGED, arming_state, arming_mode + ) client.on_zone_change(on_zone_change) client.on_state_change(on_state_change) diff --git a/homeassistant/components/ness_alarm/alarm_control_panel.py b/homeassistant/components/ness_alarm/alarm_control_panel.py index 2f54b3abde6..92feaba13aa 100644 --- a/homeassistant/components/ness_alarm/alarm_control_panel.py +++ b/homeassistant/components/ness_alarm/alarm_control_panel.py @@ -3,12 +3,15 @@ from __future__ import annotations import logging -from nessclient import ArmingState, Client +from nessclient import ArmingMode, ArmingState, Client import homeassistant.components.alarm_control_panel as alarm from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature from homeassistant.const import ( STATE_ALARM_ARMED_AWAY, + STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_NIGHT, + STATE_ALARM_ARMED_VACATION, STATE_ALARM_ARMING, STATE_ALARM_DISARMED, STATE_ALARM_PENDING, @@ -23,6 +26,15 @@ from . import DATA_NESS, SIGNAL_ARMING_STATE_CHANGED _LOGGER = logging.getLogger(__name__) +ARMING_MODE_TO_STATE = { + ArmingMode.ARMED_AWAY: STATE_ALARM_ARMED_AWAY, + ArmingMode.ARMED_HOME: STATE_ALARM_ARMED_HOME, + ArmingMode.ARMED_DAY: STATE_ALARM_ARMED_AWAY, # no applicable state, fallback to away + ArmingMode.ARMED_NIGHT: STATE_ALARM_ARMED_NIGHT, + ArmingMode.ARMED_VACATION: STATE_ALARM_ARMED_VACATION, + ArmingMode.ARMED_HIGHEST: STATE_ALARM_ARMED_AWAY, # no applicable state, fallback to away +} + async def async_setup_platform( hass: HomeAssistant, @@ -79,7 +91,9 @@ class NessAlarmPanel(alarm.AlarmControlPanelEntity): await self._client.panic(code) @callback - def _handle_arming_state_change(self, arming_state: ArmingState) -> None: + def _handle_arming_state_change( + self, arming_state: ArmingState, arming_mode: ArmingMode | None + ) -> None: """Handle arming state update.""" if arming_state == ArmingState.UNKNOWN: @@ -91,7 +105,9 @@ class NessAlarmPanel(alarm.AlarmControlPanelEntity): elif arming_state == ArmingState.EXIT_DELAY: self._attr_state = STATE_ALARM_ARMING elif arming_state == ArmingState.ARMED: - self._attr_state = STATE_ALARM_ARMED_AWAY + self._attr_state = ARMING_MODE_TO_STATE.get( + arming_mode, STATE_ALARM_ARMED_AWAY + ) elif arming_state == ArmingState.ENTRY_DELAY: self._attr_state = STATE_ALARM_PENDING elif arming_state == ArmingState.TRIGGERED: diff --git a/homeassistant/components/ness_alarm/manifest.json b/homeassistant/components/ness_alarm/manifest.json index d92a3d02c7a..e4c5b5fb344 100644 --- a/homeassistant/components/ness_alarm/manifest.json +++ b/homeassistant/components/ness_alarm/manifest.json @@ -5,5 +5,5 @@ "documentation": "https://www.home-assistant.io/integrations/ness_alarm", "iot_class": "local_push", "loggers": ["nessclient"], - "requirements": ["nessclient==0.10.0"] + "requirements": ["nessclient==1.0.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index db56052eb82..ec345859233 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1240,7 +1240,7 @@ nad-receiver==0.3.0 ndms2-client==0.1.2 # homeassistant.components.ness_alarm -nessclient==0.10.0 +nessclient==1.0.0 # homeassistant.components.netdata netdata==1.1.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index d69c88eb7a3..d65f0676a65 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -951,7 +951,7 @@ mutesync==0.0.1 ndms2-client==0.1.2 # homeassistant.components.ness_alarm -nessclient==0.10.0 +nessclient==1.0.0 # homeassistant.components.nmap_tracker netmap==0.7.0.2 diff --git a/tests/components/ness_alarm/test_init.py b/tests/components/ness_alarm/test_init.py index 908e23ec795..5bf48e0667e 100644 --- a/tests/components/ness_alarm/test_init.py +++ b/tests/components/ness_alarm/test_init.py @@ -1,7 +1,7 @@ """Tests for the ness_alarm component.""" -from enum import Enum from unittest.mock import MagicMock, patch +from nessclient import ArmingMode, ArmingState import pytest from homeassistant.components import alarm_control_panel @@ -24,6 +24,8 @@ from homeassistant.const import ( SERVICE_ALARM_DISARM, SERVICE_ALARM_TRIGGER, STATE_ALARM_ARMED_AWAY, + STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_NIGHT, STATE_ALARM_ARMING, STATE_ALARM_DISARMED, STATE_ALARM_PENDING, @@ -84,7 +86,7 @@ async def test_dispatch_state_change(hass: HomeAssistant, mock_nessclient) -> No await hass.async_block_till_done() on_state_change = mock_nessclient.on_state_change.call_args[0][0] - on_state_change(MockArmingState.ARMING) + on_state_change(ArmingState.ARMING, None) await hass.async_block_till_done() assert hass.states.is_state("alarm_control_panel.alarm_panel", STATE_ALARM_ARMING) @@ -174,13 +176,16 @@ async def test_dispatch_zone_change(hass: HomeAssistant, mock_nessclient) -> Non async def test_arming_state_change(hass: HomeAssistant, mock_nessclient) -> None: """Test arming state change handing.""" states = [ - (MockArmingState.UNKNOWN, STATE_UNKNOWN), - (MockArmingState.DISARMED, STATE_ALARM_DISARMED), - (MockArmingState.ARMING, STATE_ALARM_ARMING), - (MockArmingState.EXIT_DELAY, STATE_ALARM_ARMING), - (MockArmingState.ARMED, STATE_ALARM_ARMED_AWAY), - (MockArmingState.ENTRY_DELAY, STATE_ALARM_PENDING), - (MockArmingState.TRIGGERED, STATE_ALARM_TRIGGERED), + (ArmingState.UNKNOWN, None, STATE_UNKNOWN), + (ArmingState.DISARMED, None, STATE_ALARM_DISARMED), + (ArmingState.ARMING, None, STATE_ALARM_ARMING), + (ArmingState.EXIT_DELAY, None, STATE_ALARM_ARMING), + (ArmingState.ARMED, None, STATE_ALARM_ARMED_AWAY), + (ArmingState.ARMED, ArmingMode.ARMED_AWAY, STATE_ALARM_ARMED_AWAY), + (ArmingState.ARMED, ArmingMode.ARMED_HOME, STATE_ALARM_ARMED_HOME), + (ArmingState.ARMED, ArmingMode.ARMED_NIGHT, STATE_ALARM_ARMED_NIGHT), + (ArmingState.ENTRY_DELAY, None, STATE_ALARM_PENDING), + (ArmingState.TRIGGERED, None, STATE_ALARM_TRIGGERED), ] await async_setup_component(hass, DOMAIN, VALID_CONFIG) @@ -188,24 +193,12 @@ async def test_arming_state_change(hass: HomeAssistant, mock_nessclient) -> None assert hass.states.is_state("alarm_control_panel.alarm_panel", STATE_UNKNOWN) on_state_change = mock_nessclient.on_state_change.call_args[0][0] - for arming_state, expected_state in states: - on_state_change(arming_state) + for arming_state, arming_mode, expected_state in states: + on_state_change(arming_state, arming_mode) await hass.async_block_till_done() assert hass.states.is_state("alarm_control_panel.alarm_panel", expected_state) -class MockArmingState(Enum): - """Mock nessclient.ArmingState enum.""" - - UNKNOWN = "UNKNOWN" - DISARMED = "DISARMED" - ARMING = "ARMING" - EXIT_DELAY = "EXIT_DELAY" - ARMED = "ARMED" - ENTRY_DELAY = "ENTRY_DELAY" - TRIGGERED = "TRIGGERED" - - class MockClient: """Mock nessclient.Client stub.""" @@ -253,10 +246,5 @@ def mock_nessclient(): with patch( "homeassistant.components.ness_alarm.Client", new=_mock_factory, create=True - ), patch( - "homeassistant.components.ness_alarm.ArmingState", new=MockArmingState - ), patch( - "homeassistant.components.ness_alarm.alarm_control_panel.ArmingState", - new=MockArmingState, ): yield _mock_instance