From c7b56eb42512e3f2b64f95df5719dba1479304ae Mon Sep 17 00:00:00 2001 From: RenierM26 <66512715+RenierM26@users.noreply.github.com> Date: Sun, 1 May 2022 18:26:11 +0200 Subject: [PATCH] Add option to store bypass and arm code. Add service to bypass zones if you choose not to store bypass code. --- custom_components/ids_hyyp/__init__.py | 13 +++- .../ids_hyyp/alarm_control_panel.py | 26 +++++-- custom_components/ids_hyyp/config_flow.py | 18 ++++- custom_components/ids_hyyp/const.py | 7 ++ custom_components/ids_hyyp/manifest.json | 2 +- custom_components/ids_hyyp/services.yaml | 16 +++++ custom_components/ids_hyyp/strings.json | 4 +- custom_components/ids_hyyp/switch.py | 70 +++++++++++++++++-- .../ids_hyyp/translations/en.json | 4 +- 9 files changed, 140 insertions(+), 20 deletions(-) create mode 100644 custom_components/ids_hyyp/services.yaml diff --git a/custom_components/ids_hyyp/__init__.py b/custom_components/ids_hyyp/__init__.py index dceb6f8..dbafc0f 100644 --- a/custom_components/ids_hyyp/__init__.py +++ b/custom_components/ids_hyyp/__init__.py @@ -4,12 +4,19 @@ import logging from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_TIMEOUT, CONF_TOKEN, Platform +from homeassistant.const import ATTR_CODE, CONF_TIMEOUT, CONF_TOKEN, Platform from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from pyhyypapi import HTTPError, HyypApiError, HyypClient, InvalidURL -from .const import CONF_PKG, DATA_COORDINATOR, DEFAULT_TIMEOUT, DOMAIN +from .const import ( + ATTR_ARM_CODE, + ATTR_BYPASS_CODE, + CONF_PKG, + DATA_COORDINATOR, + DEFAULT_TIMEOUT, + DOMAIN, +) from .coordinator import HyypDataUpdateCoordinator _LOGGER = logging.getLogger(__name__) @@ -27,6 +34,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: if not entry.options: options = { CONF_TIMEOUT: DEFAULT_TIMEOUT, + ATTR_ARM_CODE: None, + ATTR_BYPASS_CODE: None, } hass.config_entries.async_update_entry(entry, options=options) diff --git a/custom_components/ids_hyyp/alarm_control_panel.py b/custom_components/ids_hyyp/alarm_control_panel.py index d3467bc..99aec84 100644 --- a/custom_components/ids_hyyp/alarm_control_panel.py +++ b/custom_components/ids_hyyp/alarm_control_panel.py @@ -4,8 +4,8 @@ from typing import Any from homeassistant.components.alarm_control_panel import ( - AlarmControlPanelEntity, FORMAT_NUMBER, + AlarmControlPanelEntity, ) from homeassistant.components.alarm_control_panel.const import ( SUPPORT_ALARM_ARM_AWAY, @@ -23,7 +23,7 @@ from homeassistant.helpers.typing import StateType from pyhyypapi.exceptions import HTTPError, HyypApiError -from .const import DATA_COORDINATOR, DOMAIN +from .const import ATTR_ARM_CODE, DATA_COORDINATOR, DOMAIN from .coordinator import HyypDataUpdateCoordinator from .entity import HyypEntity @@ -35,9 +35,13 @@ async def async_setup_entry( coordinator: HyypDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id][ DATA_COORDINATOR ] + arm_code = entry.options.get(ATTR_ARM_CODE) async_add_entities( - [HyypAlarm(coordinator, partition_id) for partition_id in coordinator.data] + [ + HyypAlarm(coordinator, partition_id, arm_code) + for partition_id in coordinator.data + ] ) @@ -49,12 +53,14 @@ class HyypAlarm(HyypEntity, AlarmControlPanelEntity): _attr_code_format = FORMAT_NUMBER def __init__( - self, coordinator: HyypDataUpdateCoordinator, partition_id: str + self, coordinator: HyypDataUpdateCoordinator, partition_id: str, arm_code: str ) -> None: """Initialize the sensor.""" super().__init__(coordinator, partition_id) self._attr_name = self.data["name"] + self._arm_code = arm_code self._attr_unique_id = f"{self._site_id}_{partition_id}_Alarm" + self._attr_code_arm_required = bool(arm_code) @property def available(self) -> bool: @@ -81,10 +87,12 @@ def state(self) -> StateType: def alarm_disarm(self, code: Any = None) -> None: """Send disarm command.""" + _code = code if not bool(self._arm_code) else self._arm_code + try: response = self.coordinator.hyyp_client.arm_site( arm=False, - pin=code, + pin=_code, partition_id=self._partition_id, site_id=self._site_id, ) @@ -100,10 +108,12 @@ def alarm_disarm(self, code: Any = None) -> None: def alarm_arm_away(self, code: Any = None) -> None: """Send arm away command.""" + _code = code if not bool(self._arm_code) else self._arm_code + try: response = self.coordinator.hyyp_client.arm_site( arm=True, - pin=code, + pin=_code, partition_id=self._partition_id, site_id=self._site_id, ) @@ -119,10 +129,12 @@ def alarm_arm_away(self, code: Any = None) -> None: def alarm_arm_home(self, code: Any = None) -> None: """Send arm home command.""" + _code = code if not bool(self._arm_code) else self._arm_code + try: response = self.coordinator.hyyp_client.arm_site( arm=True, - pin=code, + pin=_code, partition_id=self._partition_id, site_id=self._site_id, stay_profile_id=self._arm_home_profile_id, diff --git a/custom_components/ids_hyyp/config_flow.py b/custom_components/ids_hyyp/config_flow.py index a6fc3ee..9fe9818 100644 --- a/custom_components/ids_hyyp/config_flow.py +++ b/custom_components/ids_hyyp/config_flow.py @@ -7,14 +7,26 @@ import voluptuous as vol from homeassistant.config_entries import ConfigEntry, ConfigFlow, OptionsFlow -from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, CONF_TIMEOUT, CONF_TOKEN +from homeassistant.const import ( + CONF_EMAIL, + CONF_PASSWORD, + CONF_TIMEOUT, + CONF_TOKEN, +) from homeassistant.core import callback from homeassistant.data_entry_flow import FlowResult from pyhyypapi.client import HyypClient from pyhyypapi.constants import DEFAULT_TIMEOUT from pyhyypapi.exceptions import HTTPError, HyypApiError, InvalidURL -from .const import CONF_PKG, DOMAIN, PKG_ADT_SECURE_HOME, PKG_IDS_HYYP +from .const import ( + ATTR_ARM_CODE, + ATTR_BYPASS_CODE, + CONF_PKG, + DOMAIN, + PKG_ADT_SECURE_HOME, + PKG_IDS_HYYP, +) _LOGGER = logging.getLogger(__name__) DEFAULT_OPTIONS = { @@ -124,6 +136,8 @@ async def async_step_init( CONF_TIMEOUT, DEFAULT_TIMEOUT ), ): int, + vol.Optional(ATTR_ARM_CODE): str, + vol.Optional(ATTR_BYPASS_CODE): str, } ) diff --git a/custom_components/ids_hyyp/const.py b/custom_components/ids_hyyp/const.py index 1bf4f7d..ea080c3 100644 --- a/custom_components/ids_hyyp/const.py +++ b/custom_components/ids_hyyp/const.py @@ -16,3 +16,10 @@ # Data DATA_COORDINATOR = "coordinator" + +# Service names +SERVICE_BYPASS_ZONE = "zone_bypass_code" + +# Attributes +ATTR_BYPASS_CODE = "bypass_code" +ATTR_ARM_CODE = "arm_code" diff --git a/custom_components/ids_hyyp/manifest.json b/custom_components/ids_hyyp/manifest.json index 1015ce7..99d1795 100644 --- a/custom_components/ids_hyyp/manifest.json +++ b/custom_components/ids_hyyp/manifest.json @@ -1,7 +1,7 @@ { "domain": "ids_hyyp", "name": "IDS Hyyp(Beta)", - "version": "0.0.0.2", + "version": "0.0.0.3", "documentation": "https://www.home-assistant.io/integrations/idshyyp", "codeowners": ["@RenierM26"], "requirements": ["pyhyypapi==0.0.0.3"], diff --git a/custom_components/ids_hyyp/services.yaml b/custom_components/ids_hyyp/services.yaml new file mode 100644 index 0000000..ad36db6 --- /dev/null +++ b/custom_components/ids_hyyp/services.yaml @@ -0,0 +1,16 @@ +zone_bypass_code: + name: Bypass Zone + description: Bypass zone if code not saved in options. + target: + entity: + integration: ids_hyyp + domain: switch + fields: + bypass_code: + name: Zone bypass code + description: Partition or Site level bypass code. + required: true + example: 1234 + default: 1234 + selector: + text: diff --git a/custom_components/ids_hyyp/strings.json b/custom_components/ids_hyyp/strings.json index 19dbb4b..9eae700 100644 --- a/custom_components/ids_hyyp/strings.json +++ b/custom_components/ids_hyyp/strings.json @@ -25,7 +25,9 @@ "step": { "init": { "data": { - "timeout": "Request Timeout (seconds)" + "timeout": "Request Timeout (seconds)", + "bypass_code": "Bypass code", + "arm_code": "Arm code" } } } diff --git a/custom_components/ids_hyyp/switch.py b/custom_components/ids_hyyp/switch.py index 2dfaa38..f0e1767 100644 --- a/custom_components/ids_hyyp/switch.py +++ b/custom_components/ids_hyyp/switch.py @@ -3,13 +3,21 @@ from typing import Any +import voluptuous as vol + from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_platform from homeassistant.helpers.entity_platform import AddEntitiesCallback from pyhyypapi.exceptions import HTTPError, HyypApiError -from .const import DATA_COORDINATOR, DOMAIN +from .const import ( + ATTR_BYPASS_CODE, + DATA_COORDINATOR, + DOMAIN, + SERVICE_BYPASS_ZONE, +) from .coordinator import HyypDataUpdateCoordinator from .entity import HyypEntity @@ -21,15 +29,24 @@ async def async_setup_entry( coordinator: HyypDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id][ DATA_COORDINATOR ] + bypass_code = entry.options.get(ATTR_BYPASS_CODE) async_add_entities( [ - HyypSwitch(coordinator, partition_id, zone_id) + HyypSwitch(coordinator, partition_id, zone_id, bypass_code) for partition_id in coordinator.data for zone_id in coordinator.data[partition_id]["zones"] ] ) + platform = entity_platform.async_get_current_platform() + + platform.async_register_entity_service( + SERVICE_BYPASS_ZONE, + {vol.Required(ATTR_BYPASS_CODE): str}, + "perform_zone_bypass_code", + ) + class HyypSwitch(HyypEntity, SwitchEntity): """Representation of a IDS Hyyp entity Switch.""" @@ -37,10 +54,15 @@ class HyypSwitch(HyypEntity, SwitchEntity): _attr_device_class = SwitchDeviceClass.SWITCH def __init__( - self, coordinator: HyypDataUpdateCoordinator, partition_id: str, zone_id: str + self, + coordinator: HyypDataUpdateCoordinator, + partition_id: str, + zone_id: str, + bypass_code, ) -> None: """Initialize the switch.""" super().__init__(coordinator, partition_id) + self._bypass_code = bypass_code self._zone_id = zone_id self._attr_name = f"{self.data['zones'][zone_id]['name'].title()}" self._attr_unique_id = f"{self._site_id}_{partition_id}_{zone_id}" @@ -62,16 +84,23 @@ async def async_turn_on(self, **kwargs: Any) -> None: self.coordinator.hyyp_client.set_zone_bypass, self._partition_id, self._zone_id, + 0, + self._bypass_code, ) except (HTTPError, HyypApiError) as err: - raise HyypApiError("Failed to turn on switch {self._attr_name}") from err + raise HyypApiError(f"Failed to turn on switch {self._attr_name}") from err if update_ok["status"] == "SUCCESS": await self.coordinator.async_request_refresh() + elif update_ok["status"] == "PENDING": + raise HyypApiError(f"Code required to bypass zone {self._attr_name}") + else: - raise HyypApiError(f"Failed to bypass zone: {update_ok}") + raise HyypApiError( + f"Failed to bypass zone {self._attr_name} failed with: {update_ok}" + ) async def async_turn_off(self, **kwargs: Any) -> None: """Turn the switch entity off.""" @@ -80,6 +109,8 @@ async def async_turn_off(self, **kwargs: Any) -> None: self.coordinator.hyyp_client.set_zone_bypass, self._partition_id, self._zone_id, + 0, + self._bypass_code, ) except (HTTPError, HyypApiError) as err: @@ -88,5 +119,32 @@ async def async_turn_off(self, **kwargs: Any) -> None: if update_ok["status"] == "SUCCESS": await self.coordinator.async_request_refresh() + elif update_ok["status"] == "PENDING": + raise HyypApiError(f"Code required to bypass zone {self._attr_name}") + + else: + raise HyypApiError( + f"Disable bypass on zone {self._attr_name} failed with: {update_ok}" + ) + + async def perform_zone_bypass_code(self, code: Any = None) -> None: + """Service to bypass zone if code is not set in options.""" + try: + update_ok = await self.hass.async_add_executor_job( + self.coordinator.hyyp_client.set_zone_bypass, + self._partition_id, + self._zone_id, + 0, + code, + ) + + except (HTTPError, HyypApiError) as err: + raise HyypApiError(f"Failed to turn on switch {self._attr_name}") from err + + if update_ok["status"] == "SUCCESS": + await self.coordinator.async_request_refresh() + else: - raise HyypApiError(f"Disable bypass on zone: {update_ok}") + raise HyypApiError( + f"Disable bypass on zone {self._attr_name} failed with: {update_ok}" + ) diff --git a/custom_components/ids_hyyp/translations/en.json b/custom_components/ids_hyyp/translations/en.json index 1656a4e..0db7b4c 100644 --- a/custom_components/ids_hyyp/translations/en.json +++ b/custom_components/ids_hyyp/translations/en.json @@ -25,7 +25,9 @@ "step": { "init": { "data": { - "timeout": "Request Timeout (seconds)" + "timeout": "Request Timeout (seconds)", + "bypass_code": "Bypass code", + "arm_code": "Arm code" } } }