Skip to content

Commit

Permalink
Add option to store bypass and arm code. Add service to bypass zones …
Browse files Browse the repository at this point in the history
…if you choose not to store bypass code.
  • Loading branch information
RenierM26 committed May 1, 2022
1 parent f40d91d commit c7b56eb
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 20 deletions.
13 changes: 11 additions & 2 deletions custom_components/ids_hyyp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand All @@ -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)
Expand Down
26 changes: 19 additions & 7 deletions custom_components/ids_hyyp/alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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

Expand All @@ -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
]
)


Expand All @@ -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:
Expand All @@ -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,
)
Expand All @@ -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,
)
Expand All @@ -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,
Expand Down
18 changes: 16 additions & 2 deletions custom_components/ids_hyyp/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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,
}
)

Expand Down
7 changes: 7 additions & 0 deletions custom_components/ids_hyyp/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
2 changes: 1 addition & 1 deletion custom_components/ids_hyyp/manifest.json
Original file line number Diff line number Diff line change
@@ -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"],
Expand Down
16 changes: 16 additions & 0 deletions custom_components/ids_hyyp/services.yaml
Original file line number Diff line number Diff line change
@@ -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:
4 changes: 3 additions & 1 deletion custom_components/ids_hyyp/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
"step": {
"init": {
"data": {
"timeout": "Request Timeout (seconds)"
"timeout": "Request Timeout (seconds)",
"bypass_code": "Bypass code",
"arm_code": "Arm code"
}
}
}
Expand Down
70 changes: 64 additions & 6 deletions custom_components/ids_hyyp/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -21,26 +29,40 @@ 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."""

_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}"
Expand All @@ -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."""
Expand All @@ -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:
Expand All @@ -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}"
)
4 changes: 3 additions & 1 deletion custom_components/ids_hyyp/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
"step": {
"init": {
"data": {
"timeout": "Request Timeout (seconds)"
"timeout": "Request Timeout (seconds)",
"bypass_code": "Bypass code",
"arm_code": "Arm code"
}
}
}
Expand Down

0 comments on commit c7b56eb

Please sign in to comment.