Add YoLink MultiOutlet support (#82622)
This commit is contained in:
parent
412c12b992
commit
f0b979556c
6 changed files with 78 additions and 14 deletions
|
@ -16,6 +16,7 @@ ATTR_DEVICE_ID = "deviceId"
|
||||||
ATTR_DEVICE_DOOR_SENSOR = "DoorSensor"
|
ATTR_DEVICE_DOOR_SENSOR = "DoorSensor"
|
||||||
ATTR_DEVICE_TH_SENSOR = "THSensor"
|
ATTR_DEVICE_TH_SENSOR = "THSensor"
|
||||||
ATTR_DEVICE_MOTION_SENSOR = "MotionSensor"
|
ATTR_DEVICE_MOTION_SENSOR = "MotionSensor"
|
||||||
|
ATTR_DEVICE_MULTI_OUTLET = "MultiOutlet"
|
||||||
ATTR_DEVICE_LEAK_SENSOR = "LeakSensor"
|
ATTR_DEVICE_LEAK_SENSOR = "LeakSensor"
|
||||||
ATTR_DEVICE_VIBRATION_SENSOR = "VibrationSensor"
|
ATTR_DEVICE_VIBRATION_SENSOR = "VibrationSensor"
|
||||||
ATTR_DEVICE_OUTLET = "Outlet"
|
ATTR_DEVICE_OUTLET = "Outlet"
|
||||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
from yolink.client_request import ClientRequest
|
||||||
from yolink.exception import YoLinkAuthFailError, YoLinkClientError
|
from yolink.exception import YoLinkAuthFailError, YoLinkClientError
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
@ -70,3 +71,15 @@ class YoLinkEntity(CoordinatorEntity[YoLinkCoordinator]):
|
||||||
except YoLinkClientError as yl_client_err:
|
except YoLinkClientError as yl_client_err:
|
||||||
self.coordinator.last_update_success = False
|
self.coordinator.last_update_success = False
|
||||||
raise HomeAssistantError(yl_client_err) from yl_client_err
|
raise HomeAssistantError(yl_client_err) from yl_client_err
|
||||||
|
|
||||||
|
async def call_device(self, request: ClientRequest) -> None:
|
||||||
|
"""Call device api."""
|
||||||
|
try:
|
||||||
|
# call_device will check result, fail by raise YoLinkClientError
|
||||||
|
await self.coordinator.device.call_device(request)
|
||||||
|
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
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "YoLink",
|
"name": "YoLink",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/yolink",
|
"documentation": "https://www.home-assistant.io/integrations/yolink",
|
||||||
"requirements": ["yolink-api==0.1.0"],
|
"requirements": ["yolink-api==0.1.5"],
|
||||||
"dependencies": ["auth", "application_credentials"],
|
"dependencies": ["auth", "application_credentials"],
|
||||||
"codeowners": ["@matrixd2"],
|
"codeowners": ["@matrixd2"],
|
||||||
"iot_class": "cloud_push"
|
"iot_class": "cloud_push"
|
||||||
|
|
|
@ -6,6 +6,7 @@ from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from yolink.device import YoLinkDevice
|
from yolink.device import YoLinkDevice
|
||||||
|
from yolink.outlet_request_builder import OutletRequestBuilder
|
||||||
|
|
||||||
from homeassistant.components.switch import (
|
from homeassistant.components.switch import (
|
||||||
SwitchDeviceClass,
|
SwitchDeviceClass,
|
||||||
|
@ -19,6 +20,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_COORDINATORS,
|
ATTR_COORDINATORS,
|
||||||
ATTR_DEVICE_MANIPULATOR,
|
ATTR_DEVICE_MANIPULATOR,
|
||||||
|
ATTR_DEVICE_MULTI_OUTLET,
|
||||||
ATTR_DEVICE_OUTLET,
|
ATTR_DEVICE_OUTLET,
|
||||||
ATTR_DEVICE_SWITCH,
|
ATTR_DEVICE_SWITCH,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
@ -32,8 +34,7 @@ class YoLinkSwitchEntityDescription(SwitchEntityDescription):
|
||||||
"""YoLink SwitchEntityDescription."""
|
"""YoLink SwitchEntityDescription."""
|
||||||
|
|
||||||
exists_fn: Callable[[YoLinkDevice], bool] = lambda _: True
|
exists_fn: Callable[[YoLinkDevice], bool] = lambda _: True
|
||||||
value: Callable[[Any], bool | None] = lambda _: None
|
plug_index: int | None = None
|
||||||
state_key: str = "state"
|
|
||||||
|
|
||||||
|
|
||||||
DEVICE_TYPES: tuple[YoLinkSwitchEntityDescription, ...] = (
|
DEVICE_TYPES: tuple[YoLinkSwitchEntityDescription, ...] = (
|
||||||
|
@ -41,26 +42,63 @@ DEVICE_TYPES: tuple[YoLinkSwitchEntityDescription, ...] = (
|
||||||
key="outlet_state",
|
key="outlet_state",
|
||||||
device_class=SwitchDeviceClass.OUTLET,
|
device_class=SwitchDeviceClass.OUTLET,
|
||||||
name="State",
|
name="State",
|
||||||
value=lambda value: value == "open" if value is not None else None,
|
|
||||||
exists_fn=lambda device: device.device_type == ATTR_DEVICE_OUTLET,
|
exists_fn=lambda device: device.device_type == ATTR_DEVICE_OUTLET,
|
||||||
),
|
),
|
||||||
YoLinkSwitchEntityDescription(
|
YoLinkSwitchEntityDescription(
|
||||||
key="manipulator_state",
|
key="manipulator_state",
|
||||||
name="State",
|
name="State",
|
||||||
icon="mdi:pipe",
|
icon="mdi:pipe",
|
||||||
value=lambda value: value == "open" if value is not None else None,
|
|
||||||
exists_fn=lambda device: device.device_type == ATTR_DEVICE_MANIPULATOR,
|
exists_fn=lambda device: device.device_type == ATTR_DEVICE_MANIPULATOR,
|
||||||
),
|
),
|
||||||
YoLinkSwitchEntityDescription(
|
YoLinkSwitchEntityDescription(
|
||||||
key="switch_state",
|
key="switch_state",
|
||||||
name="State",
|
name="State",
|
||||||
device_class=SwitchDeviceClass.SWITCH,
|
device_class=SwitchDeviceClass.SWITCH,
|
||||||
value=lambda value: value == "open" if value is not None else None,
|
|
||||||
exists_fn=lambda device: device.device_type == ATTR_DEVICE_SWITCH,
|
exists_fn=lambda device: device.device_type == ATTR_DEVICE_SWITCH,
|
||||||
),
|
),
|
||||||
|
YoLinkSwitchEntityDescription(
|
||||||
|
key="multi_outlet_usb_ports",
|
||||||
|
name="UsbPorts",
|
||||||
|
device_class=SwitchDeviceClass.OUTLET,
|
||||||
|
exists_fn=lambda device: device.device_type == ATTR_DEVICE_MULTI_OUTLET,
|
||||||
|
plug_index=0,
|
||||||
|
),
|
||||||
|
YoLinkSwitchEntityDescription(
|
||||||
|
key="multi_outlet_plug_1",
|
||||||
|
name="Plug1",
|
||||||
|
device_class=SwitchDeviceClass.OUTLET,
|
||||||
|
exists_fn=lambda device: device.device_type == ATTR_DEVICE_MULTI_OUTLET,
|
||||||
|
plug_index=1,
|
||||||
|
),
|
||||||
|
YoLinkSwitchEntityDescription(
|
||||||
|
key="multi_outlet_plug_2",
|
||||||
|
name="Plug2",
|
||||||
|
device_class=SwitchDeviceClass.OUTLET,
|
||||||
|
exists_fn=lambda device: device.device_type == ATTR_DEVICE_MULTI_OUTLET,
|
||||||
|
plug_index=2,
|
||||||
|
),
|
||||||
|
YoLinkSwitchEntityDescription(
|
||||||
|
key="multi_outlet_plug_3",
|
||||||
|
name="Plug3",
|
||||||
|
device_class=SwitchDeviceClass.OUTLET,
|
||||||
|
exists_fn=lambda device: device.device_type == ATTR_DEVICE_MULTI_OUTLET,
|
||||||
|
plug_index=3,
|
||||||
|
),
|
||||||
|
YoLinkSwitchEntityDescription(
|
||||||
|
key="multi_outlet_plug_4",
|
||||||
|
name="Plug4",
|
||||||
|
device_class=SwitchDeviceClass.OUTLET,
|
||||||
|
exists_fn=lambda device: device.device_type == ATTR_DEVICE_MULTI_OUTLET,
|
||||||
|
plug_index=4,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
DEVICE_TYPE = [ATTR_DEVICE_MANIPULATOR, ATTR_DEVICE_OUTLET, ATTR_DEVICE_SWITCH]
|
DEVICE_TYPE = [
|
||||||
|
ATTR_DEVICE_MANIPULATOR,
|
||||||
|
ATTR_DEVICE_MULTI_OUTLET,
|
||||||
|
ATTR_DEVICE_OUTLET,
|
||||||
|
ATTR_DEVICE_SWITCH,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
|
@ -108,18 +146,30 @@ class YoLinkSwitchEntity(YoLinkEntity, SwitchEntity):
|
||||||
f"{coordinator.device.device_name} ({self.entity_description.name})"
|
f"{coordinator.device.device_name} ({self.entity_description.name})"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _get_state(
|
||||||
|
self, state_value: str | list[str] | None, plug_index: int | None
|
||||||
|
) -> bool | None:
|
||||||
|
"""Parse state value."""
|
||||||
|
if isinstance(state_value, list) and plug_index is not None:
|
||||||
|
return state_value[plug_index] == "open"
|
||||||
|
return state_value == "open" if state_value is not None else None
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def update_entity_state(self, state: dict[str, Any]) -> None:
|
def update_entity_state(self, state: dict[str, str | list[str]]) -> None:
|
||||||
"""Update HA Entity State."""
|
"""Update HA Entity State."""
|
||||||
self._attr_is_on = self.entity_description.value(
|
self._attr_is_on = self._get_state(
|
||||||
state.get(self.entity_description.state_key)
|
state.get("state"), self.entity_description.plug_index
|
||||||
)
|
)
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
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_api("setState", {"state": state})
|
await self.call_device(
|
||||||
self._attr_is_on = self.entity_description.value(state)
|
OutletRequestBuilder.set_state_request(
|
||||||
|
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()
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
|
|
|
@ -2609,7 +2609,7 @@ yeelight==0.7.10
|
||||||
yeelightsunflower==0.0.10
|
yeelightsunflower==0.0.10
|
||||||
|
|
||||||
# homeassistant.components.yolink
|
# homeassistant.components.yolink
|
||||||
yolink-api==0.1.0
|
yolink-api==0.1.5
|
||||||
|
|
||||||
# homeassistant.components.youless
|
# homeassistant.components.youless
|
||||||
youless-api==0.16
|
youless-api==0.16
|
||||||
|
|
|
@ -1816,7 +1816,7 @@ yalexs==1.2.6
|
||||||
yeelight==0.7.10
|
yeelight==0.7.10
|
||||||
|
|
||||||
# homeassistant.components.yolink
|
# homeassistant.components.yolink
|
||||||
yolink-api==0.1.0
|
yolink-api==0.1.5
|
||||||
|
|
||||||
# homeassistant.components.youless
|
# homeassistant.components.youless
|
||||||
youless-api==0.16
|
youless-api==0.16
|
||||||
|
|
Loading…
Add table
Reference in a new issue