From a9c73ac264208f7e719db3af1d0185b4fcd6a4ed Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 17 May 2021 04:18:50 -0700 Subject: [PATCH] Fix armed_night logic in totalconnect alarm and add tests (#50694) * Fix armed_night, add tests for alarm * end assertions with expected values --- .coveragerc | 1 - .../totalconnect/alarm_control_panel.py | 4 +- tests/components/totalconnect/common.py | 102 ++++++++++++ .../totalconnect/test_alarm_control_panel.py | 147 ++++++++++++++++++ 4 files changed, 251 insertions(+), 3 deletions(-) diff --git a/.coveragerc b/.coveragerc index 6f6fa152fa7..3b94df28fd9 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1057,7 +1057,6 @@ omit = homeassistant/components/toon/switch.py homeassistant/components/torque/sensor.py homeassistant/components/totalconnect/__init__.py - homeassistant/components/totalconnect/alarm_control_panel.py homeassistant/components/totalconnect/binary_sensor.py homeassistant/components/totalconnect/const.py homeassistant/components/touchline/climate.py diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index ae999ade9ac..7e88322eca1 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -89,10 +89,10 @@ class TotalConnectAlarm(alarm.AlarmControlPanelEntity): if self._client.locations[self._location_id].is_disarmed(): state = STATE_ALARM_DISARMED - elif self._client.locations[self._location_id].is_armed_home(): - state = STATE_ALARM_ARMED_HOME elif self._client.locations[self._location_id].is_armed_night(): state = STATE_ALARM_ARMED_NIGHT + elif self._client.locations[self._location_id].is_armed_home(): + state = STATE_ALARM_ARMED_HOME elif self._client.locations[self._location_id].is_armed_away(): state = STATE_ALARM_ARMED_AWAY elif self._client.locations[self._location_id].is_armed_custom_bypass(): diff --git a/tests/components/totalconnect/common.py b/tests/components/totalconnect/common.py index 6f9fef4b7c0..b092a028c0b 100644 --- a/tests/components/totalconnect/common.py +++ b/tests/components/totalconnect/common.py @@ -59,13 +59,71 @@ PARTITION_ARMED_AWAY = { "ArmingState": TotalConnectClient.TotalConnectLocation.ARMED_AWAY, } +PARTITION_ARMED_CUSTOM = { + "PartitionID": "1", + "ArmingState": TotalConnectClient.TotalConnectLocation.ARMED_CUSTOM_BYPASS, +} + +PARTITION_ARMED_NIGHT = { + "PartitionID": "1", + "ArmingState": TotalConnectClient.TotalConnectLocation.ARMED_STAY_NIGHT, +} + +PARTITION_ARMING = { + "PartitionID": "1", + "ArmingState": TotalConnectClient.TotalConnectLocation.ARMING, +} +PARTITION_DISARMING = { + "PartitionID": "1", + "ArmingState": TotalConnectClient.TotalConnectLocation.DISARMING, +} + +PARTITION_TRIGGERED_POLICE = { + "PartitionID": "1", + "ArmingState": TotalConnectClient.TotalConnectLocation.ALARMING, +} + +PARTITION_TRIGGERED_FIRE = { + "PartitionID": "1", + "ArmingState": TotalConnectClient.TotalConnectLocation.ALARMING_FIRE_SMOKE, +} + +PARTITION_TRIGGERED_CARBON_MONOXIDE = { + "PartitionID": "1", + "ArmingState": TotalConnectClient.TotalConnectLocation.ALARMING_CARBON_MONOXIDE, +} + +PARTITION_UNKNOWN = { + "PartitionID": "1", + "ArmingState": "99999", +} + + PARTITION_INFO_DISARMED = {0: PARTITION_DISARMED} PARTITION_INFO_ARMED_STAY = {0: PARTITION_ARMED_STAY} PARTITION_INFO_ARMED_AWAY = {0: PARTITION_ARMED_AWAY} +PARTITION_INFO_ARMED_CUSTOM = {0: PARTITION_ARMED_CUSTOM} +PARTITION_INFO_ARMED_NIGHT = {0: PARTITION_ARMED_NIGHT} +PARTITION_INFO_ARMING = {0: PARTITION_ARMING} +PARTITION_INFO_DISARMING = {0: PARTITION_DISARMING} +PARTITION_INFO_TRIGGERED_POLICE = {0: PARTITION_TRIGGERED_POLICE} +PARTITION_INFO_TRIGGERED_FIRE = {0: PARTITION_TRIGGERED_FIRE} +PARTITION_INFO_TRIGGERED_CARBON_MONOXIDE = {0: PARTITION_TRIGGERED_CARBON_MONOXIDE} +PARTITION_INFO_UNKNOWN = {0: PARTITION_UNKNOWN} PARTITIONS_DISARMED = {"PartitionInfo": PARTITION_INFO_DISARMED} PARTITIONS_ARMED_STAY = {"PartitionInfo": PARTITION_INFO_ARMED_STAY} PARTITIONS_ARMED_AWAY = {"PartitionInfo": PARTITION_INFO_ARMED_AWAY} +PARTITIONS_ARMED_CUSTOM = {"PartitionInfo": PARTITION_INFO_ARMED_CUSTOM} +PARTITIONS_ARMED_NIGHT = {"PartitionInfo": PARTITION_INFO_ARMED_NIGHT} +PARTITIONS_ARMING = {"PartitionInfo": PARTITION_INFO_ARMING} +PARTITIONS_DISARMING = {"PartitionInfo": PARTITION_INFO_DISARMING} +PARTITIONS_TRIGGERED_POLICE = {"PartitionInfo": PARTITION_INFO_TRIGGERED_POLICE} +PARTITIONS_TRIGGERED_FIRE = {"PartitionInfo": PARTITION_INFO_TRIGGERED_FIRE} +PARTITIONS_TRIGGERED_CARBON_MONOXIDE = { + "PartitionInfo": PARTITION_INFO_TRIGGERED_CARBON_MONOXIDE +} +PARTITIONS_UNKNOWN = {"PartitionInfo": PARTITION_INFO_UNKNOWN} ZONE_NORMAL = { "ZoneID": "1", @@ -94,9 +152,53 @@ METADATA_ARMED_STAY["Partitions"] = PARTITIONS_ARMED_STAY METADATA_ARMED_AWAY = METADATA_DISARMED.copy() METADATA_ARMED_AWAY["Partitions"] = PARTITIONS_ARMED_AWAY +METADATA_ARMED_CUSTOM = METADATA_DISARMED.copy() +METADATA_ARMED_CUSTOM["Partitions"] = PARTITIONS_ARMED_CUSTOM + +METADATA_ARMED_NIGHT = METADATA_DISARMED.copy() +METADATA_ARMED_NIGHT["Partitions"] = PARTITIONS_ARMED_NIGHT + +METADATA_ARMING = METADATA_DISARMED.copy() +METADATA_ARMING["Partitions"] = PARTITIONS_ARMING + +METADATA_DISARMING = METADATA_DISARMED.copy() +METADATA_DISARMING["Partitions"] = PARTITIONS_DISARMING + +METADATA_TRIGGERED_POLICE = METADATA_DISARMED.copy() +METADATA_TRIGGERED_POLICE["Partitions"] = PARTITIONS_TRIGGERED_POLICE + +METADATA_TRIGGERED_FIRE = METADATA_DISARMED.copy() +METADATA_TRIGGERED_FIRE["Partitions"] = PARTITIONS_TRIGGERED_FIRE + +METADATA_TRIGGERED_CARBON_MONOXIDE = METADATA_DISARMED.copy() +METADATA_TRIGGERED_CARBON_MONOXIDE["Partitions"] = PARTITIONS_TRIGGERED_CARBON_MONOXIDE + +METADATA_UNKNOWN = METADATA_DISARMED.copy() +METADATA_UNKNOWN["Partitions"] = PARTITIONS_UNKNOWN + RESPONSE_DISARMED = {"ResultCode": 0, "PanelMetadataAndStatus": METADATA_DISARMED} RESPONSE_ARMED_STAY = {"ResultCode": 0, "PanelMetadataAndStatus": METADATA_ARMED_STAY} RESPONSE_ARMED_AWAY = {"ResultCode": 0, "PanelMetadataAndStatus": METADATA_ARMED_AWAY} +RESPONSE_ARMED_CUSTOM = { + "ResultCode": 0, + "PanelMetadataAndStatus": METADATA_ARMED_CUSTOM, +} +RESPONSE_ARMED_NIGHT = {"ResultCode": 0, "PanelMetadataAndStatus": METADATA_ARMED_NIGHT} +RESPONSE_ARMING = {"ResultCode": 0, "PanelMetadataAndStatus": METADATA_ARMING} +RESPONSE_DISARMING = {"ResultCode": 0, "PanelMetadataAndStatus": METADATA_DISARMING} +RESPONSE_TRIGGERED_POLICE = { + "ResultCode": 0, + "PanelMetadataAndStatus": METADATA_TRIGGERED_POLICE, +} +RESPONSE_TRIGGERED_FIRE = { + "ResultCode": 0, + "PanelMetadataAndStatus": METADATA_TRIGGERED_FIRE, +} +RESPONSE_TRIGGERED_CARBON_MONOXIDE = { + "ResultCode": 0, + "PanelMetadataAndStatus": METADATA_TRIGGERED_CARBON_MONOXIDE, +} +RESPONSE_UNKNOWN = {"ResultCode": 0, "PanelMetadataAndStatus": METADATA_UNKNOWN} RESPONSE_ARM_SUCCESS = {"ResultCode": TotalConnectClient.TotalConnectClient.ARM_SUCCESS} RESPONSE_ARM_FAILURE = { diff --git a/tests/components/totalconnect/test_alarm_control_panel.py b/tests/components/totalconnect/test_alarm_control_panel.py index 9d8dbaf0358..a77adea5e27 100644 --- a/tests/components/totalconnect/test_alarm_control_panel.py +++ b/tests/components/totalconnect/test_alarm_control_panel.py @@ -9,10 +9,16 @@ from homeassistant.const import ( ATTR_FRIENDLY_NAME, SERVICE_ALARM_ARM_AWAY, SERVICE_ALARM_ARM_HOME, + SERVICE_ALARM_ARM_NIGHT, SERVICE_ALARM_DISARM, STATE_ALARM_ARMED_AWAY, + STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_NIGHT, + STATE_ALARM_ARMING, STATE_ALARM_DISARMED, + STATE_ALARM_DISARMING, + STATE_ALARM_TRIGGERED, ) from homeassistant.exceptions import HomeAssistantError @@ -21,10 +27,19 @@ from .common import ( RESPONSE_ARM_FAILURE, RESPONSE_ARM_SUCCESS, RESPONSE_ARMED_AWAY, + RESPONSE_ARMED_CUSTOM, + RESPONSE_ARMED_NIGHT, RESPONSE_ARMED_STAY, + RESPONSE_ARMING, RESPONSE_DISARM_FAILURE, RESPONSE_DISARM_SUCCESS, RESPONSE_DISARMED, + RESPONSE_DISARMING, + RESPONSE_SUCCESS, + RESPONSE_TRIGGERED_CARBON_MONOXIDE, + RESPONSE_TRIGGERED_FIRE, + RESPONSE_TRIGGERED_POLICE, + RESPONSE_UNKNOWN, RESPONSE_USER_CODE_INVALID, setup_platform, ) @@ -197,3 +212,135 @@ async def test_disarm_invalid_usercode(hass): await hass.async_block_till_done() assert f"{err.value}" == "TotalConnect failed to disarm test." assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_AWAY + + +async def test_arm_night_success(hass): + """Test arm night method success.""" + responses = [RESPONSE_DISARMED, RESPONSE_ARM_SUCCESS, RESPONSE_ARMED_NIGHT] + with patch( + "homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request", + side_effect=responses, + ): + await setup_platform(hass, ALARM_DOMAIN) + assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED + + await hass.services.async_call( + ALARM_DOMAIN, SERVICE_ALARM_ARM_NIGHT, DATA, blocking=True + ) + + await hass.async_block_till_done() + assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_NIGHT + + +async def test_arm_night_failure(hass): + """Test arm night method failure.""" + responses = [RESPONSE_DISARMED, RESPONSE_ARM_FAILURE, RESPONSE_DISARMED] + with patch( + "homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request", + side_effect=responses, + ): + await setup_platform(hass, ALARM_DOMAIN) + assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED + + with pytest.raises(HomeAssistantError) as err: + await hass.services.async_call( + ALARM_DOMAIN, SERVICE_ALARM_ARM_NIGHT, DATA, blocking=True + ) + await hass.async_block_till_done() + assert f"{err.value}" == "TotalConnect failed to arm night test." + assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED + + +async def test_arming(hass): + """Test arming.""" + responses = [RESPONSE_DISARMED, RESPONSE_SUCCESS, RESPONSE_ARMING] + with patch( + "homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request", + side_effect=responses, + ): + await setup_platform(hass, ALARM_DOMAIN) + assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED + + await hass.services.async_call( + ALARM_DOMAIN, SERVICE_ALARM_ARM_NIGHT, DATA, blocking=True + ) + assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMING + + +async def test_disarming(hass): + """Test disarming.""" + responses = [RESPONSE_ARMED_AWAY, RESPONSE_SUCCESS, RESPONSE_DISARMING] + with patch( + "homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request", + side_effect=responses, + ): + await setup_platform(hass, ALARM_DOMAIN) + assert hass.states.get(ENTITY_ID).state == STATE_ALARM_ARMED_AWAY + + await hass.services.async_call( + ALARM_DOMAIN, SERVICE_ALARM_DISARM, DATA, blocking=True + ) + assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMING + + +async def test_triggered_fire(hass): + """Test triggered by fire.""" + responses = [RESPONSE_TRIGGERED_FIRE] + with patch( + "homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request", + side_effect=responses, + ): + await setup_platform(hass, ALARM_DOMAIN) + state = hass.states.get(ENTITY_ID) + assert state.state == STATE_ALARM_TRIGGERED + assert state.attributes.get("triggered_source") == "Fire/Smoke" + + +async def test_triggered_police(hass): + """Test triggered by police.""" + responses = [RESPONSE_TRIGGERED_POLICE] + with patch( + "homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request", + side_effect=responses, + ): + await setup_platform(hass, ALARM_DOMAIN) + state = hass.states.get(ENTITY_ID) + assert state.state == STATE_ALARM_TRIGGERED + assert state.attributes.get("triggered_source") == "Police/Medical" + + +async def test_triggered_carbon_monoxide(hass): + """Test triggered by carbon monoxide.""" + responses = [RESPONSE_TRIGGERED_CARBON_MONOXIDE] + with patch( + "homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request", + side_effect=responses, + ): + await setup_platform(hass, ALARM_DOMAIN) + state = hass.states.get(ENTITY_ID) + assert state.state == STATE_ALARM_TRIGGERED + assert state.attributes.get("triggered_source") == "Carbon Monoxide" + + +async def test_armed_custom(hass): + """Test armed custom.""" + responses = [RESPONSE_ARMED_CUSTOM] + with patch( + "homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request", + side_effect=responses, + ): + await setup_platform(hass, ALARM_DOMAIN) + state = hass.states.get(ENTITY_ID) + assert state.state == STATE_ALARM_ARMED_CUSTOM_BYPASS + + +async def test_unknown(hass): + """Test unknown arm status.""" + responses = [RESPONSE_UNKNOWN] + with patch( + "homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request", + side_effect=responses, + ): + await setup_platform(hass, ALARM_DOMAIN) + state = hass.states.get(ENTITY_ID) + assert state.state == "unknown"