Skip to content

Commit

Permalink
move service to register_entity_service
Browse files Browse the repository at this point in the history
  • Loading branch information
hunterjm committed Apr 24, 2020
1 parent 7f2882d commit f8a8215
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 116 deletions.
63 changes: 1 addition & 62 deletions homeassistant/components/onvif/__init__.py
Expand Up @@ -5,87 +5,26 @@

from homeassistant.components.ffmpeg import CONF_EXTRA_ARGUMENTS
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import ATTR_ENTITY_ID, CONF_HOST
from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_per_platform
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.service import async_extract_entity_ids

from .const import (
ABSOLUTE_MOVE,
ATTR_CONTINUOUS_DURATION,
ATTR_DISTANCE,
ATTR_MOVE_MODE,
ATTR_PAN,
ATTR_SPEED,
ATTR_TILT,
ATTR_ZOOM,
CONF_PROFILE,
CONF_RTSP_TRANSPORT,
CONTINUOUS_MOVE,
DEFAULT_ARGUMENTS,
DEFAULT_PROFILE,
DIR_DOWN,
DIR_LEFT,
DIR_RIGHT,
DIR_UP,
DOMAIN,
ENTITIES,
RELATIVE_MOVE,
RTSP_TRANS_PROTOCOLS,
SERVICE_PTZ,
ZOOM_IN,
ZOOM_OUT,
)

CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({})}, extra=vol.ALLOW_EXTRA)

PLATFORMS = ["camera"]

SERVICE_PTZ_SCHEMA = vol.Schema(
{
ATTR_ENTITY_ID: cv.entity_ids,
vol.Optional(ATTR_PAN): vol.In([DIR_LEFT, DIR_RIGHT]),
vol.Optional(ATTR_TILT): vol.In([DIR_UP, DIR_DOWN]),
vol.Optional(ATTR_ZOOM): vol.In([ZOOM_OUT, ZOOM_IN]),
ATTR_MOVE_MODE: vol.In([CONTINUOUS_MOVE, RELATIVE_MOVE, ABSOLUTE_MOVE]),
vol.Optional(ATTR_CONTINUOUS_DURATION, default=0.5): cv.small_float,
vol.Optional(ATTR_DISTANCE, default=0.1): cv.small_float,
vol.Optional(ATTR_SPEED, default=0.5): cv.small_float,
}
)


async def async_setup(hass: HomeAssistant, config: dict):
"""Set up the ONVIF component."""
# Create PTZ service
async def async_handle_ptz(service):
"""Handle PTZ service call."""
pan = service.data.get(ATTR_PAN)
tilt = service.data.get(ATTR_TILT)
zoom = service.data.get(ATTR_ZOOM)
distance = service.data[ATTR_DISTANCE]
speed = service.data[ATTR_SPEED]
move_mode = service.data.get(ATTR_MOVE_MODE)
continuous_duration = service.data[ATTR_CONTINUOUS_DURATION]
all_cameras = hass.data[DOMAIN][ENTITIES]
entity_ids = await async_extract_entity_ids(hass, service)
target_cameras = []
if not entity_ids:
target_cameras = all_cameras
else:
target_cameras = [
camera for camera in all_cameras if camera.entity_id in entity_ids
]
for camera in target_cameras:
await camera.async_perform_ptz(
pan, tilt, zoom, distance, speed, move_mode, continuous_duration
)

hass.services.async_register(
DOMAIN, SERVICE_PTZ, async_handle_ptz, schema=SERVICE_PTZ_SCHEMA
)

# Import from yaml
configs = {}
for p_type, p_config in config_per_platform(config, "camera"):
Expand Down
147 changes: 93 additions & 54 deletions homeassistant/components/onvif/camera.py
Expand Up @@ -11,6 +11,7 @@
from onvif import ONVIFCamera, exceptions
import requests
from requests.auth import HTTPDigestAuth
import voluptuous as vol
from zeep.asyncio import AsyncTransport
from zeep.exceptions import Fault

Expand All @@ -24,6 +25,7 @@
CONF_USERNAME,
)
from homeassistant.exceptions import PlatformNotReady
from homeassistant.helpers import config_validation as cv, entity_platform
from homeassistant.helpers.aiohttp_client import (
async_aiohttp_proxy_stream,
async_get_clientsession,
Expand All @@ -32,21 +34,54 @@

from .const import (
ABSOLUTE_MOVE,
ATTR_CONTINUOUS_DURATION,
ATTR_DISTANCE,
ATTR_MOVE_MODE,
ATTR_PAN,
ATTR_SPEED,
ATTR_TILT,
ATTR_ZOOM,
CONF_PROFILE,
CONF_RTSP_TRANSPORT,
CONTINUOUS_MOVE,
DIR_DOWN,
DIR_LEFT,
DIR_RIGHT,
DIR_UP,
DOMAIN,
ENTITIES,
LOGGER,
PAN_FACTOR,
RELATIVE_MOVE,
SERVICE_PTZ,
TILT_FACTOR,
ZOOM_FACTOR,
ZOOM_IN,
ZOOM_OUT,
)


async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Axis camera video stream."""
"""Set up the ONVIF camera video stream."""
platform = entity_platform.current_platform.get()

# Create PTZ service
platform.async_register_entity_service(
SERVICE_PTZ,
{
vol.Optional(ATTR_PAN): vol.In([DIR_LEFT, DIR_RIGHT]),
vol.Optional(ATTR_TILT): vol.In([DIR_UP, DIR_DOWN]),
vol.Optional(ATTR_ZOOM): vol.In([ZOOM_OUT, ZOOM_IN]),
vol.Optional(ATTR_DISTANCE, default=0.1): cv.small_float,
vol.Optional(ATTR_SPEED, default=0.5): cv.small_float,
vol.Optional(ATTR_MOVE_MODE, default=CONTINUOUS_MOVE): vol.In(
[CONTINUOUS_MOVE, RELATIVE_MOVE, ABSOLUTE_MOVE]
),
vol.Optional(ATTR_CONTINUOUS_DURATION, default=0.5): cv.small_float,
},
"async_perform_ptz",
)

base_config = {
CONF_NAME: config_entry.data[CONF_NAME],
CONF_HOST: config_entry.data[CONF_HOST],
Expand Down Expand Up @@ -332,66 +367,70 @@ def setup_ptz(self):
LOGGER.debug("Completed set up of the ONVIF camera component")

async def async_perform_ptz(
self, pan, tilt, zoom, distance, speed, move_mode, continuous_duration
self,
distance,
speed,
move_mode,
continuous_duration,
pan=None,
tilt=None,
zoom=None,
):
"""Perform a PTZ action on the camera."""
if self._ptz_service is None:
LOGGER.warning("PTZ actions are not supported on camera '%s'", self._name)
return

if self._ptz_service:
pan_val = distance * PAN_FACTOR.get(pan, 0)
tilt_val = distance * TILT_FACTOR.get(tilt, 0)
zoom_val = distance * ZOOM_FACTOR.get(zoom, 0)
speed_val = speed
LOGGER.debug(
"Calling %s PTZ | Pan = %4.2f | Tilt = %4.2f | Zoom = %4.2f | Speed = %4.2f",
move_mode,
pan_val,
tilt_val,
zoom_val,
speed_val,
)
try:
req = self._ptz_service.create_type(move_mode)
pan_val = distance * PAN_FACTOR.get(pan, 0)
tilt_val = distance * TILT_FACTOR.get(tilt, 0)
zoom_val = distance * ZOOM_FACTOR.get(zoom, 0)
speed_val = speed
LOGGER.debug(
"Calling %s PTZ | Pan = %4.2f | Tilt = %4.2f | Zoom = %4.2f | Speed = %4.2f",
move_mode,
pan_val,
tilt_val,
zoom_val,
speed_val,
)
try:
req = self._ptz_service.create_type(move_mode)
req.ProfileToken = self._profile_token
if move_mode == CONTINUOUS_MOVE:
req.Velocity = {
"PanTilt": {"x": pan_val, "y": tilt_val},
"Zoom": {"x": zoom_val},
}

await self._ptz_service.ContinuousMove(req)
await asyncio.sleep(continuous_duration)
req = self._ptz_service.create_type("Stop")
req.ProfileToken = self._profile_token
if move_mode == CONTINUOUS_MOVE:
req.Velocity = {
"PanTilt": {"x": pan_val, "y": tilt_val},
"Zoom": {"x": zoom_val},
}

await self._ptz_service.ContinuousMove(req)
await asyncio.sleep(continuous_duration)
req = self._ptz_service.create_type("Stop")
req.ProfileToken = self._profile_token
await self._ptz_service.Stop({"ProfileToken": req.ProfileToken})
elif move_mode == RELATIVE_MOVE:
req.Translation = {
"PanTilt": {"x": pan_val, "y": tilt_val},
"Zoom": {"x": zoom_val},
}
req.Speed = {
"PanTilt": {"x": speed_val, "y": speed_val},
"Zoom": {"x": speed_val},
}
await self._ptz_service.RelativeMove(req)
elif move_mode == ABSOLUTE_MOVE:
req.Position = {
"PanTilt": {"x": pan_val, "y": tilt_val},
"Zoom": {"x": zoom_val},
}
req.Speed = {
"PanTilt": {"x": speed_val, "y": speed_val},
"Zoom": {"x": speed_val},
}
await self._ptz_service.AbsoluteMove(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)
else:
LOGGER.debug("Camera '%s' doesn't support PTZ.", self._name)
await self._ptz_service.Stop({"ProfileToken": req.ProfileToken})
elif move_mode == RELATIVE_MOVE:
req.Translation = {
"PanTilt": {"x": pan_val, "y": tilt_val},
"Zoom": {"x": zoom_val},
}
req.Speed = {
"PanTilt": {"x": speed_val, "y": speed_val},
"Zoom": {"x": speed_val},
}
await self._ptz_service.RelativeMove(req)
elif move_mode == ABSOLUTE_MOVE:
req.Position = {
"PanTilt": {"x": pan_val, "y": tilt_val},
"Zoom": {"x": zoom_val},
}
req.Speed = {
"PanTilt": {"x": speed_val, "y": speed_val},
"Zoom": {"x": speed_val},
}
await self._ptz_service.AbsoluteMove(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)

async def async_added_to_hass(self):
"""Handle entity addition to hass."""
Expand Down

0 comments on commit f8a8215

Please sign in to comment.