Add Reolink chime support (#122752)

This commit is contained in:
starkillerOG 2024-07-31 17:04:09 +02:00 committed by GitHub
parent f764705629
commit 8c0d9a1320
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 549 additions and 54 deletions

View file

@ -8,6 +8,8 @@ import logging
from typing import Any
from reolink_aio.api import (
Chime,
ChimeToneEnum,
DayNightEnum,
HDREnum,
Host,
@ -26,7 +28,11 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import ReolinkData
from .const import DOMAIN
from .entity import ReolinkChannelCoordinatorEntity, ReolinkChannelEntityDescription
from .entity import (
ReolinkChannelCoordinatorEntity,
ReolinkChannelEntityDescription,
ReolinkChimeCoordinatorEntity,
)
_LOGGER = logging.getLogger(__name__)
@ -43,6 +49,18 @@ class ReolinkSelectEntityDescription(
value: Callable[[Host, int], str] | None = None
@dataclass(frozen=True, kw_only=True)
class ReolinkChimeSelectEntityDescription(
SelectEntityDescription,
ReolinkChannelEntityDescription,
):
"""A class that describes select entities for a chime."""
get_options: list[str]
method: Callable[[Chime, str], Any]
value: Callable[[Chime], str]
def _get_quick_reply_id(api: Host, ch: int, mess: str) -> int:
"""Get the quick reply file id from the message string."""
return [k for k, v in api.quick_reply_dict(ch).items() if v == mess][0]
@ -132,6 +150,36 @@ SELECT_ENTITIES = (
),
)
CHIME_SELECT_ENTITIES = (
ReolinkChimeSelectEntityDescription(
key="motion_tone",
cmd_key="GetDingDongCfg",
translation_key="motion_tone",
entity_category=EntityCategory.CONFIG,
get_options=[method.name for method in ChimeToneEnum],
value=lambda chime: ChimeToneEnum(chime.tone("md")).name,
method=lambda chime, name: chime.set_tone("md", ChimeToneEnum[name].value),
),
ReolinkChimeSelectEntityDescription(
key="people_tone",
cmd_key="GetDingDongCfg",
translation_key="people_tone",
entity_category=EntityCategory.CONFIG,
get_options=[method.name for method in ChimeToneEnum],
value=lambda chime: ChimeToneEnum(chime.tone("people")).name,
method=lambda chime, name: chime.set_tone("people", ChimeToneEnum[name].value),
),
ReolinkChimeSelectEntityDescription(
key="visitor_tone",
cmd_key="GetDingDongCfg",
translation_key="visitor_tone",
entity_category=EntityCategory.CONFIG,
get_options=[method.name for method in ChimeToneEnum],
value=lambda chime: ChimeToneEnum(chime.tone("visitor")).name,
method=lambda chime, name: chime.set_tone("visitor", ChimeToneEnum[name].value),
),
)
async def async_setup_entry(
hass: HomeAssistant,
@ -141,12 +189,18 @@ async def async_setup_entry(
"""Set up a Reolink select entities."""
reolink_data: ReolinkData = hass.data[DOMAIN][config_entry.entry_id]
async_add_entities(
entities: list[ReolinkSelectEntity | ReolinkChimeSelectEntity] = [
ReolinkSelectEntity(reolink_data, channel, entity_description)
for entity_description in SELECT_ENTITIES
for channel in reolink_data.host.api.channels
if entity_description.supported(reolink_data.host.api, channel)
]
entities.extend(
ReolinkChimeSelectEntity(reolink_data, chime, entity_description)
for entity_description in CHIME_SELECT_ENTITIES
for chime in reolink_data.host.api.chime_list
)
async_add_entities(entities)
class ReolinkSelectEntity(ReolinkChannelCoordinatorEntity, SelectEntity):
@ -196,3 +250,45 @@ class ReolinkSelectEntity(ReolinkChannelCoordinatorEntity, SelectEntity):
except ReolinkError as err:
raise HomeAssistantError(err) from err
self.async_write_ha_state()
class ReolinkChimeSelectEntity(ReolinkChimeCoordinatorEntity, SelectEntity):
"""Base select entity class for Reolink IP cameras."""
entity_description: ReolinkChimeSelectEntityDescription
def __init__(
self,
reolink_data: ReolinkData,
chime: Chime,
entity_description: ReolinkChimeSelectEntityDescription,
) -> None:
"""Initialize Reolink select entity for a chime."""
self.entity_description = entity_description
super().__init__(reolink_data, chime)
self._log_error = True
self._attr_options = entity_description.get_options
@property
def current_option(self) -> str | None:
"""Return the current option."""
try:
option = self.entity_description.value(self._chime)
except ValueError:
if self._log_error:
_LOGGER.exception("Reolink '%s' has an unknown value", self.name)
self._log_error = False
return None
self._log_error = True
return option
async def async_select_option(self, option: str) -> None:
"""Change the selected option."""
try:
await self.entity_description.method(self._chime, option)
except InvalidParameterError as err:
raise ServiceValidationError(err) from err
except ReolinkError as err:
raise HomeAssistantError(err) from err
self.async_write_ha_state()