Add yolink finger support (#96944)
This commit is contained in:
parent
945fffebcc
commit
3bbbd8642f
8 changed files with 61 additions and 14 deletions
|
@ -121,8 +121,20 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
raise ConfigEntryNotReady from err
|
raise ConfigEntryNotReady from err
|
||||||
|
|
||||||
device_coordinators = {}
|
device_coordinators = {}
|
||||||
|
|
||||||
|
# revese mapping
|
||||||
|
device_pairing_mapping = {}
|
||||||
for device in yolink_home.get_devices():
|
for device in yolink_home.get_devices():
|
||||||
device_coordinator = YoLinkCoordinator(hass, device)
|
if (parent_id := device.get_paired_device_id()) is not None:
|
||||||
|
device_pairing_mapping[parent_id] = device.device_id
|
||||||
|
|
||||||
|
for device in yolink_home.get_devices():
|
||||||
|
paried_device: YoLinkDevice | None = None
|
||||||
|
if (
|
||||||
|
paried_device_id := device_pairing_mapping.get(device.device_id)
|
||||||
|
) is not None:
|
||||||
|
paried_device = yolink_home.get_device(paried_device_id)
|
||||||
|
device_coordinator = YoLinkCoordinator(hass, device, paried_device)
|
||||||
try:
|
try:
|
||||||
await device_coordinator.async_config_entry_first_refresh()
|
await device_coordinator.async_config_entry_first_refresh()
|
||||||
except ConfigEntryNotReady:
|
except ConfigEntryNotReady:
|
||||||
|
|
|
@ -20,7 +20,12 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
class YoLinkCoordinator(DataUpdateCoordinator[dict]):
|
class YoLinkCoordinator(DataUpdateCoordinator[dict]):
|
||||||
"""YoLink DataUpdateCoordinator."""
|
"""YoLink DataUpdateCoordinator."""
|
||||||
|
|
||||||
def __init__(self, hass: HomeAssistant, device: YoLinkDevice) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
device: YoLinkDevice,
|
||||||
|
paired_device: YoLinkDevice | None = None,
|
||||||
|
) -> None:
|
||||||
"""Init YoLink DataUpdateCoordinator.
|
"""Init YoLink DataUpdateCoordinator.
|
||||||
|
|
||||||
fetch state every 30 minutes base on yolink device heartbeat interval
|
fetch state every 30 minutes base on yolink device heartbeat interval
|
||||||
|
@ -31,16 +36,30 @@ class YoLinkCoordinator(DataUpdateCoordinator[dict]):
|
||||||
hass, _LOGGER, name=DOMAIN, update_interval=timedelta(minutes=30)
|
hass, _LOGGER, name=DOMAIN, update_interval=timedelta(minutes=30)
|
||||||
)
|
)
|
||||||
self.device = device
|
self.device = device
|
||||||
|
self.paired_device = paired_device
|
||||||
|
|
||||||
async def _async_update_data(self) -> dict:
|
async def _async_update_data(self) -> dict:
|
||||||
"""Fetch device state."""
|
"""Fetch device state."""
|
||||||
try:
|
try:
|
||||||
async with async_timeout.timeout(10):
|
async with async_timeout.timeout(10):
|
||||||
device_state_resp = await self.device.fetch_state()
|
device_state_resp = await self.device.fetch_state()
|
||||||
|
device_state = device_state_resp.data.get(ATTR_DEVICE_STATE)
|
||||||
|
if self.paired_device is not None and device_state is not None:
|
||||||
|
paried_device_state_resp = await self.paired_device.fetch_state()
|
||||||
|
paried_device_state = paried_device_state_resp.data.get(
|
||||||
|
ATTR_DEVICE_STATE
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
paried_device_state is not None
|
||||||
|
and ATTR_DEVICE_STATE in paried_device_state
|
||||||
|
):
|
||||||
|
device_state[ATTR_DEVICE_STATE] = paried_device_state[
|
||||||
|
ATTR_DEVICE_STATE
|
||||||
|
]
|
||||||
except YoLinkAuthFailError as yl_auth_err:
|
except YoLinkAuthFailError as yl_auth_err:
|
||||||
raise ConfigEntryAuthFailed from yl_auth_err
|
raise ConfigEntryAuthFailed from yl_auth_err
|
||||||
except YoLinkClientError as yl_client_err:
|
except YoLinkClientError as yl_client_err:
|
||||||
raise UpdateFailed from yl_client_err
|
raise UpdateFailed from yl_client_err
|
||||||
if ATTR_DEVICE_STATE in device_state_resp.data:
|
if device_state is not None:
|
||||||
return device_state_resp.data[ATTR_DEVICE_STATE]
|
return device_state
|
||||||
return {}
|
return {}
|
||||||
|
|
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from yolink.client_request import ClientRequest
|
from yolink.client_request import ClientRequest
|
||||||
from yolink.const import ATTR_GARAGE_DOOR_CONTROLLER
|
from yolink.const import ATTR_DEVICE_FINGER, ATTR_GARAGE_DOOR_CONTROLLER
|
||||||
|
|
||||||
from homeassistant.components.cover import (
|
from homeassistant.components.cover import (
|
||||||
CoverDeviceClass,
|
CoverDeviceClass,
|
||||||
|
@ -30,7 +30,8 @@ async def async_setup_entry(
|
||||||
entities = [
|
entities = [
|
||||||
YoLinkCoverEntity(config_entry, device_coordinator)
|
YoLinkCoverEntity(config_entry, device_coordinator)
|
||||||
for device_coordinator in device_coordinators.values()
|
for device_coordinator in device_coordinators.values()
|
||||||
if device_coordinator.device.device_type == ATTR_GARAGE_DOOR_CONTROLLER
|
if device_coordinator.device.device_type
|
||||||
|
in [ATTR_GARAGE_DOOR_CONTROLLER, ATTR_DEVICE_FINGER]
|
||||||
]
|
]
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
@ -58,6 +59,10 @@ class YoLinkCoverEntity(YoLinkEntity, CoverEntity):
|
||||||
"""Update HA Entity State."""
|
"""Update HA Entity State."""
|
||||||
if (state_val := state.get("state")) is None:
|
if (state_val := state.get("state")) is None:
|
||||||
return
|
return
|
||||||
|
if self.coordinator.paired_device is None:
|
||||||
|
self._attr_is_closed = None
|
||||||
|
self.async_write_ha_state()
|
||||||
|
elif state_val in ["open", "closed"]:
|
||||||
self._attr_is_closed = state_val == "closed"
|
self._attr_is_closed = state_val == "closed"
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
|
@ -6,5 +6,5 @@
|
||||||
"dependencies": ["auth", "application_credentials"],
|
"dependencies": ["auth", "application_credentials"],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/yolink",
|
"documentation": "https://www.home-assistant.io/integrations/yolink",
|
||||||
"iot_class": "cloud_push",
|
"iot_class": "cloud_push",
|
||||||
"requirements": ["yolink-api==0.2.9"]
|
"requirements": ["yolink-api==0.3.0"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ from yolink.const import (
|
||||||
ATTR_DEVICE_CO_SMOKE_SENSOR,
|
ATTR_DEVICE_CO_SMOKE_SENSOR,
|
||||||
ATTR_DEVICE_DIMMER,
|
ATTR_DEVICE_DIMMER,
|
||||||
ATTR_DEVICE_DOOR_SENSOR,
|
ATTR_DEVICE_DOOR_SENSOR,
|
||||||
|
ATTR_DEVICE_FINGER,
|
||||||
ATTR_DEVICE_LEAK_SENSOR,
|
ATTR_DEVICE_LEAK_SENSOR,
|
||||||
ATTR_DEVICE_LOCK,
|
ATTR_DEVICE_LOCK,
|
||||||
ATTR_DEVICE_MANIPULATOR,
|
ATTR_DEVICE_MANIPULATOR,
|
||||||
|
@ -67,6 +68,7 @@ class YoLinkSensorEntityDescription(
|
||||||
SENSOR_DEVICE_TYPE = [
|
SENSOR_DEVICE_TYPE = [
|
||||||
ATTR_DEVICE_DIMMER,
|
ATTR_DEVICE_DIMMER,
|
||||||
ATTR_DEVICE_DOOR_SENSOR,
|
ATTR_DEVICE_DOOR_SENSOR,
|
||||||
|
ATTR_DEVICE_FINGER,
|
||||||
ATTR_DEVICE_LEAK_SENSOR,
|
ATTR_DEVICE_LEAK_SENSOR,
|
||||||
ATTR_DEVICE_MOTION_SENSOR,
|
ATTR_DEVICE_MOTION_SENSOR,
|
||||||
ATTR_DEVICE_MULTI_OUTLET,
|
ATTR_DEVICE_MULTI_OUTLET,
|
||||||
|
@ -86,6 +88,7 @@ SENSOR_DEVICE_TYPE = [
|
||||||
|
|
||||||
BATTERY_POWER_SENSOR = [
|
BATTERY_POWER_SENSOR = [
|
||||||
ATTR_DEVICE_DOOR_SENSOR,
|
ATTR_DEVICE_DOOR_SENSOR,
|
||||||
|
ATTR_DEVICE_FINGER,
|
||||||
ATTR_DEVICE_LEAK_SENSOR,
|
ATTR_DEVICE_LEAK_SENSOR,
|
||||||
ATTR_DEVICE_MOTION_SENSOR,
|
ATTR_DEVICE_MOTION_SENSOR,
|
||||||
ATTR_DEVICE_POWER_FAILURE_ALARM,
|
ATTR_DEVICE_POWER_FAILURE_ALARM,
|
||||||
|
@ -129,6 +132,7 @@ SENSOR_TYPES: tuple[YoLinkSensorEntityDescription, ...] = (
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
value=cvt_battery,
|
value=cvt_battery,
|
||||||
exists_fn=lambda device: device.device_type in BATTERY_POWER_SENSOR,
|
exists_fn=lambda device: device.device_type in BATTERY_POWER_SENSOR,
|
||||||
|
should_update_entity=lambda value: value is not None,
|
||||||
),
|
),
|
||||||
YoLinkSensorEntityDescription(
|
YoLinkSensorEntityDescription(
|
||||||
key="humidity",
|
key="humidity",
|
||||||
|
|
|
@ -5,6 +5,7 @@ from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from yolink.client_request import ClientRequest
|
||||||
from yolink.const import (
|
from yolink.const import (
|
||||||
ATTR_DEVICE_MANIPULATOR,
|
ATTR_DEVICE_MANIPULATOR,
|
||||||
ATTR_DEVICE_MULTI_OUTLET,
|
ATTR_DEVICE_MULTI_OUTLET,
|
||||||
|
@ -160,11 +161,17 @@ 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 switch state."""
|
"""Call setState api to change switch state."""
|
||||||
await self.call_device(
|
client_request: ClientRequest = None
|
||||||
OutletRequestBuilder.set_state_request(
|
if self.coordinator.device.device_type in [
|
||||||
|
ATTR_DEVICE_OUTLET,
|
||||||
|
ATTR_DEVICE_MULTI_OUTLET,
|
||||||
|
]:
|
||||||
|
client_request = OutletRequestBuilder.set_state_request(
|
||||||
state, self.entity_description.plug_index
|
state, self.entity_description.plug_index
|
||||||
)
|
)
|
||||||
)
|
else:
|
||||||
|
client_request = ClientRequest("setState", {"state": state})
|
||||||
|
await self.call_device(client_request)
|
||||||
self._attr_is_on = self._get_state(state, self.entity_description.plug_index)
|
self._attr_is_on = self._get_state(state, self.entity_description.plug_index)
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
|
@ -2723,7 +2723,7 @@ yeelight==0.7.12
|
||||||
yeelightsunflower==0.0.10
|
yeelightsunflower==0.0.10
|
||||||
|
|
||||||
# homeassistant.components.yolink
|
# homeassistant.components.yolink
|
||||||
yolink-api==0.2.9
|
yolink-api==0.3.0
|
||||||
|
|
||||||
# homeassistant.components.youless
|
# homeassistant.components.youless
|
||||||
youless-api==1.0.1
|
youless-api==1.0.1
|
||||||
|
|
|
@ -1999,7 +1999,7 @@ yalexs==1.5.1
|
||||||
yeelight==0.7.12
|
yeelight==0.7.12
|
||||||
|
|
||||||
# homeassistant.components.yolink
|
# homeassistant.components.yolink
|
||||||
yolink-api==0.2.9
|
yolink-api==0.3.0
|
||||||
|
|
||||||
# homeassistant.components.youless
|
# homeassistant.components.youless
|
||||||
youless-api==1.0.1
|
youless-api==1.0.1
|
||||||
|
|
Loading…
Add table
Reference in a new issue