mirror of
https://github.com/home-assistant/core.git
synced 2025-07-29 08:07:45 +00:00
Add common reolink entity description (#104142)
Co-authored-by: Robert Resch <robert@resch.dev>
This commit is contained in:
parent
dd00357e9c
commit
69af4c8603
@ -25,16 +25,18 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||||||
|
|
||||||
from . import ReolinkData
|
from . import ReolinkData
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .entity import ReolinkChannelCoordinatorEntity
|
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
class ReolinkBinarySensorEntityDescription(BinarySensorEntityDescription):
|
class ReolinkBinarySensorEntityDescription(
|
||||||
|
BinarySensorEntityDescription,
|
||||||
|
ReolinkChannelEntityDescription,
|
||||||
|
):
|
||||||
"""A class that describes binary sensor entities."""
|
"""A class that describes binary sensor entities."""
|
||||||
|
|
||||||
icon_off: str = "mdi:motion-sensor-off"
|
icon_off: str = "mdi:motion-sensor-off"
|
||||||
icon: str = "mdi:motion-sensor"
|
icon: str = "mdi:motion-sensor"
|
||||||
supported: Callable[[Host, int], bool] = lambda host, ch: True
|
|
||||||
value: Callable[[Host, int], bool]
|
value: Callable[[Host, int], bool]
|
||||||
|
|
||||||
|
|
||||||
@ -128,8 +130,8 @@ class ReolinkBinarySensorEntity(ReolinkChannelCoordinatorEntity, BinarySensorEnt
|
|||||||
entity_description: ReolinkBinarySensorEntityDescription,
|
entity_description: ReolinkBinarySensorEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize Reolink binary sensor."""
|
"""Initialize Reolink binary sensor."""
|
||||||
super().__init__(reolink_data, channel)
|
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
|
super().__init__(reolink_data, channel)
|
||||||
|
|
||||||
if self._host.api.model in DUAL_LENS_DUAL_MOTION_MODELS:
|
if self._host.api.model in DUAL_LENS_DUAL_MOTION_MODELS:
|
||||||
if entity_description.translation_key is not None:
|
if entity_description.translation_key is not None:
|
||||||
@ -138,10 +140,6 @@ class ReolinkBinarySensorEntity(ReolinkChannelCoordinatorEntity, BinarySensorEnt
|
|||||||
key = entity_description.key
|
key = entity_description.key
|
||||||
self._attr_translation_key = f"{key}_lens_{self._channel}"
|
self._attr_translation_key = f"{key}_lens_{self._channel}"
|
||||||
|
|
||||||
self._attr_unique_id = (
|
|
||||||
f"{self._host.unique_id}_{self._channel}_{entity_description.key}"
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def icon(self) -> str | None:
|
def icon(self) -> str | None:
|
||||||
"""Icon of the sensor."""
|
"""Icon of the sensor."""
|
||||||
|
@ -27,7 +27,12 @@ from homeassistant.helpers.entity_platform import (
|
|||||||
|
|
||||||
from . import ReolinkData
|
from . import ReolinkData
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .entity import ReolinkChannelCoordinatorEntity, ReolinkHostCoordinatorEntity
|
from .entity import (
|
||||||
|
ReolinkChannelCoordinatorEntity,
|
||||||
|
ReolinkChannelEntityDescription,
|
||||||
|
ReolinkHostCoordinatorEntity,
|
||||||
|
ReolinkHostEntityDescription,
|
||||||
|
)
|
||||||
|
|
||||||
ATTR_SPEED = "speed"
|
ATTR_SPEED = "speed"
|
||||||
SUPPORT_PTZ_SPEED = CameraEntityFeature.STREAM
|
SUPPORT_PTZ_SPEED = CameraEntityFeature.STREAM
|
||||||
@ -36,21 +41,23 @@ SUPPORT_PTZ_SPEED = CameraEntityFeature.STREAM
|
|||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
class ReolinkButtonEntityDescription(
|
class ReolinkButtonEntityDescription(
|
||||||
ButtonEntityDescription,
|
ButtonEntityDescription,
|
||||||
|
ReolinkChannelEntityDescription,
|
||||||
):
|
):
|
||||||
"""A class that describes button entities for a camera channel."""
|
"""A class that describes button entities for a camera channel."""
|
||||||
|
|
||||||
enabled_default: Callable[[Host, int], bool] | None = None
|
enabled_default: Callable[[Host, int], bool] | None = None
|
||||||
method: Callable[[Host, int], Any]
|
method: Callable[[Host, int], Any]
|
||||||
supported: Callable[[Host, int], bool] = lambda api, ch: True
|
|
||||||
ptz_cmd: str | None = None
|
ptz_cmd: str | None = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
class ReolinkHostButtonEntityDescription(ButtonEntityDescription):
|
class ReolinkHostButtonEntityDescription(
|
||||||
|
ButtonEntityDescription,
|
||||||
|
ReolinkHostEntityDescription,
|
||||||
|
):
|
||||||
"""A class that describes button entities for the host."""
|
"""A class that describes button entities for the host."""
|
||||||
|
|
||||||
method: Callable[[Host], Any]
|
method: Callable[[Host], Any]
|
||||||
supported: Callable[[Host], bool] = lambda api: True
|
|
||||||
|
|
||||||
|
|
||||||
BUTTON_ENTITIES = (
|
BUTTON_ENTITIES = (
|
||||||
@ -195,12 +202,9 @@ class ReolinkButtonEntity(ReolinkChannelCoordinatorEntity, ButtonEntity):
|
|||||||
entity_description: ReolinkButtonEntityDescription,
|
entity_description: ReolinkButtonEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize Reolink button entity."""
|
"""Initialize Reolink button entity."""
|
||||||
super().__init__(reolink_data, channel)
|
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
|
super().__init__(reolink_data, channel)
|
||||||
|
|
||||||
self._attr_unique_id = (
|
|
||||||
f"{self._host.unique_id}_{channel}_{entity_description.key}"
|
|
||||||
)
|
|
||||||
if entity_description.enabled_default is not None:
|
if entity_description.enabled_default is not None:
|
||||||
self._attr_entity_registry_enabled_default = (
|
self._attr_entity_registry_enabled_default = (
|
||||||
entity_description.enabled_default(self._host.api, self._channel)
|
entity_description.enabled_default(self._host.api, self._channel)
|
||||||
@ -241,10 +245,8 @@ class ReolinkHostButtonEntity(ReolinkHostCoordinatorEntity, ButtonEntity):
|
|||||||
entity_description: ReolinkHostButtonEntityDescription,
|
entity_description: ReolinkHostButtonEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize Reolink button entity."""
|
"""Initialize Reolink button entity."""
|
||||||
super().__init__(reolink_data)
|
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
|
super().__init__(reolink_data)
|
||||||
self._attr_unique_id = f"{self._host.unique_id}_{entity_description.key}"
|
|
||||||
|
|
||||||
async def async_press(self) -> None:
|
async def async_press(self) -> None:
|
||||||
"""Execute the button action."""
|
"""Execute the button action."""
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
"""Component providing support for Reolink IP cameras."""
|
"""Component providing support for Reolink IP cameras."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Callable
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from reolink_aio.api import DUAL_LENS_MODELS, Host
|
from reolink_aio.api import DUAL_LENS_MODELS
|
||||||
from reolink_aio.exceptions import ReolinkError
|
from reolink_aio.exceptions import ReolinkError
|
||||||
|
|
||||||
from homeassistant.components.camera import (
|
from homeassistant.components.camera import (
|
||||||
@ -20,7 +19,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||||||
|
|
||||||
from . import ReolinkData
|
from . import ReolinkData
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .entity import ReolinkChannelCoordinatorEntity
|
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -28,11 +27,11 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
class ReolinkCameraEntityDescription(
|
class ReolinkCameraEntityDescription(
|
||||||
CameraEntityDescription,
|
CameraEntityDescription,
|
||||||
|
ReolinkChannelEntityDescription,
|
||||||
):
|
):
|
||||||
"""A class that describes camera entities for a camera channel."""
|
"""A class that describes camera entities for a camera channel."""
|
||||||
|
|
||||||
stream: str
|
stream: str
|
||||||
supported: Callable[[Host, int], bool] = lambda api, ch: True
|
|
||||||
|
|
||||||
|
|
||||||
CAMERA_ENTITIES = (
|
CAMERA_ENTITIES = (
|
||||||
@ -135,10 +134,6 @@ class ReolinkCamera(ReolinkChannelCoordinatorEntity, Camera):
|
|||||||
f"{entity_description.translation_key}_lens_{self._channel}"
|
f"{entity_description.translation_key}_lens_{self._channel}"
|
||||||
)
|
)
|
||||||
|
|
||||||
self._attr_unique_id = (
|
|
||||||
f"{self._host.unique_id}_{channel}_{entity_description.key}"
|
|
||||||
)
|
|
||||||
|
|
||||||
async def stream_source(self) -> str | None:
|
async def stream_source(self) -> str | None:
|
||||||
"""Return the source of the stream."""
|
"""Return the source of the stream."""
|
||||||
return await self._host.api.get_stream_source(
|
return await self._host.api.get_stream_source(
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
"""Reolink parent entity class."""
|
"""Reolink parent entity class."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
|
from dataclasses import dataclass
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
|
|
||||||
from reolink_aio.api import DUAL_LENS_MODELS
|
from reolink_aio.api import DUAL_LENS_MODELS, Host
|
||||||
|
|
||||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
|
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
|
||||||
|
from homeassistant.helpers.entity import EntityDescription
|
||||||
from homeassistant.helpers.update_coordinator import (
|
from homeassistant.helpers.update_coordinator import (
|
||||||
CoordinatorEntity,
|
CoordinatorEntity,
|
||||||
DataUpdateCoordinator,
|
DataUpdateCoordinator,
|
||||||
@ -17,8 +20,22 @@ from .const import DOMAIN
|
|||||||
_T = TypeVar("_T")
|
_T = TypeVar("_T")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(kw_only=True)
|
||||||
|
class ReolinkChannelEntityDescription(EntityDescription):
|
||||||
|
"""A class that describes entities for a camera channel."""
|
||||||
|
|
||||||
|
supported: Callable[[Host, int], bool] = lambda api, ch: True
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(kw_only=True)
|
||||||
|
class ReolinkHostEntityDescription(EntityDescription):
|
||||||
|
"""A class that describes host entities."""
|
||||||
|
|
||||||
|
supported: Callable[[Host], bool] = lambda api: True
|
||||||
|
|
||||||
|
|
||||||
class ReolinkBaseCoordinatorEntity(CoordinatorEntity[DataUpdateCoordinator[_T]]):
|
class ReolinkBaseCoordinatorEntity(CoordinatorEntity[DataUpdateCoordinator[_T]]):
|
||||||
"""Parent class fo Reolink entities."""
|
"""Parent class for Reolink entities."""
|
||||||
|
|
||||||
_attr_has_entity_name = True
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
@ -59,14 +76,20 @@ class ReolinkHostCoordinatorEntity(ReolinkBaseCoordinatorEntity[None]):
|
|||||||
basically a NVR with a single channel that has the camera connected to that channel.
|
basically a NVR with a single channel that has the camera connected to that channel.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
entity_description: ReolinkHostEntityDescription | ReolinkChannelEntityDescription
|
||||||
|
|
||||||
def __init__(self, reolink_data: ReolinkData) -> None:
|
def __init__(self, reolink_data: ReolinkData) -> None:
|
||||||
"""Initialize ReolinkHostCoordinatorEntity."""
|
"""Initialize ReolinkHostCoordinatorEntity."""
|
||||||
super().__init__(reolink_data, reolink_data.device_coordinator)
|
super().__init__(reolink_data, reolink_data.device_coordinator)
|
||||||
|
|
||||||
|
self._attr_unique_id = f"{self._host.unique_id}_{self.entity_description.key}"
|
||||||
|
|
||||||
|
|
||||||
class ReolinkChannelCoordinatorEntity(ReolinkHostCoordinatorEntity):
|
class ReolinkChannelCoordinatorEntity(ReolinkHostCoordinatorEntity):
|
||||||
"""Parent class for Reolink hardware camera entities connected to a channel of the NVR."""
|
"""Parent class for Reolink hardware camera entities connected to a channel of the NVR."""
|
||||||
|
|
||||||
|
entity_description: ReolinkChannelEntityDescription
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
reolink_data: ReolinkData,
|
reolink_data: ReolinkData,
|
||||||
@ -76,6 +99,9 @@ class ReolinkChannelCoordinatorEntity(ReolinkHostCoordinatorEntity):
|
|||||||
super().__init__(reolink_data)
|
super().__init__(reolink_data)
|
||||||
|
|
||||||
self._channel = channel
|
self._channel = channel
|
||||||
|
self._attr_unique_id = (
|
||||||
|
f"{self._host.unique_id}_{channel}_{self.entity_description.key}"
|
||||||
|
)
|
||||||
|
|
||||||
dev_ch = channel
|
dev_ch = channel
|
||||||
if self._host.api.model in DUAL_LENS_MODELS:
|
if self._host.api.model in DUAL_LENS_MODELS:
|
||||||
|
@ -22,17 +22,19 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||||||
|
|
||||||
from . import ReolinkData
|
from . import ReolinkData
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .entity import ReolinkChannelCoordinatorEntity
|
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
class ReolinkLightEntityDescription(LightEntityDescription):
|
class ReolinkLightEntityDescription(
|
||||||
|
LightEntityDescription,
|
||||||
|
ReolinkChannelEntityDescription,
|
||||||
|
):
|
||||||
"""A class that describes light entities."""
|
"""A class that describes light entities."""
|
||||||
|
|
||||||
get_brightness_fn: Callable[[Host, int], int | None] | None = None
|
get_brightness_fn: Callable[[Host, int], int | None] | None = None
|
||||||
is_on_fn: Callable[[Host, int], bool]
|
is_on_fn: Callable[[Host, int], bool]
|
||||||
set_brightness_fn: Callable[[Host, int, int], Any] | None = None
|
set_brightness_fn: Callable[[Host, int, int], Any] | None = None
|
||||||
supported_fn: Callable[[Host, int], bool] = lambda api, ch: True
|
|
||||||
turn_on_off_fn: Callable[[Host, int, bool], Any]
|
turn_on_off_fn: Callable[[Host, int, bool], Any]
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +43,7 @@ LIGHT_ENTITIES = (
|
|||||||
key="floodlight",
|
key="floodlight",
|
||||||
translation_key="floodlight",
|
translation_key="floodlight",
|
||||||
icon="mdi:spotlight-beam",
|
icon="mdi:spotlight-beam",
|
||||||
supported_fn=lambda api, ch: api.supported(ch, "floodLight"),
|
supported=lambda api, ch: api.supported(ch, "floodLight"),
|
||||||
is_on_fn=lambda api, ch: api.whiteled_state(ch),
|
is_on_fn=lambda api, ch: api.whiteled_state(ch),
|
||||||
turn_on_off_fn=lambda api, ch, value: api.set_whiteled(ch, state=value),
|
turn_on_off_fn=lambda api, ch, value: api.set_whiteled(ch, state=value),
|
||||||
get_brightness_fn=lambda api, ch: api.whiteled_brightness(ch),
|
get_brightness_fn=lambda api, ch: api.whiteled_brightness(ch),
|
||||||
@ -52,7 +54,7 @@ LIGHT_ENTITIES = (
|
|||||||
translation_key="ir_lights",
|
translation_key="ir_lights",
|
||||||
icon="mdi:led-off",
|
icon="mdi:led-off",
|
||||||
entity_category=EntityCategory.CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
supported_fn=lambda api, ch: api.supported(ch, "ir_lights"),
|
supported=lambda api, ch: api.supported(ch, "ir_lights"),
|
||||||
is_on_fn=lambda api, ch: api.ir_enabled(ch),
|
is_on_fn=lambda api, ch: api.ir_enabled(ch),
|
||||||
turn_on_off_fn=lambda api, ch, value: api.set_ir_lights(ch, value),
|
turn_on_off_fn=lambda api, ch, value: api.set_ir_lights(ch, value),
|
||||||
),
|
),
|
||||||
@ -61,7 +63,7 @@ LIGHT_ENTITIES = (
|
|||||||
translation_key="status_led",
|
translation_key="status_led",
|
||||||
icon="mdi:lightning-bolt-circle",
|
icon="mdi:lightning-bolt-circle",
|
||||||
entity_category=EntityCategory.CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
supported_fn=lambda api, ch: api.supported(ch, "power_led"),
|
supported=lambda api, ch: api.supported(ch, "power_led"),
|
||||||
is_on_fn=lambda api, ch: api.status_led_enabled(ch),
|
is_on_fn=lambda api, ch: api.status_led_enabled(ch),
|
||||||
turn_on_off_fn=lambda api, ch, value: api.set_status_led(ch, value),
|
turn_on_off_fn=lambda api, ch, value: api.set_status_led(ch, value),
|
||||||
),
|
),
|
||||||
@ -80,7 +82,7 @@ async def async_setup_entry(
|
|||||||
ReolinkLightEntity(reolink_data, channel, entity_description)
|
ReolinkLightEntity(reolink_data, channel, entity_description)
|
||||||
for entity_description in LIGHT_ENTITIES
|
for entity_description in LIGHT_ENTITIES
|
||||||
for channel in reolink_data.host.api.channels
|
for channel in reolink_data.host.api.channels
|
||||||
if entity_description.supported_fn(reolink_data.host.api, channel)
|
if entity_description.supported(reolink_data.host.api, channel)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -96,12 +98,8 @@ class ReolinkLightEntity(ReolinkChannelCoordinatorEntity, LightEntity):
|
|||||||
entity_description: ReolinkLightEntityDescription,
|
entity_description: ReolinkLightEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize Reolink light entity."""
|
"""Initialize Reolink light entity."""
|
||||||
super().__init__(reolink_data, channel)
|
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
|
super().__init__(reolink_data, channel)
|
||||||
self._attr_unique_id = (
|
|
||||||
f"{self._host.unique_id}_{channel}_{entity_description.key}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if entity_description.set_brightness_fn is None:
|
if entity_description.set_brightness_fn is None:
|
||||||
self._attr_supported_color_modes = {ColorMode.ONOFF}
|
self._attr_supported_color_modes = {ColorMode.ONOFF}
|
||||||
|
@ -21,18 +21,20 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||||||
|
|
||||||
from . import ReolinkData
|
from . import ReolinkData
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .entity import ReolinkChannelCoordinatorEntity
|
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
class ReolinkNumberEntityDescription(NumberEntityDescription):
|
class ReolinkNumberEntityDescription(
|
||||||
|
NumberEntityDescription,
|
||||||
|
ReolinkChannelEntityDescription,
|
||||||
|
):
|
||||||
"""A class that describes number entities."""
|
"""A class that describes number entities."""
|
||||||
|
|
||||||
get_max_value: Callable[[Host, int], float] | None = None
|
get_max_value: Callable[[Host, int], float] | None = None
|
||||||
get_min_value: Callable[[Host, int], float] | None = None
|
get_min_value: Callable[[Host, int], float] | None = None
|
||||||
method: Callable[[Host, int, float], Any]
|
method: Callable[[Host, int, float], Any]
|
||||||
mode: NumberMode = NumberMode.AUTO
|
mode: NumberMode = NumberMode.AUTO
|
||||||
supported: Callable[[Host, int], bool] = lambda api, ch: True
|
|
||||||
value: Callable[[Host, int], float | None]
|
value: Callable[[Host, int], float | None]
|
||||||
|
|
||||||
|
|
||||||
@ -378,8 +380,8 @@ class ReolinkNumberEntity(ReolinkChannelCoordinatorEntity, NumberEntity):
|
|||||||
entity_description: ReolinkNumberEntityDescription,
|
entity_description: ReolinkNumberEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize Reolink number entity."""
|
"""Initialize Reolink number entity."""
|
||||||
super().__init__(reolink_data, channel)
|
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
|
super().__init__(reolink_data, channel)
|
||||||
|
|
||||||
if entity_description.get_min_value is not None:
|
if entity_description.get_min_value is not None:
|
||||||
self._attr_native_min_value = entity_description.get_min_value(
|
self._attr_native_min_value = entity_description.get_min_value(
|
||||||
@ -390,9 +392,6 @@ class ReolinkNumberEntity(ReolinkChannelCoordinatorEntity, NumberEntity):
|
|||||||
self._host.api, channel
|
self._host.api, channel
|
||||||
)
|
)
|
||||||
self._attr_mode = entity_description.mode
|
self._attr_mode = entity_description.mode
|
||||||
self._attr_unique_id = (
|
|
||||||
f"{self._host.unique_id}_{channel}_{entity_description.key}"
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_value(self) -> float | None:
|
def native_value(self) -> float | None:
|
||||||
|
@ -24,18 +24,20 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||||||
|
|
||||||
from . import ReolinkData
|
from . import ReolinkData
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .entity import ReolinkChannelCoordinatorEntity
|
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
class ReolinkSelectEntityDescription(SelectEntityDescription):
|
class ReolinkSelectEntityDescription(
|
||||||
|
SelectEntityDescription,
|
||||||
|
ReolinkChannelEntityDescription,
|
||||||
|
):
|
||||||
"""A class that describes select entities."""
|
"""A class that describes select entities."""
|
||||||
|
|
||||||
get_options: list[str] | Callable[[Host, int], list[str]]
|
get_options: list[str] | Callable[[Host, int], list[str]]
|
||||||
method: Callable[[Host, int, str], Any]
|
method: Callable[[Host, int, str], Any]
|
||||||
supported: Callable[[Host, int], bool] = lambda api, ch: True
|
|
||||||
value: Callable[[Host, int], str] | None = None
|
value: Callable[[Host, int], str] | None = None
|
||||||
|
|
||||||
|
|
||||||
@ -131,14 +133,10 @@ class ReolinkSelectEntity(ReolinkChannelCoordinatorEntity, SelectEntity):
|
|||||||
entity_description: ReolinkSelectEntityDescription,
|
entity_description: ReolinkSelectEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize Reolink select entity."""
|
"""Initialize Reolink select entity."""
|
||||||
super().__init__(reolink_data, channel)
|
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
|
super().__init__(reolink_data, channel)
|
||||||
self._log_error = True
|
self._log_error = True
|
||||||
|
|
||||||
self._attr_unique_id = (
|
|
||||||
f"{self._host.unique_id}_{channel}_{entity_description.key}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if callable(entity_description.get_options):
|
if callable(entity_description.get_options):
|
||||||
self._attr_options = entity_description.get_options(self._host.api, channel)
|
self._attr_options = entity_description.get_options(self._host.api, channel)
|
||||||
else:
|
else:
|
||||||
|
@ -21,31 +21,32 @@ from homeassistant.helpers.typing import StateType
|
|||||||
|
|
||||||
from . import ReolinkData
|
from . import ReolinkData
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .entity import ReolinkChannelCoordinatorEntity, ReolinkHostCoordinatorEntity
|
from .entity import (
|
||||||
|
ReolinkChannelCoordinatorEntity,
|
||||||
|
ReolinkChannelEntityDescription,
|
||||||
|
ReolinkHostCoordinatorEntity,
|
||||||
|
ReolinkHostEntityDescription,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
class ReolinkSensorEntityDescription(SensorEntityDescription):
|
class ReolinkSensorEntityDescription(
|
||||||
|
SensorEntityDescription,
|
||||||
|
ReolinkChannelEntityDescription,
|
||||||
|
):
|
||||||
"""A class that describes sensor entities for a camera channel."""
|
"""A class that describes sensor entities for a camera channel."""
|
||||||
|
|
||||||
supported: Callable[[Host, int], bool] = lambda api, ch: True
|
|
||||||
value: Callable[[Host, int], int]
|
value: Callable[[Host, int], int]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass(kw_only=True)
|
||||||
class ReolinkHostSensorEntityDescriptionMixin:
|
|
||||||
"""Mixin values for Reolink host sensor entities."""
|
|
||||||
|
|
||||||
value: Callable[[Host], int | None]
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ReolinkHostSensorEntityDescription(
|
class ReolinkHostSensorEntityDescription(
|
||||||
SensorEntityDescription, ReolinkHostSensorEntityDescriptionMixin
|
SensorEntityDescription,
|
||||||
|
ReolinkHostEntityDescription,
|
||||||
):
|
):
|
||||||
"""A class that describes host sensor entities."""
|
"""A class that describes host sensor entities."""
|
||||||
|
|
||||||
supported: Callable[[Host], bool] = lambda api: True
|
value: Callable[[Host], int | None]
|
||||||
|
|
||||||
|
|
||||||
SENSORS = (
|
SENSORS = (
|
||||||
@ -110,12 +111,8 @@ class ReolinkSensorEntity(ReolinkChannelCoordinatorEntity, SensorEntity):
|
|||||||
entity_description: ReolinkSensorEntityDescription,
|
entity_description: ReolinkSensorEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize Reolink sensor."""
|
"""Initialize Reolink sensor."""
|
||||||
super().__init__(reolink_data, channel)
|
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
|
super().__init__(reolink_data, channel)
|
||||||
self._attr_unique_id = (
|
|
||||||
f"{self._host.unique_id}_{channel}_{entity_description.key}"
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_value(self) -> StateType | date | datetime | Decimal:
|
def native_value(self) -> StateType | date | datetime | Decimal:
|
||||||
@ -134,10 +131,8 @@ class ReolinkHostSensorEntity(ReolinkHostCoordinatorEntity, SensorEntity):
|
|||||||
entity_description: ReolinkHostSensorEntityDescription,
|
entity_description: ReolinkHostSensorEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize Reolink host sensor."""
|
"""Initialize Reolink host sensor."""
|
||||||
super().__init__(reolink_data)
|
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
|
super().__init__(reolink_data)
|
||||||
self._attr_unique_id = f"{self._host.unique_id}_{entity_description.key}"
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_value(self) -> StateType | date | datetime | Decimal:
|
def native_value(self) -> StateType | date | datetime | Decimal:
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
"""Component providing support for Reolink siren entities."""
|
"""Component providing support for Reolink siren entities."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Callable
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from reolink_aio.api import Host
|
|
||||||
from reolink_aio.exceptions import InvalidParameterError, ReolinkError
|
from reolink_aio.exceptions import InvalidParameterError, ReolinkError
|
||||||
|
|
||||||
from homeassistant.components.siren import (
|
from homeassistant.components.siren import (
|
||||||
@ -22,15 +20,15 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||||||
|
|
||||||
from . import ReolinkData
|
from . import ReolinkData
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .entity import ReolinkChannelCoordinatorEntity
|
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ReolinkSirenEntityDescription(SirenEntityDescription):
|
class ReolinkSirenEntityDescription(
|
||||||
|
SirenEntityDescription, ReolinkChannelEntityDescription
|
||||||
|
):
|
||||||
"""A class that describes siren entities."""
|
"""A class that describes siren entities."""
|
||||||
|
|
||||||
supported: Callable[[Host, int], bool] = lambda api, ch: True
|
|
||||||
|
|
||||||
|
|
||||||
SIREN_ENTITIES = (
|
SIREN_ENTITIES = (
|
||||||
ReolinkSirenEntityDescription(
|
ReolinkSirenEntityDescription(
|
||||||
@ -76,12 +74,8 @@ class ReolinkSirenEntity(ReolinkChannelCoordinatorEntity, SirenEntity):
|
|||||||
entity_description: ReolinkSirenEntityDescription,
|
entity_description: ReolinkSirenEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize Reolink siren entity."""
|
"""Initialize Reolink siren entity."""
|
||||||
super().__init__(reolink_data, channel)
|
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
|
super().__init__(reolink_data, channel)
|
||||||
self._attr_unique_id = (
|
|
||||||
f"{self._host.unique_id}_{channel}_{entity_description.key}"
|
|
||||||
)
|
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn on the siren."""
|
"""Turn on the siren."""
|
||||||
|
@ -17,24 +17,33 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||||||
|
|
||||||
from . import ReolinkData
|
from . import ReolinkData
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .entity import ReolinkChannelCoordinatorEntity, ReolinkHostCoordinatorEntity
|
from .entity import (
|
||||||
|
ReolinkChannelCoordinatorEntity,
|
||||||
|
ReolinkChannelEntityDescription,
|
||||||
|
ReolinkHostCoordinatorEntity,
|
||||||
|
ReolinkHostEntityDescription,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
class ReolinkSwitchEntityDescription(SwitchEntityDescription):
|
class ReolinkSwitchEntityDescription(
|
||||||
|
SwitchEntityDescription,
|
||||||
|
ReolinkChannelEntityDescription,
|
||||||
|
):
|
||||||
"""A class that describes switch entities."""
|
"""A class that describes switch entities."""
|
||||||
|
|
||||||
method: Callable[[Host, int, bool], Any]
|
method: Callable[[Host, int, bool], Any]
|
||||||
supported: Callable[[Host, int], bool] = lambda api, ch: True
|
|
||||||
value: Callable[[Host, int], bool]
|
value: Callable[[Host, int], bool]
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
class ReolinkNVRSwitchEntityDescription(SwitchEntityDescription):
|
class ReolinkNVRSwitchEntityDescription(
|
||||||
|
SwitchEntityDescription,
|
||||||
|
ReolinkHostEntityDescription,
|
||||||
|
):
|
||||||
"""A class that describes NVR switch entities."""
|
"""A class that describes NVR switch entities."""
|
||||||
|
|
||||||
method: Callable[[Host, bool], Any]
|
method: Callable[[Host, bool], Any]
|
||||||
supported: Callable[[Host], bool] = lambda api: True
|
|
||||||
value: Callable[[Host], bool]
|
value: Callable[[Host], bool]
|
||||||
|
|
||||||
|
|
||||||
@ -235,12 +244,8 @@ class ReolinkSwitchEntity(ReolinkChannelCoordinatorEntity, SwitchEntity):
|
|||||||
entity_description: ReolinkSwitchEntityDescription,
|
entity_description: ReolinkSwitchEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize Reolink switch entity."""
|
"""Initialize Reolink switch entity."""
|
||||||
super().__init__(reolink_data, channel)
|
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
|
super().__init__(reolink_data, channel)
|
||||||
self._attr_unique_id = (
|
|
||||||
f"{self._host.unique_id}_{channel}_{entity_description.key}"
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
@ -275,8 +280,8 @@ class ReolinkNVRSwitchEntity(ReolinkHostCoordinatorEntity, SwitchEntity):
|
|||||||
entity_description: ReolinkNVRSwitchEntityDescription,
|
entity_description: ReolinkNVRSwitchEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize Reolink switch entity."""
|
"""Initialize Reolink switch entity."""
|
||||||
super().__init__(reolink_data)
|
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
|
super().__init__(reolink_data)
|
||||||
|
|
||||||
self._attr_unique_id = f"{self._host.unique_id}_{entity_description.key}"
|
self._attr_unique_id = f"{self._host.unique_id}_{entity_description.key}"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user