Code cleanup yale_smart_alarm (#67701)

This commit is contained in:
G Johansson 2022-03-06 06:27:06 +01:00 committed by GitHub
parent f5d25eaf8f
commit 1358aed016
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 136 deletions

View File

@ -5,31 +5,25 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed from homeassistant.exceptions import ConfigEntryAuthFailed
from .const import COORDINATOR, DOMAIN, LOGGER, PLATFORMS from .const import COORDINATOR, DOMAIN, PLATFORMS
from .coordinator import YaleDataUpdateCoordinator from .coordinator import YaleDataUpdateCoordinator
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Yale from a config entry.""" """Set up Yale from a config entry."""
hass.data.setdefault(DOMAIN, {})
title = entry.title
coordinator = YaleDataUpdateCoordinator(hass, entry=entry)
coordinator = YaleDataUpdateCoordinator(hass, entry)
if not await hass.async_add_executor_job(coordinator.get_updates): if not await hass.async_add_executor_job(coordinator.get_updates):
raise ConfigEntryAuthFailed raise ConfigEntryAuthFailed
await coordinator.async_config_entry_first_refresh() await coordinator.async_config_entry_first_refresh()
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {
hass.data[DOMAIN][entry.entry_id] = {
COORDINATOR: coordinator, COORDINATOR: coordinator,
} }
hass.config_entries.async_setup_platforms(entry, PLATFORMS) hass.config_entries.async_setup_platforms(entry, PLATFORMS)
entry.async_on_unload(entry.add_update_listener(update_listener)) entry.async_on_unload(entry.add_update_listener(update_listener))
LOGGER.debug("Loaded entry for %s", title)
return True return True
@ -41,12 +35,7 @@ async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry.""" """Unload a config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) if await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
title = entry.title
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id) hass.data[DOMAIN].pop(entry.entry_id)
LOGGER.debug("Unloaded entry for %s", title) return True
return unload_ok
return False return False

View File

@ -9,7 +9,6 @@ from yalesmartalarmclient.const import (
YALE_STATE_ARM_PARTIAL, YALE_STATE_ARM_PARTIAL,
YALE_STATE_DISARM, YALE_STATE_DISARM,
) )
from yalesmartalarmclient.exceptions import AuthenticationError, UnknownError
from homeassistant.components.alarm_control_panel import ( from homeassistant.components.alarm_control_panel import (
PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA, PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA,
@ -39,6 +38,7 @@ from .const import (
MANUFACTURER, MANUFACTURER,
MODEL, MODEL,
STATE_MAP, STATE_MAP,
YALE_ALL_ERRORS,
) )
from .coordinator import YaleDataUpdateCoordinator from .coordinator import YaleDataUpdateCoordinator
@ -103,81 +103,46 @@ class YaleAlarmDevice(CoordinatorEntity, AlarmControlPanelEntity):
async def async_alarm_disarm(self, code=None) -> None: async def async_alarm_disarm(self, code=None) -> None:
"""Send disarm command.""" """Send disarm command."""
if TYPE_CHECKING: return await self.async_set_alarm(YALE_STATE_DISARM, code)
assert self.coordinator.yale, "Connection to API is missing"
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: async def async_alarm_arm_home(self, code=None) -> None:
"""Send arm home command.""" """Send arm home command."""
if TYPE_CHECKING: return await self.async_set_alarm(YALE_STATE_ARM_PARTIAL, code)
assert self.coordinator.yale, "Connection to API is missing"
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: async def async_alarm_arm_away(self, code=None) -> None:
"""Send arm away command.""" """Send arm away command."""
return await self.async_set_alarm(YALE_STATE_ARM_FULL, code)
async def async_set_alarm(self, command: str, code: str | None = None) -> None:
"""Set alarm."""
if TYPE_CHECKING: if TYPE_CHECKING:
assert self.coordinator.yale, "Connection to API is missing" assert self.coordinator.yale, "Connection to API is missing"
try: try:
alarm_state = await self.hass.async_add_executor_job( if command == YALE_STATE_ARM_FULL:
self.coordinator.yale.arm_full alarm_state = await self.hass.async_add_executor_job(
) self.coordinator.yale.arm_full
except ( )
AuthenticationError, if command == YALE_STATE_ARM_PARTIAL:
ConnectionError, alarm_state = await self.hass.async_add_executor_job(
TimeoutError, self.coordinator.yale.arm_partial
UnknownError, )
) as error: if command == YALE_STATE_DISARM:
alarm_state = await self.hass.async_add_executor_job(
self.coordinator.yale.disarm
)
except YALE_ALL_ERRORS as error:
raise HomeAssistantError( raise HomeAssistantError(
f"Could not verify armed away for {self._attr_name}: {error}" f"Could not set alarm for {self._attr_name}: {error}"
) from error ) from error
LOGGER.debug("Alarm armed away: %s", alarm_state)
if alarm_state: if alarm_state:
self.coordinator.data["alarm"] = YALE_STATE_ARM_FULL self.coordinator.data["alarm"] = command
self.async_write_ha_state() self.async_write_ha_state()
return return
raise HomeAssistantError("Could not arm away, check system ready for arming.") raise HomeAssistantError(
"Could not change alarm check system ready for arming."
)
@property @property
def available(self) -> bool: def available(self) -> bool:

View File

@ -5,7 +5,7 @@ from typing import Any
import voluptuous as vol import voluptuous as vol
from yalesmartalarmclient.client import YaleSmartAlarmClient from yalesmartalarmclient.client import YaleSmartAlarmClient
from yalesmartalarmclient.exceptions import AuthenticationError, UnknownError from yalesmartalarmclient.exceptions import AuthenticationError
from homeassistant.config_entries import ConfigEntry, ConfigFlow, OptionsFlow from homeassistant.config_entries import ConfigEntry, ConfigFlow, OptionsFlow
from homeassistant.const import CONF_CODE, CONF_NAME, CONF_PASSWORD, CONF_USERNAME from homeassistant.const import CONF_CODE, CONF_NAME, CONF_PASSWORD, CONF_USERNAME
@ -21,6 +21,7 @@ from .const import (
DEFAULT_NAME, DEFAULT_NAME,
DOMAIN, DOMAIN,
LOGGER, LOGGER,
YALE_BASE_ERRORS,
) )
DATA_SCHEMA = vol.Schema( DATA_SCHEMA = vol.Schema(
@ -81,7 +82,7 @@ class YaleConfigFlow(ConfigFlow, domain=DOMAIN):
except AuthenticationError as error: except AuthenticationError as error:
LOGGER.error("Authentication failed. Check credentials %s", error) LOGGER.error("Authentication failed. Check credentials %s", error)
errors = {"base": "invalid_auth"} errors = {"base": "invalid_auth"}
except (ConnectionError, TimeoutError, UnknownError) as error: except YALE_BASE_ERRORS as error:
LOGGER.error("Connection to API failed %s", error) LOGGER.error("Connection to API failed %s", error)
errors = {"base": "cannot_connect"} errors = {"base": "cannot_connect"}
@ -124,7 +125,7 @@ class YaleConfigFlow(ConfigFlow, domain=DOMAIN):
except AuthenticationError as error: except AuthenticationError as error:
LOGGER.error("Authentication failed. Check credentials %s", error) LOGGER.error("Authentication failed. Check credentials %s", error)
errors = {"base": "invalid_auth"} errors = {"base": "invalid_auth"}
except (ConnectionError, TimeoutError, UnknownError) as error: except YALE_BASE_ERRORS as error:
LOGGER.error("Connection to API failed %s", error) LOGGER.error("Connection to API failed %s", error)
errors = {"base": "cannot_connect"} errors = {"base": "cannot_connect"}

View File

@ -6,6 +6,7 @@ from yalesmartalarmclient.client import (
YALE_STATE_ARM_PARTIAL, YALE_STATE_ARM_PARTIAL,
YALE_STATE_DISARM, YALE_STATE_DISARM,
) )
from yalesmartalarmclient.exceptions import AuthenticationError, UnknownError
from homeassistant.const import ( from homeassistant.const import (
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_AWAY,
@ -40,3 +41,10 @@ STATE_MAP = {
YALE_STATE_ARM_PARTIAL: STATE_ALARM_ARMED_HOME, YALE_STATE_ARM_PARTIAL: STATE_ALARM_ARMED_HOME,
YALE_STATE_ARM_FULL: STATE_ALARM_ARMED_AWAY, YALE_STATE_ARM_FULL: STATE_ALARM_ARMED_AWAY,
} }
YALE_BASE_ERRORS = (
ConnectionError,
TimeoutError,
UnknownError,
)
YALE_ALL_ERRORS = (*YALE_BASE_ERRORS, AuthenticationError)

View File

@ -2,9 +2,10 @@
from __future__ import annotations from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from typing import Any
from yalesmartalarmclient.client import YaleSmartAlarmClient from yalesmartalarmclient.client import YaleSmartAlarmClient
from yalesmartalarmclient.exceptions import AuthenticationError, UnknownError from yalesmartalarmclient.exceptions import AuthenticationError
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
@ -12,7 +13,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DEFAULT_SCAN_INTERVAL, DOMAIN, LOGGER from .const import DEFAULT_SCAN_INTERVAL, DOMAIN, LOGGER, YALE_BASE_ERRORS
class YaleDataUpdateCoordinator(DataUpdateCoordinator): class YaleDataUpdateCoordinator(DataUpdateCoordinator):
@ -29,7 +30,7 @@ class YaleDataUpdateCoordinator(DataUpdateCoordinator):
update_interval=timedelta(seconds=DEFAULT_SCAN_INTERVAL), update_interval=timedelta(seconds=DEFAULT_SCAN_INTERVAL),
) )
async def _async_update_data(self) -> dict: async def _async_update_data(self) -> dict[str, Any]:
"""Fetch data from Yale.""" """Fetch data from Yale."""
updates = await self.hass.async_add_executor_job(self.get_updates) updates = await self.hass.async_add_executor_job(self.get_updates)
@ -120,7 +121,7 @@ class YaleDataUpdateCoordinator(DataUpdateCoordinator):
"lock_map": _lock_map, "lock_map": _lock_map,
} }
def get_updates(self) -> dict: def get_updates(self) -> dict[str, Any]:
"""Fetch data from Yale.""" """Fetch data from Yale."""
if self.yale is None: if self.yale is None:
@ -130,7 +131,7 @@ class YaleDataUpdateCoordinator(DataUpdateCoordinator):
) )
except AuthenticationError as error: except AuthenticationError as error:
raise ConfigEntryAuthFailed from error raise ConfigEntryAuthFailed from error
except (ConnectionError, TimeoutError, UnknownError) as error: except YALE_BASE_ERRORS as error:
raise UpdateFailed from error raise UpdateFailed from error
try: try:
@ -141,7 +142,7 @@ class YaleDataUpdateCoordinator(DataUpdateCoordinator):
except AuthenticationError as error: except AuthenticationError as error:
raise ConfigEntryAuthFailed from error raise ConfigEntryAuthFailed from error
except (ConnectionError, TimeoutError, UnknownError) as error: except YALE_BASE_ERRORS as error:
raise UpdateFailed from error raise UpdateFailed from error
return { return {

View File

@ -3,8 +3,6 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from yalesmartalarmclient.exceptions import AuthenticationError, UnknownError
from homeassistant.components.lock import LockEntity from homeassistant.components.lock import LockEntity
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_CODE, CONF_CODE from homeassistant.const import ATTR_CODE, CONF_CODE
@ -17,7 +15,7 @@ from .const import (
COORDINATOR, COORDINATOR,
DEFAULT_LOCK_CODE_DIGITS, DEFAULT_LOCK_CODE_DIGITS,
DOMAIN, DOMAIN,
LOGGER, YALE_ALL_ERRORS,
) )
from .coordinator import YaleDataUpdateCoordinator from .coordinator import YaleDataUpdateCoordinator
from .entity import YaleEntity from .entity import YaleEntity
@ -51,44 +49,15 @@ class YaleDoorlock(YaleEntity, LockEntity):
async def async_unlock(self, **kwargs) -> None: async def async_unlock(self, **kwargs) -> None:
"""Send unlock command.""" """Send unlock command."""
if TYPE_CHECKING:
assert self.coordinator.yale, "Connection to API is missing"
code = kwargs.get(ATTR_CODE, self.coordinator.entry.options.get(CONF_CODE)) code = kwargs.get(ATTR_CODE, self.coordinator.entry.options.get(CONF_CODE))
return await self.async_set_lock("unlocked", code)
if not code:
raise HomeAssistantError(
f"No code provided, {self._attr_name} not unlocked"
)
try:
get_lock = await self.hass.async_add_executor_job(
self.coordinator.yale.lock_api.get, self._attr_name
)
lock_state = await self.hass.async_add_executor_job(
self.coordinator.yale.lock_api.open_lock,
get_lock,
code,
)
except (
AuthenticationError,
ConnectionError,
TimeoutError,
UnknownError,
) as error:
raise HomeAssistantError(
f"Could not verify unlocking for {self._attr_name}: {error}"
) from error
LOGGER.debug("Door unlock: %s", lock_state)
if lock_state:
self.coordinator.data["lock_map"][self._attr_unique_id] = "unlocked"
self.async_write_ha_state()
return
raise HomeAssistantError("Could not unlock, check system ready for unlocking")
async def async_lock(self, **kwargs) -> None: async def async_lock(self, **kwargs) -> None:
"""Send lock command.""" """Send lock command."""
return await self.async_set_lock("locked", None)
async def async_set_lock(self, command: str, code: str | None) -> None:
"""Set lock."""
if TYPE_CHECKING: if TYPE_CHECKING:
assert self.coordinator.yale, "Connection to API is missing" assert self.coordinator.yale, "Connection to API is missing"
@ -96,26 +65,25 @@ class YaleDoorlock(YaleEntity, LockEntity):
get_lock = await self.hass.async_add_executor_job( get_lock = await self.hass.async_add_executor_job(
self.coordinator.yale.lock_api.get, self._attr_name self.coordinator.yale.lock_api.get, self._attr_name
) )
lock_state = await self.hass.async_add_executor_job( if command == "locked":
self.coordinator.yale.lock_api.close_lock, lock_state = await self.hass.async_add_executor_job(
get_lock, self.coordinator.yale.lock_api.close_lock,
) get_lock,
except ( )
AuthenticationError, if command == "unlocked":
ConnectionError, lock_state = await self.hass.async_add_executor_job(
TimeoutError, self.coordinator.yale.lock_api.open_lock, get_lock, code
UnknownError, )
) as error: except YALE_ALL_ERRORS as error:
raise HomeAssistantError( raise HomeAssistantError(
f"Could not verify unlocking for {self._attr_name}: {error}" f"Could not set lock for {self._attr_name}: {error}"
) from error ) from error
LOGGER.debug("Door unlock: %s", lock_state)
if lock_state: if lock_state:
self.coordinator.data["lock_map"][self._attr_unique_id] = "unlocked" self.coordinator.data["lock_map"][self._attr_unique_id] = command
self.async_write_ha_state() self.async_write_ha_state()
return return
raise HomeAssistantError("Could not unlock, check system ready for unlocking") raise HomeAssistantError("Could set lock, check system ready for lock.")
@property @property
def is_locked(self) -> bool | None: def is_locked(self) -> bool | None: