From 2b9fb73032cc3fa48302e4619dcb3323624de472 Mon Sep 17 00:00:00 2001 From: Matt N Date: Mon, 20 Feb 2017 22:17:11 -0800 Subject: [PATCH] zoneminder: Add camera mjpeg stream support (#6098) --- homeassistant/components/camera/zoneminder.py | 78 +++++++++++++++++++ homeassistant/components/zoneminder.py | 11 ++- 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/camera/zoneminder.py diff --git a/homeassistant/components/camera/zoneminder.py b/homeassistant/components/camera/zoneminder.py new file mode 100644 index 00000000000..12615262b26 --- /dev/null +++ b/homeassistant/components/camera/zoneminder.py @@ -0,0 +1,78 @@ +""" +Support for ZoneMinder camera streaming. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/camera.zoneminder/ +""" +import asyncio +import logging +from urllib.parse import urljoin, urlencode + +from homeassistant.const import CONF_NAME +from homeassistant.components.camera.mjpeg import ( + CONF_MJPEG_URL, CONF_STILL_IMAGE_URL, MjpegCamera) + +import homeassistant.components.zoneminder as zoneminder + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['zoneminder'] +DOMAIN = 'zoneminder' + + +def _get_image_url(hass, monitor, mode): + zm_data = hass.data[DOMAIN] + query = urlencode({ + 'mode': mode, + 'buffer': monitor['StreamReplayBuffer'], + 'monitor': monitor['Id'], + }) + url = '{zms_url}?{query}'.format( + zms_url=urljoin(zm_data['server_origin'], zm_data['path_zms']), + query=query, + ) + _LOGGER.debug('Monitor %s %s URL (without auth): %s', + monitor['Id'], mode, url) + + if not zm_data['username']: + return url + + url += '&user={:s}'.format(zm_data['username']) + + if not zm_data['password']: + return url + + return url + '&pass={:s}'.format(zm_data['password']) + + +@asyncio.coroutine +# pylint: disable=unused-argument +def async_setup_platform(hass, config, async_add_devices, discovery_info=None): + """Setup ZoneMinder cameras.""" + cameras = [] + monitors = zoneminder.get_state('api/monitors.json') + if not monitors: + _LOGGER.warning('Could not fetch monitors from ZoneMinder') + return + + for i in monitors['monitors']: + monitor = i['Monitor'] + + if monitor['Function'] == 'None': + _LOGGER.info('Skipping camera %s', monitor['Id']) + continue + + _LOGGER.info('Initializing camera %s', monitor['Id']) + + device_info = { + CONF_NAME: monitor['Name'], + CONF_MJPEG_URL: _get_image_url(hass, monitor, 'jpeg'), + CONF_STILL_IMAGE_URL: _get_image_url(hass, monitor, 'single') + } + cameras.append(MjpegCamera(hass, device_info)) + + if not cameras: + _LOGGER.warning('No active cameras found') + return + + yield from async_add_devices(cameras) diff --git a/homeassistant/components/zoneminder.py b/homeassistant/components/zoneminder.py index 0fbe807fb2a..8870b4713e0 100644 --- a/homeassistant/components/zoneminder.py +++ b/homeassistant/components/zoneminder.py @@ -16,7 +16,9 @@ import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) +CONF_PATH_ZMS = 'path_zms' DEFAULT_PATH = '/zm/' +DEFAULT_PATH_ZMS = '/zm/cgi-bin/nph-zms' DEFAULT_SSL = False DEFAULT_TIMEOUT = 10 DOMAIN = 'zoneminder' @@ -30,6 +32,8 @@ CONFIG_SCHEMA = vol.Schema({ vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean, vol.Optional(CONF_PATH, default=DEFAULT_PATH): cv.string, + # This should match PATH_ZMS in ZoneMinder settings. + vol.Optional(CONF_PATH_ZMS, default=DEFAULT_PATH_ZMS): cv.string, vol.Optional(CONF_USERNAME): cv.string, vol.Optional(CONF_PASSWORD): cv.string }) @@ -47,13 +51,18 @@ def setup(hass, config): else: schema = 'http' - url = urljoin('{}://{}'.format(schema, conf[CONF_HOST]), conf[CONF_PATH]) + server_origin = '{}://{}'.format(schema, conf[CONF_HOST]) + url = urljoin(server_origin, conf[CONF_PATH]) username = conf.get(CONF_USERNAME, None) password = conf.get(CONF_PASSWORD, None) + ZM['server_origin'] = server_origin ZM['url'] = url ZM['username'] = username ZM['password'] = password + ZM['path_zms'] = conf.get(CONF_PATH_ZMS) + + hass.data[DOMAIN] = ZM return login()