From 60e7440ec188b1e82e76dcb533820d857ccd3d10 Mon Sep 17 00:00:00 2001 From: SukramJ Date: Fri, 15 Nov 2019 09:55:40 +0100 Subject: [PATCH] Fix HomematicIP Cloud Alarm Control Panel support for basic mode (#28778) --- .../homematicip_cloud/alarm_control_panel.py | 67 +++-------------- .../test_alarm_control_panel.py | 72 +++++-------------- .../homematicip_cloud/test_climate.py | 1 + .../components/homematicip_cloud/test_init.py | 4 +- 4 files changed, 31 insertions(+), 113 deletions(-) diff --git a/homeassistant/components/homematicip_cloud/alarm_control_panel.py b/homeassistant/components/homematicip_cloud/alarm_control_panel.py index a7b1beaec93..8ebb35b12c1 100644 --- a/homeassistant/components/homematicip_cloud/alarm_control_panel.py +++ b/homeassistant/components/homematicip_cloud/alarm_control_panel.py @@ -1,8 +1,7 @@ """Support for HomematicIP Cloud alarm control panel.""" import logging -from homematicip.aio.group import AsyncSecurityZoneGroup -from homematicip.base.enums import WindowState +from homematicip.functionalHomes import SecurityAndAlarmHome from homeassistant.components.alarm_control_panel import AlarmControlPanel from homeassistant.config_entries import ConfigEntry @@ -32,34 +31,15 @@ async def async_setup_entry( ) -> None: """Set up the HomematicIP alrm control panel from a config entry.""" hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]] - devices = [] - security_zones = [] - for group in hap.home.groups: - if isinstance(group, AsyncSecurityZoneGroup): - security_zones.append(group) - - if security_zones: - devices.append(HomematicipAlarmControlPanel(hap, security_zones)) - - if devices: - async_add_entities(devices) + async_add_entities([HomematicipAlarmControlPanel(hap)]) class HomematicipAlarmControlPanel(AlarmControlPanel): """Representation of an alarm control panel.""" - def __init__(self, hap: HomematicipHAP, security_zones) -> None: + def __init__(self, hap: HomematicipHAP) -> None: """Initialize the alarm control panel.""" self._home = hap.home - self.alarm_state = STATE_ALARM_DISARMED - self._internal_alarm_zone = None - self._external_alarm_zone = None - - for security_zone in security_zones: - if security_zone.label == "INTERNAL": - self._internal_alarm_zone = security_zone - elif security_zone.label == "EXTERNAL": - self._external_alarm_zone = security_zone @property def device_info(self): @@ -75,28 +55,23 @@ class HomematicipAlarmControlPanel(AlarmControlPanel): @property def state(self) -> str: """Return the state of the device.""" + # check for triggered alarm + if self._security_and_alarm.alarmActive: + return STATE_ALARM_TRIGGERED + activation_state = self._home.get_security_zones_activation() # check arm_away if activation_state == (True, True): - if self._internal_alarm_zone_state or self._external_alarm_zone_state: - return STATE_ALARM_TRIGGERED return STATE_ALARM_ARMED_AWAY # check arm_home if activation_state == (False, True): - if self._external_alarm_zone_state: - return STATE_ALARM_TRIGGERED return STATE_ALARM_ARMED_HOME return STATE_ALARM_DISARMED @property - def _internal_alarm_zone_state(self) -> bool: - return _get_zone_alarm_state(self._internal_alarm_zone) - - @property - def _external_alarm_zone_state(self) -> bool: - """Return the state of the device.""" - return _get_zone_alarm_state(self._external_alarm_zone) + def _security_and_alarm(self): + return self._home.get_functionalHome(SecurityAndAlarmHome) async def async_alarm_disarm(self, code=None): """Send disarm command.""" @@ -112,10 +87,7 @@ class HomematicipAlarmControlPanel(AlarmControlPanel): async def async_added_to_hass(self): """Register callbacks.""" - if self._internal_alarm_zone: - self._internal_alarm_zone.on_update(self._async_device_changed) - if self._external_alarm_zone: - self._external_alarm_zone.on_update(self._async_device_changed) + self._home.on_update(self._async_device_changed) def _async_device_changed(self, *args, **kwargs): """Handle device state changes.""" @@ -138,26 +110,9 @@ class HomematicipAlarmControlPanel(AlarmControlPanel): @property def available(self) -> bool: """Device available.""" - return ( - not self._internal_alarm_zone.unreach - or not self._external_alarm_zone.unreach - ) + return self._home.connected @property def unique_id(self) -> str: """Return a unique ID.""" return f"{self.__class__.__name__}_{self._home.id}" - - -def _get_zone_alarm_state(security_zone) -> bool: - if security_zone and security_zone.active: - if ( - security_zone.sabotage - or security_zone.motionDetected - or security_zone.presenceDetected - or security_zone.windowState == WindowState.OPEN - or security_zone.windowState == WindowState.TILTED - ): - return True - - return False diff --git a/tests/components/homematicip_cloud/test_alarm_control_panel.py b/tests/components/homematicip_cloud/test_alarm_control_panel.py index 2798a0879b7..78bc0a09ea5 100644 --- a/tests/components/homematicip_cloud/test_alarm_control_panel.py +++ b/tests/components/homematicip_cloud/test_alarm_control_panel.py @@ -1,7 +1,4 @@ """Tests for HomematicIP Cloud alarm control panel.""" -from homematicip.base.enums import WindowState -from homematicip.group import SecurityZoneGroup - from homeassistant.components.alarm_control_panel import ( DOMAIN as ALARM_CONTROL_PANEL_DOMAIN, ) @@ -17,29 +14,24 @@ from homeassistant.setup import async_setup_component from .helper import get_and_check_entity_basics -def _get_security_zones(groups): # pylint: disable=W0221 - """Get the security zones.""" - for group in groups: - if isinstance(group, SecurityZoneGroup): - if group.label == "EXTERNAL": - external = group - elif group.label == "INTERNAL": - internal = group - return internal, external - - async def _async_manipulate_security_zones( - hass, home, internal_active, external_active, window_state + hass, home, internal_active=False, external_active=False, alarm_triggered=False ): """Set new values on hmip security zones.""" - internal_zone, external_zone = _get_security_zones(home.groups) + json = home._rawJSONData # pylint: disable=W0212 + json["functionalHomes"]["SECURITY_AND_ALARM"]["alarmActive"] = alarm_triggered + external_zone_id = json["functionalHomes"]["SECURITY_AND_ALARM"]["securityZones"][ + "EXTERNAL" + ] + internal_zone_id = json["functionalHomes"]["SECURITY_AND_ALARM"]["securityZones"][ + "INTERNAL" + ] + external_zone = home.search_group_by_id(external_zone_id) external_zone.active = external_active - external_zone.windowState = window_state + internal_zone = home.search_group_by_id(internal_zone_id) internal_zone.active = internal_active - # Just one call to a security zone is required to refresh the ACP. - internal_zone.fire_update_event() - + home.fire_update_event(json) await hass.async_block_till_done() @@ -70,79 +62,49 @@ async def test_hmip_alarm_control_panel(hass, default_mock_hap): assert not hmip_device home = default_mock_hap.home - service_call_counter = len(home.mock_calls) await hass.services.async_call( "alarm_control_panel", "alarm_arm_away", {"entity_id": entity_id}, blocking=True ) - assert len(home.mock_calls) == service_call_counter + 1 assert home.mock_calls[-1][0] == "set_security_zones_activation" assert home.mock_calls[-1][1] == (True, True) await _async_manipulate_security_zones( - hass, - home, - internal_active=True, - external_active=True, - window_state=WindowState.CLOSED, + hass, home, internal_active=True, external_active=True ) assert hass.states.get(entity_id).state is STATE_ALARM_ARMED_AWAY await hass.services.async_call( "alarm_control_panel", "alarm_arm_home", {"entity_id": entity_id}, blocking=True ) - assert len(home.mock_calls) == service_call_counter + 3 assert home.mock_calls[-1][0] == "set_security_zones_activation" assert home.mock_calls[-1][1] == (False, True) - await _async_manipulate_security_zones( - hass, - home, - internal_active=False, - external_active=True, - window_state=WindowState.CLOSED, - ) + await _async_manipulate_security_zones(hass, home, external_active=True) assert hass.states.get(entity_id).state is STATE_ALARM_ARMED_HOME await hass.services.async_call( "alarm_control_panel", "alarm_disarm", {"entity_id": entity_id}, blocking=True ) - assert len(home.mock_calls) == service_call_counter + 5 assert home.mock_calls[-1][0] == "set_security_zones_activation" assert home.mock_calls[-1][1] == (False, False) - await _async_manipulate_security_zones( - hass, - home, - internal_active=False, - external_active=False, - window_state=WindowState.CLOSED, - ) + await _async_manipulate_security_zones(hass, home) assert hass.states.get(entity_id).state is STATE_ALARM_DISARMED await hass.services.async_call( "alarm_control_panel", "alarm_arm_away", {"entity_id": entity_id}, blocking=True ) - assert len(home.mock_calls) == service_call_counter + 7 assert home.mock_calls[-1][0] == "set_security_zones_activation" assert home.mock_calls[-1][1] == (True, True) await _async_manipulate_security_zones( - hass, - home, - internal_active=True, - external_active=True, - window_state=WindowState.OPEN, + hass, home, internal_active=True, external_active=True, alarm_triggered=True ) assert hass.states.get(entity_id).state is STATE_ALARM_TRIGGERED await hass.services.async_call( "alarm_control_panel", "alarm_arm_home", {"entity_id": entity_id}, blocking=True ) - assert len(home.mock_calls) == service_call_counter + 9 assert home.mock_calls[-1][0] == "set_security_zones_activation" assert home.mock_calls[-1][1] == (False, True) await _async_manipulate_security_zones( - hass, - home, - internal_active=False, - external_active=True, - window_state=WindowState.OPEN, + hass, home, external_active=True, alarm_triggered=True ) assert hass.states.get(entity_id).state is STATE_ALARM_TRIGGERED diff --git a/tests/components/homematicip_cloud/test_climate.py b/tests/components/homematicip_cloud/test_climate.py index 858fba29563..2b233a6dee2 100644 --- a/tests/components/homematicip_cloud/test_climate.py +++ b/tests/components/homematicip_cloud/test_climate.py @@ -343,6 +343,7 @@ async def test_hmip_heating_group_heat_with_switch(hass, default_mock_hap): hass, default_mock_hap, entity_id, entity_name, device_model ) + assert hmip_device assert ha_state.state == HVAC_MODE_AUTO assert ha_state.attributes["current_temperature"] == 24.7 assert ha_state.attributes["min_temp"] == 5.0 diff --git a/tests/components/homematicip_cloud/test_init.py b/tests/components/homematicip_cloud/test_init.py index ba27a619e6a..eb51c3ece38 100644 --- a/tests/components/homematicip_cloud/test_init.py +++ b/tests/components/homematicip_cloud/test_init.py @@ -161,5 +161,5 @@ async def test_hmip_dump_hap_config_services(hass, mock_hap_with_service): ) home = mock_hap_with_service.home assert home.mock_calls[-1][0] == "download_configuration" - assert len(home.mock_calls) == 8 # pylint: disable=W0212 - assert len(write_mock.mock_calls) > 0 + assert home.mock_calls + assert write_mock.mock_calls