mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 04:07:08 +00:00
Notify user if arming or disarming totalconnect alarm fails (#36085)
This commit is contained in:
parent
1186c2c48c
commit
98a056f7a9
@ -17,6 +17,7 @@ from homeassistant.const import (
|
|||||||
STATE_ALARM_DISARMING,
|
STATE_ALARM_DISARMING,
|
||||||
STATE_ALARM_TRIGGERED,
|
STATE_ALARM_TRIGGERED,
|
||||||
)
|
)
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
|
|
||||||
@ -114,16 +115,20 @@ class TotalConnectAlarm(alarm.AlarmControlPanelEntity):
|
|||||||
|
|
||||||
def alarm_disarm(self, code=None):
|
def alarm_disarm(self, code=None):
|
||||||
"""Send disarm command."""
|
"""Send disarm command."""
|
||||||
self._client.disarm(self._location_id)
|
if self._client.disarm(self._location_id) is not True:
|
||||||
|
raise HomeAssistantError(f"TotalConnect failed to disarm {self._name}.")
|
||||||
|
|
||||||
def alarm_arm_home(self, code=None):
|
def alarm_arm_home(self, code=None):
|
||||||
"""Send arm home command."""
|
"""Send arm home command."""
|
||||||
self._client.arm_stay(self._location_id)
|
if self._client.arm_stay(self._location_id) is not True:
|
||||||
|
raise HomeAssistantError(f"TotalConnect failed to arm home {self._name}.")
|
||||||
|
|
||||||
def alarm_arm_away(self, code=None):
|
def alarm_arm_away(self, code=None):
|
||||||
"""Send arm away command."""
|
"""Send arm away command."""
|
||||||
self._client.arm_away(self._location_id)
|
if self._client.arm_away(self._location_id) is not True:
|
||||||
|
raise HomeAssistantError(f"TotalConnect failed to arm away {self._name}.")
|
||||||
|
|
||||||
def alarm_arm_night(self, code=None):
|
def alarm_arm_night(self, code=None):
|
||||||
"""Send arm night command."""
|
"""Send arm night command."""
|
||||||
self._client.arm_stay_night(self._location_id)
|
if self._client.arm_stay_night(self._location_id) is not True:
|
||||||
|
raise HomeAssistantError(f"TotalConnect failed to arm night {self._name}.")
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"domain": "totalconnect",
|
"domain": "totalconnect",
|
||||||
"name": "Honeywell Total Connect Alarm",
|
"name": "Honeywell Total Connect Alarm",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/totalconnect",
|
"documentation": "https://www.home-assistant.io/integrations/totalconnect",
|
||||||
"requirements": ["total_connect_client==0.54.1"],
|
"requirements": ["total_connect_client==0.55"],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"codeowners": ["@austinmroczek"],
|
"codeowners": ["@austinmroczek"],
|
||||||
"config_flow": true
|
"config_flow": true
|
||||||
|
@ -2102,7 +2102,7 @@ todoist-python==8.0.0
|
|||||||
toonapilib==3.2.4
|
toonapilib==3.2.4
|
||||||
|
|
||||||
# homeassistant.components.totalconnect
|
# homeassistant.components.totalconnect
|
||||||
total_connect_client==0.54.1
|
total_connect_client==0.55
|
||||||
|
|
||||||
# homeassistant.components.tplink_lte
|
# homeassistant.components.tplink_lte
|
||||||
tp-connected==0.0.4
|
tp-connected==0.0.4
|
||||||
|
@ -853,7 +853,7 @@ teslajsonpy==0.8.1
|
|||||||
toonapilib==3.2.4
|
toonapilib==3.2.4
|
||||||
|
|
||||||
# homeassistant.components.totalconnect
|
# homeassistant.components.totalconnect
|
||||||
total_connect_client==0.54.1
|
total_connect_client==0.55
|
||||||
|
|
||||||
# homeassistant.components.transmission
|
# homeassistant.components.transmission
|
||||||
transmissionrpc==0.11
|
transmissionrpc==0.11
|
||||||
|
129
tests/components/totalconnect/common.py
Normal file
129
tests/components/totalconnect/common.py
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
"""Common methods used across tests for TotalConnect."""
|
||||||
|
from total_connect_client import TotalConnectClient
|
||||||
|
|
||||||
|
from homeassistant.components.totalconnect import DOMAIN
|
||||||
|
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
from tests.async_mock import patch
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
LOCATION_INFO_BASIC_NORMAL = {
|
||||||
|
"LocationID": "123456",
|
||||||
|
"LocationName": "test",
|
||||||
|
"SecurityDeviceID": "987654",
|
||||||
|
"PhotoURL": "http://www.example.com/some/path/to/file.jpg",
|
||||||
|
"LocationModuleFlags": "Security=1,Video=0,Automation=0,GPS=0,VideoPIR=0",
|
||||||
|
"DeviceList": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCATIONS = {"LocationInfoBasic": [LOCATION_INFO_BASIC_NORMAL]}
|
||||||
|
|
||||||
|
MODULE_FLAGS = "Some=0,Fake=1,Flags=2"
|
||||||
|
|
||||||
|
USER = {
|
||||||
|
"UserID": "1234567",
|
||||||
|
"Username": "username",
|
||||||
|
"UserFeatureList": "Master=0,User Administration=0,Configuration Administration=0",
|
||||||
|
}
|
||||||
|
|
||||||
|
RESPONSE_AUTHENTICATE = {
|
||||||
|
"ResultCode": 0,
|
||||||
|
"SessionID": 1,
|
||||||
|
"Locations": LOCATIONS,
|
||||||
|
"ModuleFlags": MODULE_FLAGS,
|
||||||
|
"UserInfo": USER,
|
||||||
|
}
|
||||||
|
|
||||||
|
PARTITION_DISARMED = {
|
||||||
|
"PartitionID": "1",
|
||||||
|
"ArmingState": TotalConnectClient.TotalConnectLocation.DISARMED,
|
||||||
|
}
|
||||||
|
|
||||||
|
PARTITION_ARMED_STAY = {
|
||||||
|
"PartitionID": "1",
|
||||||
|
"ArmingState": TotalConnectClient.TotalConnectLocation.ARMED_STAY,
|
||||||
|
}
|
||||||
|
|
||||||
|
PARTITION_ARMED_AWAY = {
|
||||||
|
"PartitionID": "1",
|
||||||
|
"ArmingState": TotalConnectClient.TotalConnectLocation.ARMED_AWAY,
|
||||||
|
}
|
||||||
|
|
||||||
|
PARTITION_INFO_DISARMED = {0: PARTITION_DISARMED}
|
||||||
|
PARTITION_INFO_ARMED_STAY = {0: PARTITION_ARMED_STAY}
|
||||||
|
PARTITION_INFO_ARMED_AWAY = {0: PARTITION_ARMED_AWAY}
|
||||||
|
|
||||||
|
PARTITIONS_DISARMED = {"PartitionInfo": PARTITION_INFO_DISARMED}
|
||||||
|
PARTITIONS_ARMED_STAY = {"PartitionInfo": PARTITION_INFO_ARMED_STAY}
|
||||||
|
PARTITIONS_ARMED_AWAY = {"PartitionInfo": PARTITION_INFO_ARMED_AWAY}
|
||||||
|
|
||||||
|
ZONE_NORMAL = {
|
||||||
|
"ZoneID": "1",
|
||||||
|
"ZoneDescription": "Normal",
|
||||||
|
"ZoneStatus": TotalConnectClient.ZONE_STATUS_NORMAL,
|
||||||
|
"PartitionId": "1",
|
||||||
|
}
|
||||||
|
|
||||||
|
ZONE_INFO = [ZONE_NORMAL]
|
||||||
|
ZONES = {"ZoneInfo": ZONE_INFO}
|
||||||
|
|
||||||
|
METADATA_DISARMED = {
|
||||||
|
"Partitions": PARTITIONS_DISARMED,
|
||||||
|
"Zones": ZONES,
|
||||||
|
"PromptForImportSecuritySettings": False,
|
||||||
|
"IsInACLoss": False,
|
||||||
|
"IsCoverTampered": False,
|
||||||
|
"Bell1SupervisionFailure": False,
|
||||||
|
"Bell2SupervisionFailure": False,
|
||||||
|
"IsInLowBattery": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
METADATA_ARMED_STAY = METADATA_DISARMED.copy()
|
||||||
|
METADATA_ARMED_STAY["Partitions"] = PARTITIONS_ARMED_STAY
|
||||||
|
|
||||||
|
METADATA_ARMED_AWAY = METADATA_DISARMED.copy()
|
||||||
|
METADATA_ARMED_AWAY["Partitions"] = PARTITIONS_ARMED_AWAY
|
||||||
|
|
||||||
|
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_ARM_SUCCESS = {"ResultCode": TotalConnectClient.TotalConnectClient.ARM_SUCCESS}
|
||||||
|
RESPONSE_ARM_FAILURE = {
|
||||||
|
"ResultCode": TotalConnectClient.TotalConnectClient.COMMAND_FAILED
|
||||||
|
}
|
||||||
|
RESPONSE_DISARM_SUCCESS = {
|
||||||
|
"ResultCode": TotalConnectClient.TotalConnectClient.DISARM_SUCCESS
|
||||||
|
}
|
||||||
|
RESPONSE_DISARM_FAILURE = {
|
||||||
|
"ResultCode": TotalConnectClient.TotalConnectClient.COMMAND_FAILED,
|
||||||
|
"ResultData": "Command Failed",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def setup_platform(hass, platform):
|
||||||
|
"""Set up the TotalConnect platform."""
|
||||||
|
# first set up a config entry and add it to hass
|
||||||
|
mock_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={CONF_USERNAME: "user@email.com", CONF_PASSWORD: "password"},
|
||||||
|
)
|
||||||
|
mock_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
responses = [RESPONSE_AUTHENTICATE, RESPONSE_DISARMED]
|
||||||
|
|
||||||
|
with patch("homeassistant.components.totalconnect.PLATFORMS", [platform]), patch(
|
||||||
|
"zeep.Client", autospec=True
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request",
|
||||||
|
side_effect=responses,
|
||||||
|
) as mock_request, patch(
|
||||||
|
"homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.get_zone_details",
|
||||||
|
return_value=True,
|
||||||
|
):
|
||||||
|
assert await async_setup_component(hass, DOMAIN, {})
|
||||||
|
assert mock_request.call_count == 2
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
return mock_entry
|
153
tests/components/totalconnect/test_alarm_control_panel.py
Normal file
153
tests/components/totalconnect/test_alarm_control_panel.py
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
"""Tests for the TotalConnect alarm control panel device."""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.alarm_control_panel import DOMAIN as ALARM_DOMAIN
|
||||||
|
from homeassistant.const import (
|
||||||
|
ATTR_ENTITY_ID,
|
||||||
|
ATTR_FRIENDLY_NAME,
|
||||||
|
SERVICE_ALARM_ARM_AWAY,
|
||||||
|
SERVICE_ALARM_ARM_HOME,
|
||||||
|
SERVICE_ALARM_DISARM,
|
||||||
|
STATE_ALARM_ARMED_AWAY,
|
||||||
|
STATE_ALARM_ARMED_HOME,
|
||||||
|
STATE_ALARM_DISARMED,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .common import (
|
||||||
|
RESPONSE_ARM_FAILURE,
|
||||||
|
RESPONSE_ARM_SUCCESS,
|
||||||
|
RESPONSE_ARMED_AWAY,
|
||||||
|
RESPONSE_ARMED_STAY,
|
||||||
|
RESPONSE_DISARM_FAILURE,
|
||||||
|
RESPONSE_DISARM_SUCCESS,
|
||||||
|
RESPONSE_DISARMED,
|
||||||
|
setup_platform,
|
||||||
|
)
|
||||||
|
|
||||||
|
from tests.async_mock import patch
|
||||||
|
|
||||||
|
ENTITY_ID = "alarm_control_panel.test"
|
||||||
|
CODE = "-1"
|
||||||
|
DATA = {ATTR_ENTITY_ID: ENTITY_ID}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_attributes(hass):
|
||||||
|
"""Test the alarm control panel attributes are correct."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request",
|
||||||
|
return_value=RESPONSE_DISARMED,
|
||||||
|
) as mock_request:
|
||||||
|
await setup_platform(hass, ALARM_DOMAIN)
|
||||||
|
state = hass.states.get(ENTITY_ID)
|
||||||
|
assert state.state == STATE_ALARM_DISARMED
|
||||||
|
mock_request.assert_called_once()
|
||||||
|
assert state.attributes.get(ATTR_FRIENDLY_NAME) == "test"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_arm_home_success(hass):
|
||||||
|
"""Test arm home method success."""
|
||||||
|
responses = [RESPONSE_DISARMED, RESPONSE_ARM_SUCCESS, RESPONSE_ARMED_STAY]
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request",
|
||||||
|
side_effect=responses,
|
||||||
|
):
|
||||||
|
await setup_platform(hass, ALARM_DOMAIN)
|
||||||
|
assert STATE_ALARM_DISARMED == hass.states.get(ENTITY_ID).state
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
ALARM_DOMAIN, SERVICE_ALARM_ARM_HOME, DATA, blocking=True
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert STATE_ALARM_ARMED_HOME == hass.states.get(ENTITY_ID).state
|
||||||
|
|
||||||
|
|
||||||
|
async def test_arm_home_failure(hass):
|
||||||
|
"""Test arm home 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 STATE_ALARM_DISARMED == hass.states.get(ENTITY_ID).state
|
||||||
|
|
||||||
|
with pytest.raises(Exception) as e:
|
||||||
|
await hass.services.async_call(
|
||||||
|
ALARM_DOMAIN, SERVICE_ALARM_ARM_HOME, DATA, blocking=True
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert f"{e.value}" == "TotalConnect failed to arm home test."
|
||||||
|
assert STATE_ALARM_DISARMED == hass.states.get(ENTITY_ID).state
|
||||||
|
|
||||||
|
|
||||||
|
async def test_arm_away_success(hass):
|
||||||
|
"""Test arm away method success."""
|
||||||
|
responses = [RESPONSE_DISARMED, RESPONSE_ARM_SUCCESS, RESPONSE_ARMED_AWAY]
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request",
|
||||||
|
side_effect=responses,
|
||||||
|
):
|
||||||
|
await setup_platform(hass, ALARM_DOMAIN)
|
||||||
|
assert STATE_ALARM_DISARMED == hass.states.get(ENTITY_ID).state
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
ALARM_DOMAIN, SERVICE_ALARM_ARM_AWAY, DATA, blocking=True
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert STATE_ALARM_ARMED_AWAY == hass.states.get(ENTITY_ID).state
|
||||||
|
|
||||||
|
|
||||||
|
async def test_arm_away_failure(hass):
|
||||||
|
"""Test arm away 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 STATE_ALARM_DISARMED == hass.states.get(ENTITY_ID).state
|
||||||
|
|
||||||
|
with pytest.raises(Exception) as e:
|
||||||
|
await hass.services.async_call(
|
||||||
|
ALARM_DOMAIN, SERVICE_ALARM_ARM_AWAY, DATA, blocking=True
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert f"{e.value}" == "TotalConnect failed to arm away test."
|
||||||
|
assert STATE_ALARM_DISARMED == hass.states.get(ENTITY_ID).state
|
||||||
|
|
||||||
|
|
||||||
|
async def test_disarm_success(hass):
|
||||||
|
"""Test disarm method success."""
|
||||||
|
responses = [RESPONSE_ARMED_AWAY, RESPONSE_DISARM_SUCCESS, RESPONSE_DISARMED]
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request",
|
||||||
|
side_effect=responses,
|
||||||
|
):
|
||||||
|
await setup_platform(hass, ALARM_DOMAIN)
|
||||||
|
assert STATE_ALARM_ARMED_AWAY == hass.states.get(ENTITY_ID).state
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
ALARM_DOMAIN, SERVICE_ALARM_DISARM, DATA, blocking=True
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert STATE_ALARM_DISARMED == hass.states.get(ENTITY_ID).state
|
||||||
|
|
||||||
|
|
||||||
|
async def test_disarm_failure(hass):
|
||||||
|
"""Test disarm method failure."""
|
||||||
|
responses = [RESPONSE_ARMED_AWAY, RESPONSE_DISARM_FAILURE, RESPONSE_ARMED_AWAY]
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.totalconnect.TotalConnectClient.TotalConnectClient.request",
|
||||||
|
side_effect=responses,
|
||||||
|
):
|
||||||
|
await setup_platform(hass, ALARM_DOMAIN)
|
||||||
|
assert STATE_ALARM_ARMED_AWAY == hass.states.get(ENTITY_ID).state
|
||||||
|
|
||||||
|
with pytest.raises(Exception) as e:
|
||||||
|
await hass.services.async_call(
|
||||||
|
ALARM_DOMAIN, SERVICE_ALARM_DISARM, DATA, blocking=True
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert f"{e.value}" == "TotalConnect failed to disarm test."
|
||||||
|
assert STATE_ALARM_ARMED_AWAY == hass.states.get(ENTITY_ID).state
|
Loading…
x
Reference in New Issue
Block a user