mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Add Yolink lock support (#73069)
* Add yolink lock support * Update .coveragerct * extract the commons
This commit is contained in:
parent
1744e7224b
commit
db53ab5fd0
@ -1495,6 +1495,7 @@ omit =
|
|||||||
homeassistant/components/yolink/const.py
|
homeassistant/components/yolink/const.py
|
||||||
homeassistant/components/yolink/coordinator.py
|
homeassistant/components/yolink/coordinator.py
|
||||||
homeassistant/components/yolink/entity.py
|
homeassistant/components/yolink/entity.py
|
||||||
|
homeassistant/components/yolink/lock.py
|
||||||
homeassistant/components/yolink/sensor.py
|
homeassistant/components/yolink/sensor.py
|
||||||
homeassistant/components/yolink/siren.py
|
homeassistant/components/yolink/siren.py
|
||||||
homeassistant/components/yolink/switch.py
|
homeassistant/components/yolink/switch.py
|
||||||
|
@ -24,7 +24,13 @@ from .coordinator import YoLinkCoordinator
|
|||||||
SCAN_INTERVAL = timedelta(minutes=5)
|
SCAN_INTERVAL = timedelta(minutes=5)
|
||||||
|
|
||||||
|
|
||||||
PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR, Platform.SIREN, Platform.SWITCH]
|
PLATFORMS = [
|
||||||
|
Platform.BINARY_SENSOR,
|
||||||
|
Platform.LOCK,
|
||||||
|
Platform.SENSOR,
|
||||||
|
Platform.SIREN,
|
||||||
|
Platform.SWITCH,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
|
@ -96,7 +96,7 @@ async def async_setup_entry(
|
|||||||
if description.exists_fn(binary_sensor_device_coordinator.device):
|
if description.exists_fn(binary_sensor_device_coordinator.device):
|
||||||
entities.append(
|
entities.append(
|
||||||
YoLinkBinarySensorEntity(
|
YoLinkBinarySensorEntity(
|
||||||
binary_sensor_device_coordinator, description
|
config_entry, binary_sensor_device_coordinator, description
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
@ -109,11 +109,12 @@ class YoLinkBinarySensorEntity(YoLinkEntity, BinarySensorEntity):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
coordinator: YoLinkCoordinator,
|
coordinator: YoLinkCoordinator,
|
||||||
description: YoLinkBinarySensorEntityDescription,
|
description: YoLinkBinarySensorEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Init YoLink Sensor."""
|
"""Init YoLink Sensor."""
|
||||||
super().__init__(coordinator)
|
super().__init__(config_entry, coordinator)
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
self._attr_unique_id = (
|
self._attr_unique_id = (
|
||||||
f"{coordinator.device.device_id} {self.entity_description.key}"
|
f"{coordinator.device.device_id} {self.entity_description.key}"
|
||||||
|
@ -20,3 +20,4 @@ ATTR_DEVICE_LEAK_SENSOR = "LeakSensor"
|
|||||||
ATTR_DEVICE_VIBRATION_SENSOR = "VibrationSensor"
|
ATTR_DEVICE_VIBRATION_SENSOR = "VibrationSensor"
|
||||||
ATTR_DEVICE_OUTLET = "Outlet"
|
ATTR_DEVICE_OUTLET = "Outlet"
|
||||||
ATTR_DEVICE_SIREN = "Siren"
|
ATTR_DEVICE_SIREN = "Siren"
|
||||||
|
ATTR_DEVICE_LOCK = "Lock"
|
||||||
|
@ -3,7 +3,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
from yolink.exception import YoLinkAuthFailError, YoLinkClientError
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
@ -16,10 +20,12 @@ class YoLinkEntity(CoordinatorEntity[YoLinkCoordinator]):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
coordinator: YoLinkCoordinator,
|
coordinator: YoLinkCoordinator,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Init YoLink Entity."""
|
"""Init YoLink Entity."""
|
||||||
super().__init__(coordinator)
|
super().__init__(coordinator)
|
||||||
|
self.config_entry = config_entry
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_id(self) -> str:
|
def device_id(self) -> str:
|
||||||
@ -52,3 +58,15 @@ class YoLinkEntity(CoordinatorEntity[YoLinkCoordinator]):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
def update_entity_state(self, state: dict) -> None:
|
def update_entity_state(self, state: dict) -> None:
|
||||||
"""Parse and update entity state, should be overridden."""
|
"""Parse and update entity state, should be overridden."""
|
||||||
|
|
||||||
|
async def call_device_api(self, command: str, params: dict) -> None:
|
||||||
|
"""Call device Api."""
|
||||||
|
try:
|
||||||
|
# call_device_http_api will check result, fail by raise YoLinkClientError
|
||||||
|
await self.coordinator.device.call_device_http_api(command, params)
|
||||||
|
except YoLinkAuthFailError as yl_auth_err:
|
||||||
|
self.config_entry.async_start_reauth(self.hass)
|
||||||
|
raise HomeAssistantError(yl_auth_err) from yl_auth_err
|
||||||
|
except YoLinkClientError as yl_client_err:
|
||||||
|
self.coordinator.last_update_success = False
|
||||||
|
raise HomeAssistantError(yl_client_err) from yl_client_err
|
||||||
|
65
homeassistant/components/yolink/lock.py
Normal file
65
homeassistant/components/yolink/lock.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
"""YoLink Lock."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from homeassistant.components.lock import LockEntity
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from .const import ATTR_COORDINATORS, ATTR_DEVICE_LOCK, DOMAIN
|
||||||
|
from .coordinator import YoLinkCoordinator
|
||||||
|
from .entity import YoLinkEntity
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up YoLink lock from a config entry."""
|
||||||
|
device_coordinators = hass.data[DOMAIN][config_entry.entry_id][ATTR_COORDINATORS]
|
||||||
|
entities = [
|
||||||
|
YoLinkLockEntity(config_entry, device_coordinator)
|
||||||
|
for device_coordinator in device_coordinators.values()
|
||||||
|
if device_coordinator.device.device_type == ATTR_DEVICE_LOCK
|
||||||
|
]
|
||||||
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
|
class YoLinkLockEntity(YoLinkEntity, LockEntity):
|
||||||
|
"""YoLink Lock Entity."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
coordinator: YoLinkCoordinator,
|
||||||
|
) -> None:
|
||||||
|
"""Init YoLink Lock."""
|
||||||
|
super().__init__(config_entry, coordinator)
|
||||||
|
self._attr_unique_id = f"{coordinator.device.device_id}_lock_state"
|
||||||
|
self._attr_name = f"{coordinator.device.device_name}(LockState)"
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def update_entity_state(self, state: dict[str, Any]) -> None:
|
||||||
|
"""Update HA Entity State."""
|
||||||
|
state_value = state.get("state")
|
||||||
|
self._attr_is_locked = (
|
||||||
|
state_value == "locked" if state_value is not None else None
|
||||||
|
)
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
async def call_lock_state_change(self, state: str) -> None:
|
||||||
|
"""Call setState api to change lock state."""
|
||||||
|
await self.call_device_api("setState", {"state": state})
|
||||||
|
self._attr_is_locked = state == "lock"
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
async def async_lock(self, **kwargs: Any) -> None:
|
||||||
|
"""Lock device."""
|
||||||
|
await self.call_lock_state_change("lock")
|
||||||
|
|
||||||
|
async def async_unlock(self, **kwargs: Any) -> None:
|
||||||
|
"""Unlock device."""
|
||||||
|
await self.call_lock_state_change("unlock")
|
@ -21,6 +21,7 @@ from homeassistant.util import percentage
|
|||||||
from .const import (
|
from .const import (
|
||||||
ATTR_COORDINATORS,
|
ATTR_COORDINATORS,
|
||||||
ATTR_DEVICE_DOOR_SENSOR,
|
ATTR_DEVICE_DOOR_SENSOR,
|
||||||
|
ATTR_DEVICE_LOCK,
|
||||||
ATTR_DEVICE_MOTION_SENSOR,
|
ATTR_DEVICE_MOTION_SENSOR,
|
||||||
ATTR_DEVICE_TH_SENSOR,
|
ATTR_DEVICE_TH_SENSOR,
|
||||||
ATTR_DEVICE_VIBRATION_SENSOR,
|
ATTR_DEVICE_VIBRATION_SENSOR,
|
||||||
@ -51,6 +52,7 @@ SENSOR_DEVICE_TYPE = [
|
|||||||
ATTR_DEVICE_MOTION_SENSOR,
|
ATTR_DEVICE_MOTION_SENSOR,
|
||||||
ATTR_DEVICE_TH_SENSOR,
|
ATTR_DEVICE_TH_SENSOR,
|
||||||
ATTR_DEVICE_VIBRATION_SENSOR,
|
ATTR_DEVICE_VIBRATION_SENSOR,
|
||||||
|
ATTR_DEVICE_LOCK,
|
||||||
]
|
]
|
||||||
|
|
||||||
BATTERY_POWER_SENSOR = [
|
BATTERY_POWER_SENSOR = [
|
||||||
@ -58,6 +60,7 @@ BATTERY_POWER_SENSOR = [
|
|||||||
ATTR_DEVICE_TH_SENSOR,
|
ATTR_DEVICE_TH_SENSOR,
|
||||||
ATTR_DEVICE_MOTION_SENSOR,
|
ATTR_DEVICE_MOTION_SENSOR,
|
||||||
ATTR_DEVICE_VIBRATION_SENSOR,
|
ATTR_DEVICE_VIBRATION_SENSOR,
|
||||||
|
ATTR_DEVICE_LOCK,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -112,6 +115,7 @@ async def async_setup_entry(
|
|||||||
if description.exists_fn(sensor_device_coordinator.device):
|
if description.exists_fn(sensor_device_coordinator.device):
|
||||||
entities.append(
|
entities.append(
|
||||||
YoLinkSensorEntity(
|
YoLinkSensorEntity(
|
||||||
|
config_entry,
|
||||||
sensor_device_coordinator,
|
sensor_device_coordinator,
|
||||||
description,
|
description,
|
||||||
)
|
)
|
||||||
@ -126,11 +130,12 @@ class YoLinkSensorEntity(YoLinkEntity, SensorEntity):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
coordinator: YoLinkCoordinator,
|
coordinator: YoLinkCoordinator,
|
||||||
description: YoLinkSensorEntityDescription,
|
description: YoLinkSensorEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Init YoLink Sensor."""
|
"""Init YoLink Sensor."""
|
||||||
super().__init__(coordinator)
|
super().__init__(config_entry, coordinator)
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
self._attr_unique_id = (
|
self._attr_unique_id = (
|
||||||
f"{coordinator.device.device_id} {self.entity_description.key}"
|
f"{coordinator.device.device_id} {self.entity_description.key}"
|
||||||
|
@ -6,7 +6,6 @@ from dataclasses import dataclass
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from yolink.device import YoLinkDevice
|
from yolink.device import YoLinkDevice
|
||||||
from yolink.exception import YoLinkAuthFailError, YoLinkClientError
|
|
||||||
|
|
||||||
from homeassistant.components.siren import (
|
from homeassistant.components.siren import (
|
||||||
SirenEntity,
|
SirenEntity,
|
||||||
@ -15,7 +14,6 @@ from homeassistant.components.siren import (
|
|||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .const import ATTR_COORDINATORS, ATTR_DEVICE_SIREN, DOMAIN
|
from .const import ATTR_COORDINATORS, ATTR_DEVICE_SIREN, DOMAIN
|
||||||
@ -79,8 +77,7 @@ class YoLinkSirenEntity(YoLinkEntity, SirenEntity):
|
|||||||
description: YoLinkSirenEntityDescription,
|
description: YoLinkSirenEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Init YoLink Siren."""
|
"""Init YoLink Siren."""
|
||||||
super().__init__(coordinator)
|
super().__init__(config_entry, coordinator)
|
||||||
self.config_entry = config_entry
|
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
self._attr_unique_id = (
|
self._attr_unique_id = (
|
||||||
f"{coordinator.device.device_id} {self.entity_description.key}"
|
f"{coordinator.device.device_id} {self.entity_description.key}"
|
||||||
@ -102,17 +99,7 @@ class YoLinkSirenEntity(YoLinkEntity, SirenEntity):
|
|||||||
|
|
||||||
async def call_state_change(self, state: bool) -> None:
|
async def call_state_change(self, state: bool) -> None:
|
||||||
"""Call setState api to change siren state."""
|
"""Call setState api to change siren state."""
|
||||||
try:
|
await self.call_device_api("setState", {"state": {"alarm": state}})
|
||||||
# call_device_http_api will check result, fail by raise YoLinkClientError
|
|
||||||
await self.coordinator.device.call_device_http_api(
|
|
||||||
"setState", {"state": {"alarm": state}}
|
|
||||||
)
|
|
||||||
except YoLinkAuthFailError as yl_auth_err:
|
|
||||||
self.config_entry.async_start_reauth(self.hass)
|
|
||||||
raise HomeAssistantError(yl_auth_err) from yl_auth_err
|
|
||||||
except YoLinkClientError as yl_client_err:
|
|
||||||
self.coordinator.last_update_success = False
|
|
||||||
raise HomeAssistantError(yl_client_err) from yl_client_err
|
|
||||||
self._attr_is_on = self.entity_description.value("alert" if state else "normal")
|
self._attr_is_on = self.entity_description.value("alert" if state else "normal")
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ from dataclasses import dataclass
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from yolink.device import YoLinkDevice
|
from yolink.device import YoLinkDevice
|
||||||
from yolink.exception import YoLinkAuthFailError, YoLinkClientError
|
|
||||||
|
|
||||||
from homeassistant.components.switch import (
|
from homeassistant.components.switch import (
|
||||||
SwitchDeviceClass,
|
SwitchDeviceClass,
|
||||||
@ -15,7 +14,6 @@ from homeassistant.components.switch import (
|
|||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .const import ATTR_COORDINATORS, ATTR_DEVICE_OUTLET, DOMAIN
|
from .const import ATTR_COORDINATORS, ATTR_DEVICE_OUTLET, DOMAIN
|
||||||
@ -80,8 +78,7 @@ class YoLinkSwitchEntity(YoLinkEntity, SwitchEntity):
|
|||||||
description: YoLinkSwitchEntityDescription,
|
description: YoLinkSwitchEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Init YoLink Outlet."""
|
"""Init YoLink Outlet."""
|
||||||
super().__init__(coordinator)
|
super().__init__(config_entry, coordinator)
|
||||||
self.config_entry = config_entry
|
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
self._attr_unique_id = (
|
self._attr_unique_id = (
|
||||||
f"{coordinator.device.device_id} {self.entity_description.key}"
|
f"{coordinator.device.device_id} {self.entity_description.key}"
|
||||||
@ -100,17 +97,7 @@ class YoLinkSwitchEntity(YoLinkEntity, SwitchEntity):
|
|||||||
|
|
||||||
async def call_state_change(self, state: str) -> None:
|
async def call_state_change(self, state: str) -> None:
|
||||||
"""Call setState api to change outlet state."""
|
"""Call setState api to change outlet state."""
|
||||||
try:
|
await self.call_device_api("setState", {"state": state})
|
||||||
# call_device_http_api will check result, fail by raise YoLinkClientError
|
|
||||||
await self.coordinator.device.call_device_http_api(
|
|
||||||
"setState", {"state": state}
|
|
||||||
)
|
|
||||||
except YoLinkAuthFailError as yl_auth_err:
|
|
||||||
self.config_entry.async_start_reauth(self.hass)
|
|
||||||
raise HomeAssistantError(yl_auth_err) from yl_auth_err
|
|
||||||
except YoLinkClientError as yl_client_err:
|
|
||||||
self.coordinator.last_update_success = False
|
|
||||||
raise HomeAssistantError(yl_client_err) from yl_client_err
|
|
||||||
self._attr_is_on = self.entity_description.value(state)
|
self._attr_is_on = self.entity_description.value(state)
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user