From dd53434742d871766edabcb9c58b3ecde62d19d3 Mon Sep 17 00:00:00 2001 From: Markus Jankowski Date: Wed, 1 May 2019 21:35:57 +0200 Subject: [PATCH] Redesign AlarmControlPanel for Homematic IP (#23565) * redesign AlarmControlPanel * Fix lint * Fixes after review --- .../homematicip_cloud/alarm_control_panel.py | 112 ++++++++++++++++++ .../components/homematicip_cloud/device.py | 4 +- 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/homematicip_cloud/alarm_control_panel.py b/homeassistant/components/homematicip_cloud/alarm_control_panel.py index c2ad23700f3..1e072c6784c 100644 --- a/homeassistant/components/homematicip_cloud/alarm_control_panel.py +++ b/homeassistant/components/homematicip_cloud/alarm_control_panel.py @@ -16,6 +16,8 @@ from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice _LOGGER = logging.getLogger(__name__) +CONST_ALARM_CONTROL_PANEL_NAME = 'HmIP Alarm Control Panel' + async def async_setup_platform( hass, config, async_add_entities, discovery_info=None): @@ -28,9 +30,18 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, """Set up the HomematicIP alrm control panel from a config entry.""" home = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]].home devices = [] + security_zones = [] for group in home.groups: if isinstance(group, AsyncSecurityZoneGroup): + security_zones.append(group) + # To be removed in a later release. devices.append(HomematicipSecurityZone(home, group)) + _LOGGER.warning("Homematic IP: alarm_control_panel.%s is " + "deprecated. Please switch to " + "alarm_control_panel.*hmip_alarm_control_panel.", + group.label) + if security_zones: + devices.append(HomematicipAlarmControlPanel(home, security_zones)) if devices: async_add_entities(devices) @@ -73,3 +84,104 @@ class HomematicipSecurityZone(HomematicipGenericDevice, AlarmControlPanel): async def async_alarm_arm_away(self, code=None): """Send arm away command.""" await self._home.set_security_zones_activation(True, True) + + +class HomematicipAlarmControlPanel(AlarmControlPanel): + """Representation of an alarm control panel.""" + + def __init__(self, home: AsyncHome, security_zones) -> None: + """Initialize the alarm control panel.""" + self._home = home + self.alarm_state = STATE_ALARM_DISARMED + + for security_zone in security_zones: + if security_zone.label == 'INTERNAL': + self._internal_alarm_zone = security_zone + else: + self._external_alarm_zone = security_zone + + @property + def state(self) -> str: + """Return the state of the device.""" + 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) + + async def async_alarm_disarm(self, code=None): + """Send disarm command.""" + await self._home.set_security_zones_activation(False, False) + + async def async_alarm_arm_home(self, code=None): + """Send arm home command.""" + await self._home.set_security_zones_activation(False, True) + + async def async_alarm_arm_away(self, code=None): + """Send arm away command.""" + await self._home.set_security_zones_activation(True, True) + + async def async_added_to_hass(self): + """Register callbacks.""" + self._internal_alarm_zone.on_update(self._async_device_changed) + self._external_alarm_zone.on_update(self._async_device_changed) + + def _async_device_changed(self, *args, **kwargs): + """Handle device state changes.""" + _LOGGER.debug("Event %s (%s)", self.name, + CONST_ALARM_CONTROL_PANEL_NAME) + self.async_schedule_update_ha_state() + + @property + def name(self) -> str: + """Return the name of the generic device.""" + name = CONST_ALARM_CONTROL_PANEL_NAME + if self._home.name: + name = "{} {}".format(self._home.name, name) + return name + + @property + def should_poll(self) -> bool: + """No polling needed.""" + return False + + @property + def available(self) -> bool: + """Device available.""" + return not self._internal_alarm_zone.unreach or \ + not self._external_alarm_zone.unreach + + @property + def unique_id(self) -> str: + """Return a unique ID.""" + return "{}_{}".format(self.__class__.__name__, self._home.id) + + +def _get_zone_alarm_state(security_zone) -> bool: + if 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/homeassistant/components/homematicip_cloud/device.py b/homeassistant/components/homematicip_cloud/device.py index 6bbbb8b4fab..2c77d225263 100644 --- a/homeassistant/components/homematicip_cloud/device.py +++ b/homeassistant/components/homematicip_cloud/device.py @@ -51,9 +51,9 @@ class HomematicipGenericDevice(Entity): async def async_added_to_hass(self): """Register callbacks.""" - self._device.on_update(self._device_changed) + self._device.on_update(self._async_device_changed) - def _device_changed(self, *args, **kwargs): + def _async_device_changed(self, *args, **kwargs): """Handle device state changes.""" _LOGGER.debug("Event %s (%s)", self.name, self._device.modelType) self.async_schedule_update_ha_state()