Skip to content

Commit

Permalink
support presets
Browse files Browse the repository at this point in the history
  • Loading branch information
rbtying committed Jun 23, 2023
1 parent 24bff17 commit de60486
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 16 deletions.
56 changes: 56 additions & 0 deletions custom_components/onvif_ptz/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,16 @@
ATTR_PANTILT,
ATTR_ZOOM,
ATTR_TIMEOUT,
ATTR_PRESET,
ATTR_NAME,
SERVICE_RELATIVE_MOVE_PTZ,
SERVICE_ABSOLUTE_MOVE_PTZ,
SERVICE_CONTINUOUS_MOVE_PTZ,
SERVICE_STOP_PTZ,
SERVICE_GOTO_HOME_POSITION,
SERVICE_GOTO_PRESET,
SERVICE_SET_HOME_POSITION,
SERVICE_SET_PRESET,
DOMAIN,
)
from .device import ONVIFDevice
Expand Down Expand Up @@ -81,6 +87,34 @@ async def async_setup_entry(
},
"async_perform_ptz_stop",
)
platform.async_register_entity_service(
SERVICE_SET_HOME_POSITION,
{},
"async_perform_ptz_set_home_position",
)
platform.async_register_entity_service(
SERVICE_GOTO_HOME_POSITION,
{
vol.Optional(ATTR_SPEED): PTZ_SCHEMA,
},
"async_perform_ptz_goto_home_position",
)
platform.async_register_entity_service(
SERVICE_SET_PRESET,
{
vol.Required(ATTR_PRESET): cv.string,
vol.Optional(ATTR_NAME): cv.string,
},
"async_perform_ptz_set_preset",
)
platform.async_register_entity_service(
SERVICE_GOTO_PRESET,
{
vol.Required(ATTR_PRESET): cv.string,
vol.Optional(ATTR_SPEED): PTZ_SCHEMA,
},
"async_perform_ptz_goto_preset",
)

device = hass.data[DOMAIN][config_entry.unique_id]
async_add_entities(
Expand Down Expand Up @@ -133,3 +167,25 @@ async def async_perform_ptz_stop(self, pan_tilt=None, zoom=None) -> None:
await self.device.async_perform_ptz_stop(
self.profile, pan_tilt=pan_tilt, zoom=zoom
)

async def async_perform_ptz_set_home_position(self) -> None:
"""Perform a SetHomePosition PTZ action on the camera."""
await self.device.async_perform_ptz_set_home_position(self.profile)

async def async_perform_ptz_goto_home_position(self, speed=None) -> None:
"""Perform a GotoHomePosition PTZ action on the camera."""
await self.device.async_perform_ptz_goto_home_position(
self.profile, speed=speed
)

async def async_perform_ptz_set_preset(self, preset, name=None) -> None:
"""Perform a SetPreset PTZ action on the camera."""
await self.device.async_perform_ptz_set_preset(
self.profile, preset=preset, name=name
)

async def async_perform_ptz_goto_preset(self, preset, speed=None) -> None:
"""Perform a GotoPreset PTZ action on the camera."""
await self.device.async_perform_ptz_goto_preset(
self.profile, preset=preset, speed=speed
)
1 change: 0 additions & 1 deletion custom_components/onvif_ptz/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ async def async_setup_profiles(self):
)

device = get_device(
self.hass,
self.onvif_config[CONF_HOST],
self.onvif_config[CONF_PORT],
self.onvif_config[CONF_USERNAME],
Expand Down
6 changes: 6 additions & 0 deletions custom_components/onvif_ptz/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@
ATTR_PANTILT = "pan_tilt"
ATTR_ZOOM = "zoom"
ATTR_TIMEOUT = "timeout"
ATTR_PRESET = "preset"
ATTR_NAME = "name"

SERVICE_RELATIVE_MOVE_PTZ = "ptz_relative"
SERVICE_ABSOLUTE_MOVE_PTZ = "ptz_absolute"
SERVICE_CONTINUOUS_MOVE_PTZ = "ptz_continuous"
SERVICE_STOP_PTZ = "ptz_stop"
SERVICE_SET_HOME_POSITION = "ptz_set_home_position"
SERVICE_GOTO_HOME_POSITION = "ptz_goto_home_position"
SERVICE_SET_PRESET = "ptz_set_preset"
SERVICE_GOTO_PRESET = "ptz_goto_preset"
110 changes: 107 additions & 3 deletions custom_components/onvif_ptz/device.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""ONVIF device abstraction."""
from __future__ import annotations
from typing import Optional

from contextlib import suppress
import datetime as dt
Expand Down Expand Up @@ -75,7 +76,6 @@ def password(self) -> str:
async def async_setup(self) -> bool:
"""Set up the device."""
self.device = get_device(
self.hass,
host=self.config_entry.data[CONF_HOST],
port=self.config_entry.data[CONF_PORT],
username=self.config_entry.data[CONF_USERNAME],
Expand Down Expand Up @@ -360,11 +360,14 @@ async def async_perform_ptz_continuous(
self,
profile: Profile,
velocity,
timeout,
):
"""Perform a ContinuousMove PTZ action on the camera."""
ptz_service = await self.device.create_ptz_service()

LOGGER.debug("Calling ContinousMove PTZ: velocity: %s", velocity)
LOGGER.debug(
"Calling ContinousMove PTZ: velocity: %s, timeout: %s", velocity, timeout
)
try:
req = ptz_service.create_type("ContinuousMove")
req.ProfileToken = profile.token
Expand All @@ -373,6 +376,7 @@ async def async_perform_ptz_continuous(
return

req.Velocity = velocity
req.Timeout = timeout
LOGGER.debug("Making ContinuousMove request %s", req)
await ptz_service.ContinuousMove(req)
except ONVIFError as err:
Expand Down Expand Up @@ -410,8 +414,108 @@ async def async_perform_ptz_relative(
else:
LOGGER.error("Error trying to perform PTZ action: %s", err)

async def async_perform_ptz_set_home_position(
self,
profile: Profile,
):
"""Perform a SetHomePosition PTZ action on the camera."""
ptz_service = await self.device.create_ptz_service()

LOGGER.debug("Calling SetHomePosition")
try:
if not profile.ptz:
LOGGER.warning(
"SetHomePosition not supported on device '%s'", self.name
)
return

LOGGER.debug("Making SetHomePosition request %s", profile.token)
await ptz_service.SetHomePosition(profile.token)
except ONVIFError as err:
if "Bad Request" in err.reason:
LOGGER.warning("Device '%s' doesn't support PTZ", self.name)
else:
LOGGER.error("Error trying to perform PTZ action: %s", err)

async def async_perform_ptz_goto_home_position(self, profile: Profile, speed=None):
"""Perform a GotoHomePosition PTZ action on the camera."""
ptz_service = await self.device.create_ptz_service()

LOGGER.debug("Calling GotoHomePosition speed=%s", speed)
try:
if not profile.ptz:
LOGGER.warning(
"GotoHomePosition not supported on device '%s'", self.name
)
return

req = ptz_service.create_type("GotoHomePosition")
req.ProfileToken = profile.token
req.Speed = speed

LOGGER.debug("Making GotoHomePosition request %s", req)
await ptz_service.GotoHomePosition(req)
except ONVIFError as err:
if "Bad Request" in err.reason:
LOGGER.warning("Device '%s' doesn't support PTZ", self.name)
else:
LOGGER.error("Error trying to perform PTZ action: %s", err)

async def async_perform_ptz_set_preset(
self,
profile: Profile,
preset: str,
name: Optional[str] = None,
):
"""Perform a SetPreset PTZ action on the camera."""
ptz_service = await self.device.create_ptz_service()

LOGGER.debug("Calling SetPreset preset=%s name=%s", preset, name)
try:
if not profile.ptz:
LOGGER.warning("SetPreset not supported on device '%s'", self.name)
return

req = ptz_service.create_type("SetPreset")
req.ProfileToken = profile.token
req.PresetToken = preset
req.PresetName = name

LOGGER.debug("Making SetPreset request %s", req)
await ptz_service.SetPreset(req)
except ONVIFError as err:
if "Bad Request" in err.reason:
LOGGER.warning("Device '%s' doesn't support PTZ", self.name)
else:
LOGGER.error("Error trying to perform PTZ action: %s", err)

async def async_perform_ptz_goto_preset(
self, profile: Profile, preset: str, speed=None
):
"""Perform a GotoPreset PTZ action on the camera."""
ptz_service = await self.device.create_ptz_service()

LOGGER.debug("Calling SetPreset preset=%s speed=%s", preset, speed)
try:
if not profile.ptz:
LOGGER.warning("GotoPrest not supported on device '%s'", self.name)
return

req = ptz_service.create_type("GotoPreset")
req.ProfileToken = profile.token
req.PresetToken = preset
req.Speed = speed

LOGGER.debug("Making GotoPreset request %s", req)
await ptz_service.GotoPreset(req)
except ONVIFError as err:
if "Bad Request" in err.reason:
LOGGER.warning("Device '%s' doesn't support PTZ", self.name)
else:
LOGGER.error("Error trying to perform PTZ action: %s", err)


def get_device(hass, host, port, username, password) -> ONVIFCamera:
def get_device(host, port, username, password) -> ONVIFCamera:
"""Get ONVIFCamera instance."""
return ONVIFCamera(
host,
Expand Down
102 changes: 92 additions & 10 deletions custom_components/onvif_ptz/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ ptz_absolute:
description: >
If your ONVIF camera supports AbsoluteMove PTZ, you will be able to pan,
tilt or zoom your camera. Not all cameras which support PTZ support
absoluteMove. Camera devices may have multiple PTZ nodes, you usually want
AbsoluteMove. Camera devices may have multiple PTZ nodes, you usually want
to select a single entity rather than a device.
target:
entity:
Expand All @@ -53,7 +53,7 @@ ptz_continuous:
description: >
If your ONVIF camera supports ContinuousMove PTZ, you will be able to pan,
tilt or zoom your camera. Not all cameras which support PTZ support
absoluteMove. Camera devices may have multiple PTZ nodes, you usually want
ContinuousMove. Camera devices may have multiple PTZ nodes, you usually want
to select a single entity rather than a device.
target:
entity:
Expand All @@ -67,19 +67,21 @@ ptz_continuous:
description: "How to translate the camera (usually, {PanTilt: {x: 0, y: 0}, Zoom: 0})"
selector:
object:
speed:
name: Speed
description: How fast to translate the camera (optional, same format as translation)
timeout:
name: Timeout
description: "How long to move for (optional)"
selector:
object:
number:
min: 0
max: 100

ptz_stop:
name: PTZ (Stop)
description: >
If your ONVIF camera supports PTZ, you will be able to pan, tilt or zoom
your camera. This command stops any ongoing movement. Not all cameras which
support PTZ support absoluteMove. Camera devices may have multiple PTZ
nodes, you usually want to select a single entity rather than a device.
your camera. This command stops any ongoing movement. Camera devices may
have multiple PTZ nodes, you usually want to select a single entity rather
than a device.
target:
entity:
integration: onvif_ptz
Expand All @@ -96,4 +98,84 @@ ptz_stop:
name: Stop Zoom
description: Stop zoom
selector:
boolean:
boolean:

ptz_set_home_position:
name: PTZ (SetHomePosition)
description: >
Set the home position for the camera. Not all cameras which support PTZ
support setting the home position. Camera devices may have multiple PTZ
nodes, you usually want to select a single entity rather than a device.
target:
entity:
integration: onvif_ptz
domain: button
device:
integration: onvif_ptz

ptz_goto_home_position:
name: PTZ (GotoHomePosition)
description: >
Go to the home position for the camera. Not all cameras which support PTZ
support the home position. Camera devices may have multiple PTZ nodes, you
usually want to select a single entity rather than a device.
target:
entity:
integration: onvif_ptz
domain: button
device:
integration: onvif_ptz
fields:
speed:
name: Speed
description: How fast to translate the camera (optional, same format as translation)
selector:
object:

ptz_set_preset:
name: PTZ (SetPreset)
description: >
Set the specified preset for the camera. Not all cameras which support PTZ
support setting the home position. Camera devices may have multiple PTZ
nodes, you usually want to select a single entity rather than a device.
target:
entity:
integration: onvif_ptz
domain: button
device:
integration: onvif_ptz
fields:
preset:
name: Preset
description: Which preset to set (often, a number)
selector:
text:
name:
name: Name
description: The name for the preset (optional)
selector:
text:

ptz_goto_preset:
name: PTZ (GotoPreset)
description: >
Go to the specified preset for the camera. Not all cameras which support PTZ
support the home position. Camera devices may have multiple PTZ nodes, you
usually want to select a single entity rather than a device.
target:
entity:
integration: onvif_ptz
domain: button
device:
integration: onvif_ptz
fields:
speed:
name: Speed
description: How fast to translate the camera (optional, same format as translation)
selector:
object:
preset:
name: Preset
description: Which preset to go to (often, a number)
selector:
text:
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
WSDiscovery==2.0.0
colorlog==6.7.0
homeassistant==2023.2.0
onvif-zeep-async==1.2.1
homeassistant==2023.6.0
onvif-zeep-async==3.1.9
pip>=21.0,<23.2
ruff==0.0.267

0 comments on commit de60486

Please sign in to comment.