Separate the yolink garage door device from the door sensor (#84561)

* Separate the garage door device from the door sensor

* Bump yolink api to 0.2.1

* fix suggest

* fix typos

* Bump yolink-api to 0.2.6

* Bump version to 0.2.7 and fix rename effects

* change aiohttp min version to 3.8.1
This commit is contained in:
Matrix 2023-01-31 19:20:19 +05:30 committed by GitHub
parent 4dba9c09fc
commit d6e817aa62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 152 additions and 176 deletions

View File

@ -2,14 +2,15 @@
from __future__ import annotations
import asyncio
from dataclasses import dataclass
from datetime import timedelta
from typing import Any
import async_timeout
from yolink.client import YoLinkClient
from yolink.device import YoLinkDevice
from yolink.exception import YoLinkAuthFailError, YoLinkClientError
from yolink.model import BRDP
from yolink.mqtt_client import MqttClient
from yolink.home_manager import YoLinkHome
from yolink.message_listener import MessageListener
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform
@ -18,7 +19,7 @@ from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import aiohttp_client, config_entry_oauth2_flow
from . import api
from .const import ATTR_CLIENT, ATTR_COORDINATORS, ATTR_DEVICE, ATTR_MQTT_CLIENT, DOMAIN
from .const import DOMAIN
from .coordinator import YoLinkCoordinator
SCAN_INTERVAL = timedelta(minutes=5)
@ -36,6 +37,35 @@ PLATFORMS = [
]
class YoLinkHomeMessageListener(MessageListener):
"""YoLink home message listener."""
def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Init YoLink home message listener."""
self._hass = hass
self._entry = entry
def on_message(self, device: YoLinkDevice, msg_data: dict[str, Any]) -> None:
"""On YoLink home message received."""
entry_data = self._hass.data[DOMAIN].get(self._entry.entry_id)
if not entry_data:
return
device_coordinators = entry_data.device_coordinators
if not device_coordinators:
return
device_coordiantor = device_coordinators.get(device.device_id)
if device_coordiantor is not None:
device_coordiantor.async_set_updated_data(msg_data)
@dataclass
class YoLinkHomeStore:
"""YoLink home store."""
home_instance: YoLinkHome
device_coordinators: dict[str, YoLinkCoordinator]
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up yolink from a config entry."""
hass.data.setdefault(DOMAIN, {})
@ -50,58 +80,19 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
auth_mgr = api.ConfigEntryAuth(
hass, aiohttp_client.async_get_clientsession(hass), session
)
yolink_http_client = YoLinkClient(auth_mgr)
yolink_mqtt_client = MqttClient(auth_mgr)
def on_message_callback(message: tuple[str, BRDP]) -> None:
data = message[1]
device_id = message[0]
if data.event is None:
return
event_param = data.event.split(".")
event_type = event_param[len(event_param) - 1]
if event_type not in (
"Report",
"Alert",
"StatusChange",
"getState",
):
return
resolved_state = data.data
if resolved_state is None:
return
entry_data = hass.data[DOMAIN].get(entry.entry_id)
if entry_data is None:
return
device_coordinators = entry_data.get(ATTR_COORDINATORS)
if device_coordinators is None:
return
device_coordinator = device_coordinators.get(device_id)
if device_coordinator is None:
return
device_coordinator.async_set_updated_data(resolved_state)
yolink_home = YoLinkHome()
try:
async with async_timeout.timeout(10):
device_response = await yolink_http_client.get_auth_devices()
home_info = await yolink_http_client.get_general_info()
await yolink_mqtt_client.init_home_connection(
home_info.data["id"], on_message_callback
await yolink_home.async_setup(
auth_mgr, YoLinkHomeMessageListener(hass, entry)
)
except YoLinkAuthFailError as yl_auth_err:
raise ConfigEntryAuthFailed from yl_auth_err
except (YoLinkClientError, asyncio.TimeoutError) as err:
raise ConfigEntryNotReady from err
hass.data[DOMAIN][entry.entry_id] = {
ATTR_CLIENT: yolink_http_client,
ATTR_MQTT_CLIENT: yolink_mqtt_client,
}
auth_devices = device_response.data[ATTR_DEVICE]
device_coordinators = {}
for device_info in auth_devices:
device = YoLinkDevice(device_info, yolink_http_client)
for device in yolink_home.get_devices():
device_coordinator = YoLinkCoordinator(hass, device)
try:
await device_coordinator.async_config_entry_first_refresh()
@ -109,15 +100,17 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# Not failure by fetching device state
device_coordinator.data = {}
device_coordinators[device.device_id] = device_coordinator
hass.data[DOMAIN][entry.entry_id][ATTR_COORDINATORS] = device_coordinators
hass.data[DOMAIN][entry.entry_id] = YoLinkHomeStore(
yolink_home, device_coordinators
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
async def shutdown_subscription(event) -> None:
"""Shutdown mqtt message subscription."""
await yolink_mqtt_client.shutdown_home_subscription()
async def async_yolink_unload(event) -> None:
"""Unload yolink."""
await yolink_home.async_unload()
entry.async_on_unload(
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, shutdown_subscription)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_yolink_unload)
)
return True
@ -126,8 +119,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
await hass.data[DOMAIN][entry.entry_id][
ATTR_MQTT_CLIENT
].shutdown_home_subscription()
await hass.data[DOMAIN][entry.entry_id].home_instance.async_unload()
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok

View File

@ -5,6 +5,13 @@ from collections.abc import Callable
from dataclasses import dataclass
from typing import Any
from yolink.const import (
ATTR_DEVICE_CO_SMOKE_SENSOR,
ATTR_DEVICE_DOOR_SENSOR,
ATTR_DEVICE_LEAK_SENSOR,
ATTR_DEVICE_MOTION_SENSOR,
ATTR_DEVICE_VIBRATION_SENSOR,
)
from yolink.device import YoLinkDevice
from homeassistant.components.binary_sensor import (
@ -16,15 +23,7 @@ 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_CO_SMOKE_SENSOR,
ATTR_DEVICE_DOOR_SENSOR,
ATTR_DEVICE_LEAK_SENSOR,
ATTR_DEVICE_MOTION_SENSOR,
ATTR_DEVICE_VIBRATION_SENSOR,
DOMAIN,
)
from .const import DOMAIN
from .coordinator import YoLinkCoordinator
from .entity import YoLinkEntity
@ -47,13 +46,6 @@ SENSOR_DEVICE_TYPE = [
]
def is_door_sensor(device: YoLinkDevice) -> bool:
"""Check Door Sensor type."""
return device.device_type == ATTR_DEVICE_DOOR_SENSOR and (
device.parent_id is None or device.parent_id == "null"
)
SENSOR_TYPES: tuple[YoLinkBinarySensorEntityDescription, ...] = (
YoLinkBinarySensorEntityDescription(
key="door_state",
@ -61,7 +53,7 @@ SENSOR_TYPES: tuple[YoLinkBinarySensorEntityDescription, ...] = (
device_class=BinarySensorDeviceClass.DOOR,
name="State",
value=lambda value: value == "open" if value is not None else None,
exists_fn=is_door_sensor,
exists_fn=lambda device: device.device_type == ATTR_DEVICE_DOOR_SENSOR,
),
YoLinkBinarySensorEntityDescription(
key="motion_state",
@ -108,7 +100,7 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up YoLink Sensor from a config entry."""
device_coordinators = hass.data[DOMAIN][config_entry.entry_id][ATTR_COORDINATORS]
device_coordinators = hass.data[DOMAIN][config_entry.entry_id].device_coordinators
binary_sensor_device_coordinators = [
device_coordinator
for device_coordinator in device_coordinators.values()

View File

@ -3,6 +3,9 @@ from __future__ import annotations
from typing import Any
from yolink.const import ATTR_DEVICE_THERMOSTAT
from yolink.thermostat_request_builder import ThermostatRequestBuilder, ThermostatState
from homeassistant.components.climate import (
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
@ -20,7 +23,7 @@ from homeassistant.const import UnitOfTemperature
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import ATTR_COORDINATORS, ATTR_DEVICE_THERMOSTAT, DOMAIN
from .const import DOMAIN
from .coordinator import YoLinkCoordinator
from .entity import YoLinkEntity
@ -46,7 +49,7 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up YoLink Thermostat from a config entry."""
device_coordinators = hass.data[DOMAIN][config_entry.entry_id][ATTR_COORDINATORS]
device_coordinators = hass.data[DOMAIN][config_entry.entry_id].device_coordinators
entities = [
YoLinkClimateEntity(config_entry, device_coordinator)
for device_coordinator in device_coordinators.values()
@ -107,12 +110,18 @@ class YoLinkClimateEntity(YoLinkEntity, ClimateEntity):
"""Set new target hvac mode."""
if (hvac_mode_id := HA_MODEL_2_YOLINK.get(hvac_mode)) is None:
raise ValueError(f"Received an invalid hvac mode: {hvac_mode}")
await self.call_device_api("setState", {"mode": hvac_mode_id})
await self.call_device(
ThermostatRequestBuilder.set_state_request(
ThermostatState(mode=hvac_mode_id)
)
)
await self.coordinator.async_refresh()
async def async_set_fan_mode(self, fan_mode: str) -> None:
"""Set fan mode."""
await self.call_device_api("setState", {"fan": fan_mode})
await self.call_device(
ThermostatRequestBuilder.set_state_request(ThermostatState(fan=fan_mode))
)
self._attr_fan_mode = fan_mode
self.async_write_ha_state()
@ -121,16 +130,24 @@ class YoLinkClimateEntity(YoLinkEntity, ClimateEntity):
target_temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW)
target_temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH)
if target_temp_low is not None:
await self.call_device_api("setState", {"lowTemp": target_temp_low})
await self.call_device(
ThermostatRequestBuilder.set_state_request(
ThermostatState(lowTemp=target_temp_low)
)
)
self._attr_target_temperature_low = target_temp_low
if target_temp_high is not None:
await self.call_device_api("setState", {"highTemp": target_temp_high})
await self.call_device(
ThermostatRequestBuilder.set_state_request(
ThermostatState(highTemp=target_temp_high)
)
)
self._attr_target_temperature_high = target_temp_high
await self.coordinator.async_refresh()
async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set preset mode."""
eco_params = "on" if preset_mode == PRESET_ECO else "off"
await self.call_device_api("setECO", {"mode": eco_params})
await self.call_device(ThermostatRequestBuilder.set_eco_request(eco_params))
self._attr_preset_mode = PRESET_ECO if eco_params == "on" else PRESET_NONE
self.async_write_ha_state()

View File

@ -2,28 +2,8 @@
DOMAIN = "yolink"
MANUFACTURER = "YoLink"
HOME_ID = "homeId"
HOME_SUBSCRIPTION = "home_subscription"
ATTR_PLATFORM_SENSOR = "sensor"
ATTR_COORDINATORS = "coordinators"
ATTR_DEVICE = "devices"
ATTR_DEVICE_TYPE = "type"
ATTR_DEVICE_NAME = "name"
ATTR_DEVICE_STATE = "state"
ATTR_CLIENT = "client"
ATTR_MQTT_CLIENT = "mqtt_client"
ATTR_DEVICE_ID = "deviceId"
ATTR_DEVICE_DOOR_SENSOR = "DoorSensor"
ATTR_DEVICE_TH_SENSOR = "THSensor"
ATTR_DEVICE_MOTION_SENSOR = "MotionSensor"
ATTR_DEVICE_MULTI_OUTLET = "MultiOutlet"
ATTR_DEVICE_LEAK_SENSOR = "LeakSensor"
ATTR_DEVICE_VIBRATION_SENSOR = "VibrationSensor"
ATTR_DEVICE_OUTLET = "Outlet"
ATTR_DEVICE_SIREN = "Siren"
ATTR_DEVICE_LOCK = "Lock"
ATTR_DEVICE_MANIPULATOR = "Manipulator"
ATTR_DEVICE_CO_SMOKE_SENSOR = "COSmokeSensor"
ATTR_DEVICE_SWITCH = "Switch"
ATTR_DEVICE_THERMOSTAT = "Thermostat"
ATTR_DEVICE_DIMMER = "Dimmer"

View File

@ -35,7 +35,7 @@ class YoLinkCoordinator(DataUpdateCoordinator[dict]):
"""Fetch device state."""
try:
async with async_timeout.timeout(10):
device_state_resp = await self.device.fetch_state_with_api()
device_state_resp = await self.device.fetch_state()
except YoLinkAuthFailError as yl_auth_err:
raise ConfigEntryAuthFailed from yl_auth_err
except YoLinkClientError as yl_client_err:

View File

@ -3,6 +3,9 @@ from __future__ import annotations
from typing import Any
from yolink.client_request import ClientRequest
from yolink.const import ATTR_GARAGE_DOOR_CONTROLLER
from homeassistant.components.cover import (
CoverDeviceClass,
CoverEntity,
@ -12,7 +15,7 @@ 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_DOOR_SENSOR, DOMAIN
from .const import DOMAIN
from .coordinator import YoLinkCoordinator
from .entity import YoLinkEntity
@ -23,13 +26,11 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up YoLink garage door from a config entry."""
device_coordinators = hass.data[DOMAIN][config_entry.entry_id][ATTR_COORDINATORS]
device_coordinators = hass.data[DOMAIN][config_entry.entry_id].device_coordinators
entities = [
YoLinkCoverEntity(config_entry, device_coordinator)
for device_coordinator in device_coordinators.values()
if device_coordinator.device.device_type == ATTR_DEVICE_DOOR_SENSOR
and device_coordinator.device.parent_id is not None
and device_coordinator.device.parent_id != "null"
if device_coordinator.device.device_type == ATTR_GARAGE_DOOR_CONTROLLER
]
async_add_entities(entities)
@ -54,33 +55,21 @@ class YoLinkCoverEntity(YoLinkEntity, CoverEntity):
@callback
def update_entity_state(self, state: dict[str, Any]) -> None:
"""Update HA Entity State."""
self._attr_is_closed = state.get("state") == "closed"
if (state_val := state.get("state")) is None:
return
self._attr_is_closed = state_val == "closed"
self.async_write_ha_state()
async def toggle_garage_state(self, state: str) -> None:
async def toggle_garage_state(self) -> None:
"""Toggle Garage door state."""
# make sure current state is correct
await self.coordinator.async_refresh()
if state == "open" and self.is_closed is False:
return
if state == "close" and self.is_closed is True:
return
# get paired controller
door_controller_coordinator = self.hass.data[DOMAIN][
self.config_entry.entry_id
][ATTR_COORDINATORS].get(self.coordinator.device.parent_id)
if door_controller_coordinator is None:
raise ValueError(
"This device has not been paired with a garage door controller"
)
# call controller api open/close garage door
await door_controller_coordinator.device.call_device_http_api("toggle", None)
await self.coordinator.async_refresh()
# garage door state will not be changed by device call
# it depends on paired device state, such as door sensor or contact sensor
await self.call_device(ClientRequest("toggle", {}))
async def async_open_cover(self, **kwargs: Any) -> None:
"""Open garage door."""
await self.toggle_garage_state("open")
"""Toggle garage door."""
await self.toggle_garage_state()
async def async_close_cover(self, **kwargs: Any) -> None:
"""Close garage door."""
await self.toggle_garage_state("close")
"""Toggle garage door."""
await self.toggle_garage_state()

View File

@ -60,18 +60,6 @@ class YoLinkEntity(CoordinatorEntity[YoLinkCoordinator]):
def update_entity_state(self, state: dict) -> None:
"""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
async def call_device(self, request: ClientRequest) -> None:
"""Call device api."""
try:
@ -81,5 +69,4 @@ class YoLinkEntity(CoordinatorEntity[YoLinkCoordinator]):
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

View File

@ -3,12 +3,15 @@ from __future__ import annotations
from typing import Any
from yolink.client_request import ClientRequest
from yolink.const import ATTR_DEVICE_DIMMER
from homeassistant.components.light import ATTR_BRIGHTNESS, ColorMode, LightEntity
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_DIMMER, DOMAIN
from .const import DOMAIN
from .coordinator import YoLinkCoordinator
from .entity import YoLinkEntity
@ -19,7 +22,7 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up YoLink Dimmer from a config entry."""
device_coordinators = hass.data[DOMAIN][config_entry.entry_id][ATTR_COORDINATORS]
device_coordinators = hass.data[DOMAIN][config_entry.entry_id].device_coordinators
entities = [
YoLinkDimmerEntity(config_entry, device_coordinator)
for device_coordinator in device_coordinators.values()
@ -61,7 +64,7 @@ class YoLinkDimmerEntity(YoLinkEntity, LightEntity):
if brightness is not None:
self._attr_brightness = brightness
params["brightness"] = round(brightness / 255, 2) * 100
await self.call_device_api("setState", params)
await self.call_device(ClientRequest("setState", params))
self._attr_is_on = state == "open"
self.async_write_ha_state()

View File

@ -3,12 +3,15 @@ from __future__ import annotations
from typing import Any
from yolink.client_request import ClientRequest
from yolink.const import ATTR_DEVICE_LOCK
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 .const import DOMAIN
from .coordinator import YoLinkCoordinator
from .entity import YoLinkEntity
@ -19,7 +22,7 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up YoLink lock from a config entry."""
device_coordinators = hass.data[DOMAIN][config_entry.entry_id][ATTR_COORDINATORS]
device_coordinators = hass.data[DOMAIN][config_entry.entry_id].device_coordinators
entities = [
YoLinkLockEntity(config_entry, device_coordinator)
for device_coordinator in device_coordinators.values()
@ -52,7 +55,7 @@ class YoLinkLockEntity(YoLinkEntity, LockEntity):
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})
await self.call_device(ClientRequest("setState", {"state": state}))
self._attr_is_locked = state == "lock"
self.async_write_ha_state()

View File

@ -3,7 +3,7 @@
"name": "YoLink",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/yolink",
"requirements": ["yolink-api==0.1.5"],
"requirements": ["yolink-api==0.2.8"],
"dependencies": ["auth", "application_credentials"],
"codeowners": ["@matrixd2"],
"iot_class": "cloud_push"

View File

@ -4,6 +4,23 @@ from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from yolink.const import (
ATTR_DEVICE_CO_SMOKE_SENSOR,
ATTR_DEVICE_DIMMER,
ATTR_DEVICE_DOOR_SENSOR,
ATTR_DEVICE_LEAK_SENSOR,
ATTR_DEVICE_LOCK,
ATTR_DEVICE_MANIPULATOR,
ATTR_DEVICE_MOTION_SENSOR,
ATTR_DEVICE_MULTI_OUTLET,
ATTR_DEVICE_OUTLET,
ATTR_DEVICE_SIREN,
ATTR_DEVICE_SWITCH,
ATTR_DEVICE_TH_SENSOR,
ATTR_DEVICE_THERMOSTAT,
ATTR_DEVICE_VIBRATION_SENSOR,
ATTR_GARAGE_DOOR_CONTROLLER,
)
from yolink.device import YoLinkDevice
from homeassistant.components.sensor import (
@ -23,18 +40,7 @@ from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util import percentage
from .const import (
ATTR_COORDINATORS,
ATTR_DEVICE_CO_SMOKE_SENSOR,
ATTR_DEVICE_DOOR_SENSOR,
ATTR_DEVICE_LEAK_SENSOR,
ATTR_DEVICE_LOCK,
ATTR_DEVICE_MANIPULATOR,
ATTR_DEVICE_MOTION_SENSOR,
ATTR_DEVICE_TH_SENSOR,
ATTR_DEVICE_VIBRATION_SENSOR,
DOMAIN,
)
from .const import DOMAIN
from .coordinator import YoLinkCoordinator
from .entity import YoLinkEntity
@ -57,14 +63,21 @@ class YoLinkSensorEntityDescription(
SENSOR_DEVICE_TYPE = [
ATTR_DEVICE_DIMMER,
ATTR_DEVICE_DOOR_SENSOR,
ATTR_DEVICE_LEAK_SENSOR,
ATTR_DEVICE_MOTION_SENSOR,
ATTR_DEVICE_MULTI_OUTLET,
ATTR_DEVICE_OUTLET,
ATTR_DEVICE_SIREN,
ATTR_DEVICE_SWITCH,
ATTR_DEVICE_TH_SENSOR,
ATTR_DEVICE_THERMOSTAT,
ATTR_DEVICE_VIBRATION_SENSOR,
ATTR_DEVICE_LOCK,
ATTR_DEVICE_MANIPULATOR,
ATTR_DEVICE_CO_SMOKE_SENSOR,
ATTR_GARAGE_DOOR_CONTROLLER,
]
BATTERY_POWER_SENSOR = [
@ -150,7 +163,7 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up YoLink Sensor from a config entry."""
device_coordinators = hass.data[DOMAIN][config_entry.entry_id][ATTR_COORDINATORS]
device_coordinators = hass.data[DOMAIN][config_entry.entry_id].device_coordinators
sensor_device_coordinators = [
device_coordinator
for device_coordinator in device_coordinators.values()

View File

@ -5,6 +5,8 @@ from collections.abc import Callable
from dataclasses import dataclass
from typing import Any
from yolink.client_request import ClientRequest
from yolink.const import ATTR_DEVICE_SIREN
from yolink.device import YoLinkDevice
from homeassistant.components.siren import (
@ -16,7 +18,7 @@ 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_SIREN, DOMAIN
from .const import DOMAIN
from .coordinator import YoLinkCoordinator
from .entity import YoLinkEntity
@ -47,7 +49,7 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up YoLink siren from a config entry."""
device_coordinators = hass.data[DOMAIN][config_entry.entry_id][ATTR_COORDINATORS]
device_coordinators = hass.data[DOMAIN][config_entry.entry_id].device_coordinators
siren_device_coordinators = [
device_coordinator
for device_coordinator in device_coordinators.values()
@ -99,7 +101,7 @@ class YoLinkSirenEntity(YoLinkEntity, SirenEntity):
async def call_state_change(self, state: bool) -> None:
"""Call setState api to change siren state."""
await self.call_device_api("setState", {"state": {"alarm": state}})
await self.call_device(ClientRequest("setState", {"state": {"alarm": state}}))
self._attr_is_on = self.entity_description.value("alert" if state else "normal")
self.async_write_ha_state()

View File

@ -5,6 +5,12 @@ from collections.abc import Callable
from dataclasses import dataclass
from typing import Any
from yolink.const import (
ATTR_DEVICE_MANIPULATOR,
ATTR_DEVICE_MULTI_OUTLET,
ATTR_DEVICE_OUTLET,
ATTR_DEVICE_SWITCH,
)
from yolink.device import YoLinkDevice
from yolink.outlet_request_builder import OutletRequestBuilder
@ -17,14 +23,7 @@ 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_MANIPULATOR,
ATTR_DEVICE_MULTI_OUTLET,
ATTR_DEVICE_OUTLET,
ATTR_DEVICE_SWITCH,
DOMAIN,
)
from .const import DOMAIN
from .coordinator import YoLinkCoordinator
from .entity import YoLinkEntity
@ -107,7 +106,7 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up YoLink switch from a config entry."""
device_coordinators = hass.data[DOMAIN][config_entry.entry_id][ATTR_COORDINATORS]
device_coordinators = hass.data[DOMAIN][config_entry.entry_id].device_coordinators
switch_device_coordinators = [
device_coordinator
for device_coordinator in device_coordinators.values()

View File

@ -2672,7 +2672,7 @@ yeelight==0.7.10
yeelightsunflower==0.0.10
# homeassistant.components.yolink
yolink-api==0.1.5
yolink-api==0.2.8
# homeassistant.components.youless
youless-api==0.16

View File

@ -1891,7 +1891,7 @@ yalexs_ble==1.12.8
yeelight==0.7.10
# homeassistant.components.yolink
yolink-api==0.1.5
yolink-api==0.2.8
# homeassistant.components.youless
youless-api==0.16