Reolink ptz service to specify move speed (#104350)

pull/92906/head^2
starkillerOG 2023-11-24 11:50:16 +01:00 committed by GitHub
parent 9ed745638d
commit e9dd158a8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 1 deletions

View File

@ -7,22 +7,31 @@ from typing import Any
from reolink_aio.api import GuardEnum, Host, PtzEnum
from reolink_aio.exceptions import ReolinkError
import voluptuous as vol
from homeassistant.components.button import (
ButtonDeviceClass,
ButtonEntity,
ButtonEntityDescription,
)
from homeassistant.components.camera import CameraEntityFeature
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import (
AddEntitiesCallback,
async_get_current_platform,
)
from . import ReolinkData
from .const import DOMAIN
from .entity import ReolinkChannelCoordinatorEntity, ReolinkHostCoordinatorEntity
ATTR_SPEED = "speed"
SUPPORT_PTZ_SPEED = CameraEntityFeature.STREAM
@dataclass(kw_only=True)
class ReolinkButtonEntityDescription(
@ -33,6 +42,7 @@ class ReolinkButtonEntityDescription(
enabled_default: Callable[[Host, int], bool] | None = None
method: Callable[[Host, int], Any]
supported: Callable[[Host, int], bool] = lambda api, ch: True
ptz_cmd: str | None = None
@dataclass(kw_only=True)
@ -60,6 +70,7 @@ BUTTON_ENTITIES = (
icon="mdi:pan",
supported=lambda api, ch: api.supported(ch, "pan"),
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.left.value),
ptz_cmd=PtzEnum.left.value,
),
ReolinkButtonEntityDescription(
key="ptz_right",
@ -67,6 +78,7 @@ BUTTON_ENTITIES = (
icon="mdi:pan",
supported=lambda api, ch: api.supported(ch, "pan"),
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.right.value),
ptz_cmd=PtzEnum.right.value,
),
ReolinkButtonEntityDescription(
key="ptz_up",
@ -74,6 +86,7 @@ BUTTON_ENTITIES = (
icon="mdi:pan",
supported=lambda api, ch: api.supported(ch, "tilt"),
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.up.value),
ptz_cmd=PtzEnum.up.value,
),
ReolinkButtonEntityDescription(
key="ptz_down",
@ -81,6 +94,7 @@ BUTTON_ENTITIES = (
icon="mdi:pan",
supported=lambda api, ch: api.supported(ch, "tilt"),
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.down.value),
ptz_cmd=PtzEnum.down.value,
),
ReolinkButtonEntityDescription(
key="ptz_zoom_in",
@ -89,6 +103,7 @@ BUTTON_ENTITIES = (
entity_registry_enabled_default=False,
supported=lambda api, ch: api.supported(ch, "zoom_basic"),
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.zoomin.value),
ptz_cmd=PtzEnum.zoomin.value,
),
ReolinkButtonEntityDescription(
key="ptz_zoom_out",
@ -97,6 +112,7 @@ BUTTON_ENTITIES = (
entity_registry_enabled_default=False,
supported=lambda api, ch: api.supported(ch, "zoom_basic"),
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.zoomout.value),
ptz_cmd=PtzEnum.zoomout.value,
),
ReolinkButtonEntityDescription(
key="ptz_calibrate",
@ -158,6 +174,14 @@ async def async_setup_entry(
)
async_add_entities(entities)
platform = async_get_current_platform()
platform.async_register_entity_service(
"ptz_move",
{vol.Required(ATTR_SPEED): cv.positive_int},
"async_ptz_move",
[SUPPORT_PTZ_SPEED],
)
class ReolinkButtonEntity(ReolinkChannelCoordinatorEntity, ButtonEntity):
"""Base button entity class for Reolink IP cameras."""
@ -182,6 +206,12 @@ class ReolinkButtonEntity(ReolinkChannelCoordinatorEntity, ButtonEntity):
entity_description.enabled_default(self._host.api, self._channel)
)
if (
self._host.api.supported(channel, "ptz_speed")
and entity_description.ptz_cmd is not None
):
self._attr_supported_features = SUPPORT_PTZ_SPEED
async def async_press(self) -> None:
"""Execute the button action."""
try:
@ -189,6 +219,16 @@ class ReolinkButtonEntity(ReolinkChannelCoordinatorEntity, ButtonEntity):
except ReolinkError as err:
raise HomeAssistantError(err) from err
async def async_ptz_move(self, **kwargs) -> None:
"""PTZ move with speed."""
speed = kwargs[ATTR_SPEED]
try:
await self._host.api.set_ptz_command(
self._channel, command=self.entity_description.ptz_cmd, speed=speed
)
except ReolinkError as err:
raise HomeAssistantError(err) from err
class ReolinkHostButtonEntity(ReolinkHostCoordinatorEntity, ButtonEntity):
"""Base button entity class for Reolink IP cameras."""

View File

@ -0,0 +1,18 @@
# Describes the format for available reolink services
ptz_move:
target:
entity:
integration: reolink
domain: button
supported_features:
- camera.CameraEntityFeature.STREAM
fields:
speed:
required: true
default: 10
selector:
number:
min: 1
max: 64
step: 1

View File

@ -61,6 +61,18 @@
"description": "\"{name}\" with model \"{model}\" and hardware version \"{hw_version}\" is running a old firmware version \"{current_firmware}\", while at least firmware version \"{required_firmware}\" is required for proper operation of the Reolink integration. The latest firmware can be downloaded from the [Reolink download center]({download_link})."
}
},
"services": {
"ptz_move": {
"name": "PTZ move",
"description": "Move the camera with a specific speed.",
"fields": {
"speed": {
"name": "Speed",
"description": "PTZ move speed."
}
}
}
},
"entity": {
"binary_sensor": {
"face": {