From d6e817aa62f1bdf65ab7e131b6b6903d62ba06ae Mon Sep 17 00:00:00 2001 From: Matrix Date: Tue, 31 Jan 2023 19:20:19 +0530 Subject: [PATCH] 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 --- homeassistant/components/yolink/__init__.py | 101 ++++++++---------- .../components/yolink/binary_sensor.py | 28 ++--- homeassistant/components/yolink/climate.py | 31 ++++-- homeassistant/components/yolink/const.py | 20 ---- .../components/yolink/coordinator.py | 2 +- homeassistant/components/yolink/cover.py | 45 +++----- homeassistant/components/yolink/entity.py | 13 --- homeassistant/components/yolink/light.py | 9 +- homeassistant/components/yolink/lock.py | 9 +- homeassistant/components/yolink/manifest.json | 2 +- homeassistant/components/yolink/sensor.py | 39 ++++--- homeassistant/components/yolink/siren.py | 8 +- homeassistant/components/yolink/switch.py | 17 ++- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 15 files changed, 152 insertions(+), 176 deletions(-) diff --git a/homeassistant/components/yolink/__init__.py b/homeassistant/components/yolink/__init__.py index 58407df38a3..7362a09609a 100644 --- a/homeassistant/components/yolink/__init__.py +++ b/homeassistant/components/yolink/__init__.py @@ -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 diff --git a/homeassistant/components/yolink/binary_sensor.py b/homeassistant/components/yolink/binary_sensor.py index 6e29bccf437..5b9dacb9db7 100644 --- a/homeassistant/components/yolink/binary_sensor.py +++ b/homeassistant/components/yolink/binary_sensor.py @@ -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() diff --git a/homeassistant/components/yolink/climate.py b/homeassistant/components/yolink/climate.py index a151e30062d..e9d11fb77d0 100644 --- a/homeassistant/components/yolink/climate.py +++ b/homeassistant/components/yolink/climate.py @@ -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() diff --git a/homeassistant/components/yolink/const.py b/homeassistant/components/yolink/const.py index c36f01bd4fd..61cbc8b3028 100644 --- a/homeassistant/components/yolink/const.py +++ b/homeassistant/components/yolink/const.py @@ -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" diff --git a/homeassistant/components/yolink/coordinator.py b/homeassistant/components/yolink/coordinator.py index 68a1aef42f7..c3519510e92 100644 --- a/homeassistant/components/yolink/coordinator.py +++ b/homeassistant/components/yolink/coordinator.py @@ -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: diff --git a/homeassistant/components/yolink/cover.py b/homeassistant/components/yolink/cover.py index e7e32764ca8..1b22f76f177 100644 --- a/homeassistant/components/yolink/cover.py +++ b/homeassistant/components/yolink/cover.py @@ -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() diff --git a/homeassistant/components/yolink/entity.py b/homeassistant/components/yolink/entity.py index 0ae960d726f..76ef1ecd534 100644 --- a/homeassistant/components/yolink/entity.py +++ b/homeassistant/components/yolink/entity.py @@ -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 diff --git a/homeassistant/components/yolink/light.py b/homeassistant/components/yolink/light.py index fbb8c8d50c6..7c11b54efa5 100644 --- a/homeassistant/components/yolink/light.py +++ b/homeassistant/components/yolink/light.py @@ -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() diff --git a/homeassistant/components/yolink/lock.py b/homeassistant/components/yolink/lock.py index ca340c2e762..7565c66867a 100644 --- a/homeassistant/components/yolink/lock.py +++ b/homeassistant/components/yolink/lock.py @@ -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() diff --git a/homeassistant/components/yolink/manifest.json b/homeassistant/components/yolink/manifest.json index 3a2a1f6a390..0e0b4f59166 100644 --- a/homeassistant/components/yolink/manifest.json +++ b/homeassistant/components/yolink/manifest.json @@ -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" diff --git a/homeassistant/components/yolink/sensor.py b/homeassistant/components/yolink/sensor.py index 4b658246bc9..9d0cf33ae49 100644 --- a/homeassistant/components/yolink/sensor.py +++ b/homeassistant/components/yolink/sensor.py @@ -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() diff --git a/homeassistant/components/yolink/siren.py b/homeassistant/components/yolink/siren.py index fd1c8e89e07..ad51b912193 100644 --- a/homeassistant/components/yolink/siren.py +++ b/homeassistant/components/yolink/siren.py @@ -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() diff --git a/homeassistant/components/yolink/switch.py b/homeassistant/components/yolink/switch.py index 2ac322002d5..773477e6c3f 100644 --- a/homeassistant/components/yolink/switch.py +++ b/homeassistant/components/yolink/switch.py @@ -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() diff --git a/requirements_all.txt b/requirements_all.txt index 8d7d581a249..96220b50bb8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -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 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 78ec0e09c1a..3aa31d8d210 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -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