Improve code quality alarm_control_panel in yale_smart_alarm (#63672)

* Code quality yale_smart_alarm

* Raise error on arming

* Raise error if not possible to arm/disarm

* Type checking and settings properties

* Fix direct write state
pull/64024/head
G Johansson 2022-01-11 16:49:46 +01:00 committed by GitHub
parent f4f1ea4068
commit 4b6e196606
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 102 additions and 36 deletions

View File

@ -1,7 +1,15 @@
"""Support for Yale Alarm."""
from __future__ import annotations
from typing import TYPE_CHECKING
import voluptuous as vol
from yalesmartalarmclient.const import (
YALE_STATE_ARM_FULL,
YALE_STATE_ARM_PARTIAL,
YALE_STATE_DISARM,
)
from yalesmartalarmclient.exceptions import AuthenticationError, UnknownError
from homeassistant.components.alarm_control_panel import (
PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA,
@ -14,10 +22,11 @@ from homeassistant.components.alarm_control_panel.const import (
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_NAME, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import (
@ -75,51 +84,108 @@ async def async_setup_entry(
class YaleAlarmDevice(CoordinatorEntity, AlarmControlPanelEntity):
"""Represent a Yale Smart Alarm."""
_attr_code_arm_required = False
_attr_supported_features = SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY
def __init__(self, coordinator: YaleDataUpdateCoordinator) -> None:
"""Initialize the Yale Alarm Device."""
super().__init__(coordinator)
self._attr_name: str = coordinator.entry.data[CONF_NAME]
self._coordinator = coordinator
self._attr_name = coordinator.entry.data[CONF_NAME]
self._attr_unique_id = coordinator.entry.entry_id
self._identifier: str = coordinator.entry.data[CONF_USERNAME]
@property
def device_info(self) -> DeviceInfo:
"""Return device information about this entity."""
return DeviceInfo(
identifiers={(DOMAIN, self._identifier)},
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, coordinator.entry.data[CONF_USERNAME])},
manufacturer=MANUFACTURER,
model=MODEL,
name=str(self.name),
name=self._attr_name,
)
@property
def state(self):
"""Return the state of the device."""
return STATE_MAP.get(self.coordinator.data["alarm"])
@property
def available(self):
"""Return if entity is available."""
return STATE_MAP.get(self.coordinator.data["alarm"]) is not None
@property
def code_arm_required(self):
"""Whether the code is required for arm actions."""
return False
@property
def supported_features(self) -> int:
"""Return the list of supported features."""
return SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY
def alarm_disarm(self, code=None):
async def async_alarm_disarm(self, code=None) -> None:
"""Send disarm command."""
self.coordinator.yale.disarm()
if TYPE_CHECKING:
assert self._coordinator.yale, "Connection to API is missing"
def alarm_arm_home(self, code=None):
try:
alarm_state = await self.hass.async_add_executor_job(
self._coordinator.yale.disarm
)
except (
AuthenticationError,
ConnectionError,
TimeoutError,
UnknownError,
) as error:
raise HomeAssistantError(
f"Could not verify disarmed for {self._attr_name}: {error}"
) from error
LOGGER.debug("Alarm disarmed: %s", alarm_state)
if alarm_state:
self.coordinator.data["alarm"] = YALE_STATE_DISARM
self.async_write_ha_state()
return
raise HomeAssistantError("Could not disarm, check system ready for disarming.")
async def async_alarm_arm_home(self, code=None) -> None:
"""Send arm home command."""
self.coordinator.yale.arm_partial()
if TYPE_CHECKING:
assert self._coordinator.yale, "Connection to API is missing"
def alarm_arm_away(self, code=None):
try:
alarm_state = await self.hass.async_add_executor_job(
self._coordinator.yale.arm_partial
)
except (
AuthenticationError,
ConnectionError,
TimeoutError,
UnknownError,
) as error:
raise HomeAssistantError(
f"Could not verify armed home for {self._attr_name}: {error}"
) from error
LOGGER.debug("Alarm armed home: %s", alarm_state)
if alarm_state:
self.coordinator.data["alarm"] = YALE_STATE_ARM_PARTIAL
self.async_write_ha_state()
return
raise HomeAssistantError("Could not arm home, check system ready for arming.")
async def async_alarm_arm_away(self, code=None) -> None:
"""Send arm away command."""
self.coordinator.yale.arm_full()
if TYPE_CHECKING:
assert self._coordinator.yale, "Connection to API is missing"
try:
alarm_state = await self.hass.async_add_executor_job(
self._coordinator.yale.arm_full
)
except (
AuthenticationError,
ConnectionError,
TimeoutError,
UnknownError,
) as error:
raise HomeAssistantError(
f"Could not verify armed away for {self._attr_name}: {error}"
) from error
LOGGER.debug("Alarm armed away: %s", alarm_state)
if alarm_state:
self.coordinator.data["alarm"] = YALE_STATE_ARM_FULL
self.async_write_ha_state()
return
raise HomeAssistantError("Could not arm away, check system ready for arming.")
@property
def available(self) -> bool:
"""Return True if alarm is available."""
if STATE_MAP.get(self.coordinator.data["alarm"]) is None:
return False
return super().available
@property
def state(self) -> StateType:
"""Return the state of the alarm."""
return STATE_MAP.get(self.coordinator.data["alarm"])