onvif: Add absolute and relative movements for PTZ
Right now only continous movement is possible with the onvif component, which makes it not usable for many usecases. This patch adds the possibisity to set absolute and relative movements for PTZ but stays backwards compatible so we don't break the API.
This commit is contained in:
parent
909c3bdd63
commit
584ea43d8e
1 changed files with 32 additions and 14 deletions
|
@ -39,6 +39,7 @@ CONF_PROFILE = "profile"
|
|||
ATTR_PAN = "pan"
|
||||
ATTR_TILT = "tilt"
|
||||
ATTR_ZOOM = "zoom"
|
||||
ATTR_TYPE = "type"
|
||||
|
||||
DIR_UP = "UP"
|
||||
DIR_DOWN = "DOWN"
|
||||
|
@ -46,6 +47,9 @@ DIR_LEFT = "LEFT"
|
|||
DIR_RIGHT = "RIGHT"
|
||||
ZOOM_OUT = "ZOOM_OUT"
|
||||
ZOOM_IN = "ZOOM_IN"
|
||||
TYPE_CONTINOUS = "CONTINOUS"
|
||||
TYPE_ABSOLUTE = "ABSOLUTE"
|
||||
TYPE_RELATIVE = "RELATIVE"
|
||||
|
||||
SERVICE_PTZ = "onvif_ptz"
|
||||
|
||||
|
@ -65,9 +69,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|||
|
||||
SERVICE_PTZ_SCHEMA = vol.Schema({
|
||||
ATTR_ENTITY_ID: cv.entity_ids,
|
||||
ATTR_PAN: vol.In([DIR_LEFT, DIR_RIGHT]),
|
||||
ATTR_TILT: vol.In([DIR_UP, DIR_DOWN]),
|
||||
ATTR_ZOOM: vol.In([ZOOM_OUT, ZOOM_IN])
|
||||
ATTR_PAN: vol.Or(vol.In([DIR_LEFT, DIR_RIGHT]), vol.Range(min=-1, max=1)),
|
||||
ATTR_TILT: vol.Or(vol.In([DIR_UP, DIR_DOWN]), vol.Range(min=-1, max=1)),
|
||||
ATTR_ZOOM: vol.Or(vol.In([ZOOM_OUT, ZOOM_IN]), vol.Range(min=-1, max=1)),
|
||||
vol.Required(ATTR_TYPE, default=TYPE_CONTINOUS):
|
||||
vol.In([TYPE_CONTINOUS, TYPE_ABSOLUTE, TYPE_RELATIVE])
|
||||
})
|
||||
|
||||
|
||||
|
@ -81,6 +87,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
pan = service.data.get(ATTR_PAN, None)
|
||||
tilt = service.data.get(ATTR_TILT, None)
|
||||
zoom = service.data.get(ATTR_ZOOM, None)
|
||||
type_ = service.data.get(ATTR_TYPE, None)
|
||||
all_cameras = hass.data[ONVIF_DATA][ENTITIES]
|
||||
entity_ids = extract_entity_ids(hass, service)
|
||||
target_cameras = []
|
||||
|
@ -90,7 +97,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
target_cameras = [camera for camera in all_cameras
|
||||
if camera.entity_id in entity_ids]
|
||||
for camera in target_cameras:
|
||||
camera.perform_ptz(pan, tilt, zoom)
|
||||
camera.perform_ptz(type_, pan, tilt, zoom)
|
||||
|
||||
hass.services.async_register(DOMAIN, SERVICE_PTZ, handle_ptz,
|
||||
schema=SERVICE_PTZ_SCHEMA)
|
||||
|
@ -162,23 +169,34 @@ class ONVIFHassCamera(Camera):
|
|||
self._name, err)
|
||||
return
|
||||
|
||||
def perform_ptz(self, pan, tilt, zoom):
|
||||
def perform_ptz(self, type_, pan, tilt, zoom):
|
||||
"""Perform a PTZ action on the camera."""
|
||||
from onvif import exceptions
|
||||
|
||||
if self._ptz_service:
|
||||
pan_val = 1 if pan == DIR_RIGHT else -1 if pan == DIR_LEFT else 0
|
||||
tilt_val = 1 if tilt == DIR_UP else -1 if tilt == DIR_DOWN else 0
|
||||
zoom_val = 1 if zoom == ZOOM_IN else -1 if zoom == ZOOM_OUT else 0
|
||||
req = {"Velocity": {
|
||||
"PanTilt": {"_x": pan_val, "_y": tilt_val},
|
||||
"Zoom": {"_x": zoom_val}}}
|
||||
type_val = "continous" if type_ == "" else type_
|
||||
pan_val = 1 if pan == DIR_RIGHT else -1 if pan == DIR_LEFT else (pan or 0)
|
||||
tilt_val = 1 if tilt == DIR_UP else -1 if tilt == DIR_DOWN else (tilt or 0)
|
||||
zoom_val = 1 if zoom == ZOOM_IN else -1 if zoom == ZOOM_OUT else (zoom or 0)
|
||||
|
||||
xy = {"_x": pan_val, "_y": tilt_val}
|
||||
z = {"_x": zoom_val}
|
||||
|
||||
try:
|
||||
self._ptz_service.ContinuousMove(req)
|
||||
if type_val == TYPE_ABSOLUTE:
|
||||
req = {"Position": {"PanTilt": xy, "Zoom": z}}
|
||||
self._ptz_service.AbsoluteMove(req)
|
||||
elif type_val == TYPE_RELATIVE:
|
||||
req = {"Position": {"Translation": xy, "Zoom": z}}
|
||||
self._ptz_service.RelativeMove(req)
|
||||
else:
|
||||
req = {"Velocity": {"PanTilt": xy, "Zoom": z}}
|
||||
self._ptz_service.ContinuousMove(req)
|
||||
except exceptions.ONVIFError as err:
|
||||
if "Bad Request" in err.reason:
|
||||
self._ptz_service = None
|
||||
_LOGGER.debug("Camera '%s' doesn't support PTZ.",
|
||||
self._name)
|
||||
_LOGGER.debug("Camera '%s' doesn't support PTZ of type '%s.",
|
||||
self._name, type_)
|
||||
else:
|
||||
_LOGGER.debug("Camera '%s' doesn't support PTZ.", self._name)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue