mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Reolink ptz service to specify move speed (#104350)
This commit is contained in:
parent
9ed745638d
commit
e9dd158a8d
@ -7,22 +7,31 @@ from typing import Any
|
|||||||
|
|
||||||
from reolink_aio.api import GuardEnum, Host, PtzEnum
|
from reolink_aio.api import GuardEnum, Host, PtzEnum
|
||||||
from reolink_aio.exceptions import ReolinkError
|
from reolink_aio.exceptions import ReolinkError
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.button import (
|
from homeassistant.components.button import (
|
||||||
ButtonDeviceClass,
|
ButtonDeviceClass,
|
||||||
ButtonEntity,
|
ButtonEntity,
|
||||||
ButtonEntityDescription,
|
ButtonEntityDescription,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.camera import CameraEntityFeature
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import EntityCategory
|
from homeassistant.const import EntityCategory
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
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 . import ReolinkData
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .entity import ReolinkChannelCoordinatorEntity, ReolinkHostCoordinatorEntity
|
from .entity import ReolinkChannelCoordinatorEntity, ReolinkHostCoordinatorEntity
|
||||||
|
|
||||||
|
ATTR_SPEED = "speed"
|
||||||
|
SUPPORT_PTZ_SPEED = CameraEntityFeature.STREAM
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
class ReolinkButtonEntityDescription(
|
class ReolinkButtonEntityDescription(
|
||||||
@ -33,6 +42,7 @@ class ReolinkButtonEntityDescription(
|
|||||||
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
|
supported: Callable[[Host, int], bool] = lambda api, ch: True
|
||||||
|
ptz_cmd: str | None = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
@ -60,6 +70,7 @@ BUTTON_ENTITIES = (
|
|||||||
icon="mdi:pan",
|
icon="mdi:pan",
|
||||||
supported=lambda api, ch: api.supported(ch, "pan"),
|
supported=lambda api, ch: api.supported(ch, "pan"),
|
||||||
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.left.value),
|
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.left.value),
|
||||||
|
ptz_cmd=PtzEnum.left.value,
|
||||||
),
|
),
|
||||||
ReolinkButtonEntityDescription(
|
ReolinkButtonEntityDescription(
|
||||||
key="ptz_right",
|
key="ptz_right",
|
||||||
@ -67,6 +78,7 @@ BUTTON_ENTITIES = (
|
|||||||
icon="mdi:pan",
|
icon="mdi:pan",
|
||||||
supported=lambda api, ch: api.supported(ch, "pan"),
|
supported=lambda api, ch: api.supported(ch, "pan"),
|
||||||
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.right.value),
|
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.right.value),
|
||||||
|
ptz_cmd=PtzEnum.right.value,
|
||||||
),
|
),
|
||||||
ReolinkButtonEntityDescription(
|
ReolinkButtonEntityDescription(
|
||||||
key="ptz_up",
|
key="ptz_up",
|
||||||
@ -74,6 +86,7 @@ BUTTON_ENTITIES = (
|
|||||||
icon="mdi:pan",
|
icon="mdi:pan",
|
||||||
supported=lambda api, ch: api.supported(ch, "tilt"),
|
supported=lambda api, ch: api.supported(ch, "tilt"),
|
||||||
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.up.value),
|
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.up.value),
|
||||||
|
ptz_cmd=PtzEnum.up.value,
|
||||||
),
|
),
|
||||||
ReolinkButtonEntityDescription(
|
ReolinkButtonEntityDescription(
|
||||||
key="ptz_down",
|
key="ptz_down",
|
||||||
@ -81,6 +94,7 @@ BUTTON_ENTITIES = (
|
|||||||
icon="mdi:pan",
|
icon="mdi:pan",
|
||||||
supported=lambda api, ch: api.supported(ch, "tilt"),
|
supported=lambda api, ch: api.supported(ch, "tilt"),
|
||||||
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.down.value),
|
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.down.value),
|
||||||
|
ptz_cmd=PtzEnum.down.value,
|
||||||
),
|
),
|
||||||
ReolinkButtonEntityDescription(
|
ReolinkButtonEntityDescription(
|
||||||
key="ptz_zoom_in",
|
key="ptz_zoom_in",
|
||||||
@ -89,6 +103,7 @@ BUTTON_ENTITIES = (
|
|||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
supported=lambda api, ch: api.supported(ch, "zoom_basic"),
|
supported=lambda api, ch: api.supported(ch, "zoom_basic"),
|
||||||
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.zoomin.value),
|
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.zoomin.value),
|
||||||
|
ptz_cmd=PtzEnum.zoomin.value,
|
||||||
),
|
),
|
||||||
ReolinkButtonEntityDescription(
|
ReolinkButtonEntityDescription(
|
||||||
key="ptz_zoom_out",
|
key="ptz_zoom_out",
|
||||||
@ -97,6 +112,7 @@ BUTTON_ENTITIES = (
|
|||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
supported=lambda api, ch: api.supported(ch, "zoom_basic"),
|
supported=lambda api, ch: api.supported(ch, "zoom_basic"),
|
||||||
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.zoomout.value),
|
method=lambda api, ch: api.set_ptz_command(ch, command=PtzEnum.zoomout.value),
|
||||||
|
ptz_cmd=PtzEnum.zoomout.value,
|
||||||
),
|
),
|
||||||
ReolinkButtonEntityDescription(
|
ReolinkButtonEntityDescription(
|
||||||
key="ptz_calibrate",
|
key="ptz_calibrate",
|
||||||
@ -158,6 +174,14 @@ async def async_setup_entry(
|
|||||||
)
|
)
|
||||||
async_add_entities(entities)
|
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):
|
class ReolinkButtonEntity(ReolinkChannelCoordinatorEntity, ButtonEntity):
|
||||||
"""Base button entity class for Reolink IP cameras."""
|
"""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)
|
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:
|
async def async_press(self) -> None:
|
||||||
"""Execute the button action."""
|
"""Execute the button action."""
|
||||||
try:
|
try:
|
||||||
@ -189,6 +219,16 @@ class ReolinkButtonEntity(ReolinkChannelCoordinatorEntity, ButtonEntity):
|
|||||||
except ReolinkError as err:
|
except ReolinkError as err:
|
||||||
raise HomeAssistantError(err) from 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):
|
class ReolinkHostButtonEntity(ReolinkHostCoordinatorEntity, ButtonEntity):
|
||||||
"""Base button entity class for Reolink IP cameras."""
|
"""Base button entity class for Reolink IP cameras."""
|
||||||
|
18
homeassistant/components/reolink/services.yaml
Normal file
18
homeassistant/components/reolink/services.yaml
Normal 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
|
@ -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})."
|
"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": {
|
"entity": {
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
"face": {
|
"face": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user