mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 07:07:28 +00:00
Improve lock handling in Yale Smart Living (#124245)
* Improve handling of locks in yalesmartalarm * requirements * fix coordinator setup * Fix lock iteration * Fix tests * Fix review comments
This commit is contained in:
parent
3e1da876c6
commit
41c1cfcef0
@ -3,8 +3,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from typing import Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
|
from yalesmartalarmclient import YaleLock
|
||||||
from yalesmartalarmclient.client import YaleSmartAlarmClient
|
from yalesmartalarmclient.client import YaleSmartAlarmClient
|
||||||
from yalesmartalarmclient.exceptions import AuthenticationError
|
from yalesmartalarmclient.exceptions import AuthenticationError
|
||||||
|
|
||||||
@ -32,6 +33,7 @@ class YaleDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||||||
update_interval=timedelta(seconds=DEFAULT_SCAN_INTERVAL),
|
update_interval=timedelta(seconds=DEFAULT_SCAN_INTERVAL),
|
||||||
always_update=False,
|
always_update=False,
|
||||||
)
|
)
|
||||||
|
self.locks: list[YaleLock] = []
|
||||||
|
|
||||||
async def _async_setup(self) -> None:
|
async def _async_setup(self) -> None:
|
||||||
"""Set up connection to Yale."""
|
"""Set up connection to Yale."""
|
||||||
@ -41,6 +43,7 @@ class YaleDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||||||
self.entry.data[CONF_USERNAME],
|
self.entry.data[CONF_USERNAME],
|
||||||
self.entry.data[CONF_PASSWORD],
|
self.entry.data[CONF_PASSWORD],
|
||||||
)
|
)
|
||||||
|
self.locks = await self.hass.async_add_executor_job(self.yale.get_locks)
|
||||||
except AuthenticationError as error:
|
except AuthenticationError as error:
|
||||||
raise ConfigEntryAuthFailed from error
|
raise ConfigEntryAuthFailed from error
|
||||||
except YALE_BASE_ERRORS as error:
|
except YALE_BASE_ERRORS as error:
|
||||||
@ -51,65 +54,11 @@ class YaleDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||||||
|
|
||||||
updates = await self.hass.async_add_executor_job(self.get_updates)
|
updates = await self.hass.async_add_executor_job(self.get_updates)
|
||||||
|
|
||||||
locks = []
|
|
||||||
door_windows = []
|
door_windows = []
|
||||||
temp_sensors = []
|
temp_sensors = []
|
||||||
|
|
||||||
for device in updates["cycle"]["device_status"]:
|
for device in updates["cycle"]["device_status"]:
|
||||||
state = device["status1"]
|
state = device["status1"]
|
||||||
if device["type"] == "device_type.door_lock":
|
|
||||||
lock_status_str = device["minigw_lock_status"]
|
|
||||||
lock_status = int(str(lock_status_str or 0), 16)
|
|
||||||
closed = (lock_status & 16) == 16
|
|
||||||
locked = (lock_status & 1) == 1
|
|
||||||
if not lock_status and "device_status.lock" in state:
|
|
||||||
device["_state"] = "locked"
|
|
||||||
device["_state2"] = "unknown"
|
|
||||||
locks.append(device)
|
|
||||||
continue
|
|
||||||
if not lock_status and "device_status.unlock" in state:
|
|
||||||
device["_state"] = "unlocked"
|
|
||||||
device["_state2"] = "unknown"
|
|
||||||
locks.append(device)
|
|
||||||
continue
|
|
||||||
if (
|
|
||||||
lock_status
|
|
||||||
and (
|
|
||||||
"device_status.lock" in state or "device_status.unlock" in state
|
|
||||||
)
|
|
||||||
and closed
|
|
||||||
and locked
|
|
||||||
):
|
|
||||||
device["_state"] = "locked"
|
|
||||||
device["_state2"] = "closed"
|
|
||||||
locks.append(device)
|
|
||||||
continue
|
|
||||||
if (
|
|
||||||
lock_status
|
|
||||||
and (
|
|
||||||
"device_status.lock" in state or "device_status.unlock" in state
|
|
||||||
)
|
|
||||||
and closed
|
|
||||||
and not locked
|
|
||||||
):
|
|
||||||
device["_state"] = "unlocked"
|
|
||||||
device["_state2"] = "closed"
|
|
||||||
locks.append(device)
|
|
||||||
continue
|
|
||||||
if (
|
|
||||||
lock_status
|
|
||||||
and (
|
|
||||||
"device_status.lock" in state or "device_status.unlock" in state
|
|
||||||
)
|
|
||||||
and not closed
|
|
||||||
):
|
|
||||||
device["_state"] = "unlocked"
|
|
||||||
device["_state2"] = "open"
|
|
||||||
locks.append(device)
|
|
||||||
continue
|
|
||||||
device["_state"] = "unavailable"
|
|
||||||
locks.append(device)
|
|
||||||
continue
|
|
||||||
if device["type"] == "device_type.door_contact":
|
if device["type"] == "device_type.door_contact":
|
||||||
if "device_status.dc_close" in state:
|
if "device_status.dc_close" in state:
|
||||||
device["_state"] = "closed"
|
device["_state"] = "closed"
|
||||||
@ -128,19 +77,16 @@ class YaleDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||||||
_sensor_map = {
|
_sensor_map = {
|
||||||
contact["address"]: contact["_state"] for contact in door_windows
|
contact["address"]: contact["_state"] for contact in door_windows
|
||||||
}
|
}
|
||||||
_lock_map = {lock["address"]: lock["_state"] for lock in locks}
|
|
||||||
_temp_map = {temp["address"]: temp["status_temp"] for temp in temp_sensors}
|
_temp_map = {temp["address"]: temp["status_temp"] for temp in temp_sensors}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"alarm": updates["arm_status"],
|
"alarm": updates["arm_status"],
|
||||||
"locks": locks,
|
|
||||||
"door_windows": door_windows,
|
"door_windows": door_windows,
|
||||||
"temp_sensors": temp_sensors,
|
"temp_sensors": temp_sensors,
|
||||||
"status": updates["status"],
|
"status": updates["status"],
|
||||||
"online": updates["online"],
|
"online": updates["online"],
|
||||||
"sensor_map": _sensor_map,
|
"sensor_map": _sensor_map,
|
||||||
"temp_map": _temp_map,
|
"temp_map": _temp_map,
|
||||||
"lock_map": _lock_map,
|
|
||||||
"panel_info": updates["panel_info"],
|
"panel_info": updates["panel_info"],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,6 +95,13 @@ class YaleDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||||||
try:
|
try:
|
||||||
arm_status = self.yale.get_armed_status()
|
arm_status = self.yale.get_armed_status()
|
||||||
data = self.yale.get_information()
|
data = self.yale.get_information()
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
assert data.cycle
|
||||||
|
for device in data.cycle["data"]["device_status"]:
|
||||||
|
if device["type"] == YaleLock.DEVICE_TYPE:
|
||||||
|
for lock in self.locks:
|
||||||
|
if lock.name == device["name"]:
|
||||||
|
lock.update(device)
|
||||||
except AuthenticationError as error:
|
except AuthenticationError as error:
|
||||||
raise ConfigEntryAuthFailed from error
|
raise ConfigEntryAuthFailed from error
|
||||||
except YALE_BASE_ERRORS as error:
|
except YALE_BASE_ERRORS as error:
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
"""Base class for yale_smart_alarm entity."""
|
"""Base class for yale_smart_alarm entity."""
|
||||||
|
|
||||||
|
from yalesmartalarmclient import YaleLock
|
||||||
|
|
||||||
from homeassistant.const import CONF_NAME, CONF_USERNAME
|
from homeassistant.const import CONF_NAME, CONF_USERNAME
|
||||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
|
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
@ -9,7 +11,7 @@ from .const import DOMAIN, MANUFACTURER, MODEL
|
|||||||
from .coordinator import YaleDataUpdateCoordinator
|
from .coordinator import YaleDataUpdateCoordinator
|
||||||
|
|
||||||
|
|
||||||
class YaleEntity(CoordinatorEntity[YaleDataUpdateCoordinator], Entity):
|
class YaleEntity(CoordinatorEntity[YaleDataUpdateCoordinator]):
|
||||||
"""Base implementation for Yale device."""
|
"""Base implementation for Yale device."""
|
||||||
|
|
||||||
_attr_has_entity_name = True
|
_attr_has_entity_name = True
|
||||||
@ -23,7 +25,25 @@ class YaleEntity(CoordinatorEntity[YaleDataUpdateCoordinator], Entity):
|
|||||||
manufacturer=MANUFACTURER,
|
manufacturer=MANUFACTURER,
|
||||||
model=MODEL,
|
model=MODEL,
|
||||||
identifiers={(DOMAIN, data["address"])},
|
identifiers={(DOMAIN, data["address"])},
|
||||||
via_device=(DOMAIN, self.coordinator.entry.data[CONF_USERNAME]),
|
via_device=(DOMAIN, coordinator.entry.data[CONF_USERNAME]),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class YaleLockEntity(CoordinatorEntity[YaleDataUpdateCoordinator]):
|
||||||
|
"""Base implementation for Yale lock device."""
|
||||||
|
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
|
def __init__(self, coordinator: YaleDataUpdateCoordinator, lock: YaleLock) -> None:
|
||||||
|
"""Initialize an Yale device."""
|
||||||
|
super().__init__(coordinator)
|
||||||
|
self._attr_unique_id: str = lock.sid()
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
name=lock.name,
|
||||||
|
manufacturer=MANUFACTURER,
|
||||||
|
model=MODEL,
|
||||||
|
identifiers={(DOMAIN, lock.sid())},
|
||||||
|
via_device=(DOMAIN, coordinator.entry.data[CONF_USERNAME]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,9 +2,16 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.components.lock import LockEntity
|
from yalesmartalarmclient import YaleLock, YaleLockState
|
||||||
|
|
||||||
|
from homeassistant.components.lock import (
|
||||||
|
STATE_LOCKED,
|
||||||
|
STATE_OPEN,
|
||||||
|
STATE_UNLOCKED,
|
||||||
|
LockEntity,
|
||||||
|
)
|
||||||
from homeassistant.const import ATTR_CODE
|
from homeassistant.const import ATTR_CODE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
@ -18,7 +25,13 @@ from .const import (
|
|||||||
YALE_ALL_ERRORS,
|
YALE_ALL_ERRORS,
|
||||||
)
|
)
|
||||||
from .coordinator import YaleDataUpdateCoordinator
|
from .coordinator import YaleDataUpdateCoordinator
|
||||||
from .entity import YaleEntity
|
from .entity import YaleLockEntity
|
||||||
|
|
||||||
|
LOCK_STATE_MAP = {
|
||||||
|
YaleLockState.LOCKED: STATE_LOCKED,
|
||||||
|
YaleLockState.UNLOCKED: STATE_UNLOCKED,
|
||||||
|
YaleLockState.DOOR_OPEN: STATE_OPEN,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
@ -30,68 +43,62 @@ async def async_setup_entry(
|
|||||||
code_format = entry.options.get(CONF_LOCK_CODE_DIGITS, DEFAULT_LOCK_CODE_DIGITS)
|
code_format = entry.options.get(CONF_LOCK_CODE_DIGITS, DEFAULT_LOCK_CODE_DIGITS)
|
||||||
|
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
YaleDoorlock(coordinator, data, code_format)
|
YaleDoorlock(coordinator, lock, code_format) for lock in coordinator.locks
|
||||||
for data in coordinator.data["locks"]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class YaleDoorlock(YaleEntity, LockEntity):
|
class YaleDoorlock(YaleLockEntity, LockEntity):
|
||||||
"""Representation of a Yale doorlock."""
|
"""Representation of a Yale doorlock."""
|
||||||
|
|
||||||
_attr_name = None
|
_attr_name = None
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, coordinator: YaleDataUpdateCoordinator, data: dict, code_format: int
|
self, coordinator: YaleDataUpdateCoordinator, lock: YaleLock, code_format: int
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the Yale Lock Device."""
|
"""Initialize the Yale Lock Device."""
|
||||||
super().__init__(coordinator, data)
|
super().__init__(coordinator, lock)
|
||||||
self._attr_code_format = rf"^\d{{{code_format}}}$"
|
self._attr_code_format = rf"^\d{{{code_format}}}$"
|
||||||
self.lock_name: str = data["name"]
|
self.lock_data = lock
|
||||||
|
|
||||||
async def async_unlock(self, **kwargs: Any) -> None:
|
async def async_unlock(self, **kwargs: Any) -> None:
|
||||||
"""Send unlock command."""
|
"""Send unlock command."""
|
||||||
code: str | None = kwargs.get(ATTR_CODE)
|
code: str | None = kwargs.get(ATTR_CODE)
|
||||||
return await self.async_set_lock("unlocked", code)
|
return await self.async_set_lock(YaleLockState.UNLOCKED, code)
|
||||||
|
|
||||||
async def async_lock(self, **kwargs: Any) -> None:
|
async def async_lock(self, **kwargs: Any) -> None:
|
||||||
"""Send lock command."""
|
"""Send lock command."""
|
||||||
return await self.async_set_lock("locked", None)
|
return await self.async_set_lock(YaleLockState.LOCKED, None)
|
||||||
|
|
||||||
async def async_set_lock(self, command: str, code: str | None) -> None:
|
async def async_set_lock(self, state: YaleLockState, code: str | None) -> None:
|
||||||
"""Set lock."""
|
"""Set lock."""
|
||||||
if TYPE_CHECKING:
|
if state is YaleLockState.UNLOCKED and not code:
|
||||||
assert self.coordinator.yale, "Connection to API is missing"
|
|
||||||
if command == "unlocked" and not code:
|
|
||||||
raise ServiceValidationError(
|
raise ServiceValidationError(
|
||||||
translation_domain=DOMAIN,
|
translation_domain=DOMAIN,
|
||||||
translation_key="no_code",
|
translation_key="no_code",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
lock_state = False
|
||||||
try:
|
try:
|
||||||
get_lock = await self.hass.async_add_executor_job(
|
if state is YaleLockState.LOCKED:
|
||||||
self.coordinator.yale.lock_api.get, self.lock_name
|
|
||||||
)
|
|
||||||
if get_lock and command == "locked":
|
|
||||||
lock_state = await self.hass.async_add_executor_job(
|
lock_state = await self.hass.async_add_executor_job(
|
||||||
self.coordinator.yale.lock_api.close_lock,
|
self.lock_data.close
|
||||||
get_lock,
|
|
||||||
)
|
)
|
||||||
if code and get_lock and command == "unlocked":
|
if code and state is YaleLockState.UNLOCKED:
|
||||||
lock_state = await self.hass.async_add_executor_job(
|
lock_state = await self.hass.async_add_executor_job(
|
||||||
self.coordinator.yale.lock_api.open_lock, get_lock, code
|
self.lock_data.open, code
|
||||||
)
|
)
|
||||||
except YALE_ALL_ERRORS as error:
|
except YALE_ALL_ERRORS as error:
|
||||||
raise HomeAssistantError(
|
raise HomeAssistantError(
|
||||||
translation_domain=DOMAIN,
|
translation_domain=DOMAIN,
|
||||||
translation_key="set_lock",
|
translation_key="set_lock",
|
||||||
translation_placeholders={
|
translation_placeholders={
|
||||||
"name": self.lock_name,
|
"name": self.lock_data.name,
|
||||||
"error": str(error),
|
"error": str(error),
|
||||||
},
|
},
|
||||||
) from error
|
) from error
|
||||||
|
|
||||||
if lock_state:
|
if lock_state:
|
||||||
self.coordinator.data["lock_map"][self._attr_unique_id] = command
|
self.lock_data.set_state(state)
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
return
|
return
|
||||||
raise HomeAssistantError(
|
raise HomeAssistantError(
|
||||||
@ -102,4 +109,9 @@ class YaleDoorlock(YaleEntity, LockEntity):
|
|||||||
@property
|
@property
|
||||||
def is_locked(self) -> bool | None:
|
def is_locked(self) -> bool | None:
|
||||||
"""Return true if the lock is locked."""
|
"""Return true if the lock is locked."""
|
||||||
return bool(self.coordinator.data["lock_map"][self._attr_unique_id] == "locked")
|
return LOCK_STATE_MAP.get(self.lock_data.state()) == STATE_LOCKED
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_open(self) -> bool | None:
|
||||||
|
"""Return true if the lock is open."""
|
||||||
|
return LOCK_STATE_MAP.get(self.lock_data.state()) == STATE_OPEN
|
||||||
|
@ -6,5 +6,5 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/yale_smart_alarm",
|
"documentation": "https://www.home-assistant.io/integrations/yale_smart_alarm",
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["yalesmartalarmclient"],
|
"loggers": ["yalesmartalarmclient"],
|
||||||
"requirements": ["yalesmartalarmclient==0.4.0"]
|
"requirements": ["yalesmartalarmclient==0.4.2"]
|
||||||
}
|
}
|
||||||
|
@ -3002,7 +3002,7 @@ xmltodict==0.13.0
|
|||||||
xs1-api-client==3.0.0
|
xs1-api-client==3.0.0
|
||||||
|
|
||||||
# homeassistant.components.yale_smart_alarm
|
# homeassistant.components.yale_smart_alarm
|
||||||
yalesmartalarmclient==0.4.0
|
yalesmartalarmclient==0.4.2
|
||||||
|
|
||||||
# homeassistant.components.august
|
# homeassistant.components.august
|
||||||
# homeassistant.components.yale
|
# homeassistant.components.yale
|
||||||
|
@ -2388,7 +2388,7 @@ xknxproject==3.7.1
|
|||||||
xmltodict==0.13.0
|
xmltodict==0.13.0
|
||||||
|
|
||||||
# homeassistant.components.yale_smart_alarm
|
# homeassistant.components.yale_smart_alarm
|
||||||
yalesmartalarmclient==0.4.0
|
yalesmartalarmclient==0.4.2
|
||||||
|
|
||||||
# homeassistant.components.august
|
# homeassistant.components.august
|
||||||
# homeassistant.components.yale
|
# homeassistant.components.yale
|
||||||
|
@ -7,7 +7,7 @@ from typing import Any
|
|||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from yalesmartalarmclient import YaleSmartAlarmData
|
from yalesmartalarmclient import YaleDoorManAPI, YaleLock, YaleSmartAlarmData
|
||||||
from yalesmartalarmclient.const import YALE_STATE_ARM_FULL
|
from yalesmartalarmclient.const import YALE_STATE_ARM_FULL
|
||||||
|
|
||||||
from homeassistant.components.yale_smart_alarm.const import DOMAIN, PLATFORMS
|
from homeassistant.components.yale_smart_alarm.const import DOMAIN, PLATFORMS
|
||||||
@ -53,16 +53,28 @@ async def load_config_entry(
|
|||||||
|
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
cycle = get_data.cycle["data"]
|
||||||
|
data = {"data": cycle["device_status"]}
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.yale_smart_alarm.coordinator.YaleSmartAlarmClient",
|
"homeassistant.components.yale_smart_alarm.coordinator.YaleSmartAlarmClient",
|
||||||
autospec=True,
|
autospec=True,
|
||||||
) as mock_client_class:
|
) as mock_client_class:
|
||||||
client = mock_client_class.return_value
|
client = mock_client_class.return_value
|
||||||
client.auth = Mock()
|
client.auth = Mock()
|
||||||
client.lock_api = Mock()
|
client.auth.get_authenticated = Mock(return_value=data)
|
||||||
|
client.auth.post_authenticated = Mock(return_value={"code": "000"})
|
||||||
|
client.lock_api = YaleDoorManAPI(client.auth)
|
||||||
|
locks = [
|
||||||
|
YaleLock(device, lock_api=client.lock_api)
|
||||||
|
for device in cycle["device_status"]
|
||||||
|
if device["type"] == YaleLock.DEVICE_TYPE
|
||||||
|
]
|
||||||
|
client.get_locks.return_value = locks
|
||||||
client.get_all.return_value = get_all_data
|
client.get_all.return_value = get_all_data
|
||||||
client.get_information.return_value = get_data
|
client.get_information.return_value = get_data
|
||||||
client.get_armed_status.return_value = YALE_STATE_ARM_FULL
|
client.get_armed_status.return_value = YALE_STATE_ARM_FULL
|
||||||
|
|
||||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -78,7 +90,7 @@ def get_fixture_data() -> dict[str, Any]:
|
|||||||
return json_data
|
return json_data
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="get_data", scope="package")
|
@pytest.fixture(name="get_data")
|
||||||
def get_update_data(loaded_fixture: dict[str, Any]) -> YaleSmartAlarmData:
|
def get_update_data(loaded_fixture: dict[str, Any]) -> YaleSmartAlarmData:
|
||||||
"""Load update data and return."""
|
"""Load update data and return."""
|
||||||
|
|
||||||
@ -94,7 +106,7 @@ def get_update_data(loaded_fixture: dict[str, Any]) -> YaleSmartAlarmData:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="get_all_data", scope="package")
|
@pytest.fixture(name="get_all_data")
|
||||||
def get_diag_data(loaded_fixture: dict[str, Any]) -> YaleSmartAlarmData:
|
def get_diag_data(loaded_fixture: dict[str, Any]) -> YaleSmartAlarmData:
|
||||||
"""Load all data and return."""
|
"""Load all data and return."""
|
||||||
|
|
||||||
|
@ -24,8 +24,6 @@
|
|||||||
'capture_latest': None,
|
'capture_latest': None,
|
||||||
'device_status': list([
|
'device_status': list([
|
||||||
dict({
|
dict({
|
||||||
'_state': 'locked',
|
|
||||||
'_state2': 'closed',
|
|
||||||
'address': '**REDACTED**',
|
'address': '**REDACTED**',
|
||||||
'area': '1',
|
'area': '1',
|
||||||
'bypass': '0',
|
'bypass': '0',
|
||||||
@ -86,8 +84,6 @@
|
|||||||
'type_no': '72',
|
'type_no': '72',
|
||||||
}),
|
}),
|
||||||
dict({
|
dict({
|
||||||
'_state': 'unlocked',
|
|
||||||
'_state2': 'unknown',
|
|
||||||
'address': '**REDACTED**',
|
'address': '**REDACTED**',
|
||||||
'area': '1',
|
'area': '1',
|
||||||
'bypass': '0',
|
'bypass': '0',
|
||||||
@ -147,8 +143,6 @@
|
|||||||
'type_no': '72',
|
'type_no': '72',
|
||||||
}),
|
}),
|
||||||
dict({
|
dict({
|
||||||
'_state': 'locked',
|
|
||||||
'_state2': 'unknown',
|
|
||||||
'address': '**REDACTED**',
|
'address': '**REDACTED**',
|
||||||
'area': '1',
|
'area': '1',
|
||||||
'bypass': '0',
|
'bypass': '0',
|
||||||
@ -391,8 +385,6 @@
|
|||||||
'type_no': '4',
|
'type_no': '4',
|
||||||
}),
|
}),
|
||||||
dict({
|
dict({
|
||||||
'_state': 'unlocked',
|
|
||||||
'_state2': 'closed',
|
|
||||||
'address': '**REDACTED**',
|
'address': '**REDACTED**',
|
||||||
'area': '1',
|
'area': '1',
|
||||||
'bypass': '0',
|
'bypass': '0',
|
||||||
@ -453,8 +445,6 @@
|
|||||||
'type_no': '72',
|
'type_no': '72',
|
||||||
}),
|
}),
|
||||||
dict({
|
dict({
|
||||||
'_state': 'unlocked',
|
|
||||||
'_state2': 'open',
|
|
||||||
'address': '**REDACTED**',
|
'address': '**REDACTED**',
|
||||||
'area': '1',
|
'area': '1',
|
||||||
'bypass': '0',
|
'bypass': '0',
|
||||||
@ -515,7 +505,6 @@
|
|||||||
'type_no': '72',
|
'type_no': '72',
|
||||||
}),
|
}),
|
||||||
dict({
|
dict({
|
||||||
'_state': 'unavailable',
|
|
||||||
'address': '**REDACTED**',
|
'address': '**REDACTED**',
|
||||||
'area': '1',
|
'area': '1',
|
||||||
'bypass': '0',
|
'bypass': '0',
|
||||||
|
@ -236,7 +236,7 @@
|
|||||||
'last_changed': <ANY>,
|
'last_changed': <ANY>,
|
||||||
'last_reported': <ANY>,
|
'last_reported': <ANY>,
|
||||||
'last_updated': <ANY>,
|
'last_updated': <ANY>,
|
||||||
'state': 'unlocked',
|
'state': 'open',
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_lock[load_platforms0][lock.device9-entry]
|
# name: test_lock[load_platforms0][lock.device9-entry]
|
||||||
|
@ -47,8 +47,6 @@ async def test_lock_service_calls(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
get_data: YaleSmartAlarmData,
|
get_data: YaleSmartAlarmData,
|
||||||
load_config_entry: tuple[MockConfigEntry, Mock],
|
load_config_entry: tuple[MockConfigEntry, Mock],
|
||||||
entity_registry: er.EntityRegistry,
|
|
||||||
snapshot: SnapshotAssertion,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the Yale Smart Alarm lock."""
|
"""Test the Yale Smart Alarm lock."""
|
||||||
|
|
||||||
@ -101,8 +99,6 @@ async def test_lock_service_call_fails(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
get_data: YaleSmartAlarmData,
|
get_data: YaleSmartAlarmData,
|
||||||
load_config_entry: tuple[MockConfigEntry, Mock],
|
load_config_entry: tuple[MockConfigEntry, Mock],
|
||||||
entity_registry: er.EntityRegistry,
|
|
||||||
snapshot: SnapshotAssertion,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the Yale Smart Alarm lock service call fails."""
|
"""Test the Yale Smart Alarm lock service call fails."""
|
||||||
|
|
||||||
@ -153,8 +149,6 @@ async def test_lock_service_call_fails_with_incorrect_status(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
get_data: YaleSmartAlarmData,
|
get_data: YaleSmartAlarmData,
|
||||||
load_config_entry: tuple[MockConfigEntry, Mock],
|
load_config_entry: tuple[MockConfigEntry, Mock],
|
||||||
entity_registry: er.EntityRegistry,
|
|
||||||
snapshot: SnapshotAssertion,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the Yale Smart Alarm lock service call fails with incorrect return state."""
|
"""Test the Yale Smart Alarm lock service call fails with incorrect return state."""
|
||||||
|
|
||||||
@ -163,9 +157,7 @@ async def test_lock_service_call_fails_with_incorrect_status(
|
|||||||
data = deepcopy(get_data.cycle)
|
data = deepcopy(get_data.cycle)
|
||||||
data["data"] = data["data"].pop("device_status")
|
data["data"] = data["data"].pop("device_status")
|
||||||
|
|
||||||
client.auth.get_authenticated = Mock(return_value=data)
|
|
||||||
client.auth.post_authenticated = Mock(return_value={"code": "FFF"})
|
client.auth.post_authenticated = Mock(return_value={"code": "FFF"})
|
||||||
client.lock_api = YaleDoorManAPI(client.auth)
|
|
||||||
|
|
||||||
state = hass.states.get("lock.device1")
|
state = hass.states.get("lock.device1")
|
||||||
assert state.state == "locked"
|
assert state.state == "locked"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user