diff --git a/custom_components/camera/shinobi.py b/custom_components/camera/shinobi.py index 429da5c..951292c 100644 --- a/custom_components/camera/shinobi.py +++ b/custom_components/camera/shinobi.py @@ -5,8 +5,8 @@ import homeassistant.loader as loader import homeassistant.helpers.config_validation as cv from homeassistant.const import (CONF_NAME, CONF_WHITELIST, CONF_BLACKLIST) -from homeassistant.components.camera.mjpeg import ( - CONF_MJPEG_URL, CONF_STILL_IMAGE_URL, MjpegCamera) +from homeassistant.components.camera import PLATFORM_SCHEMA +from homeassistant.components.camera.mjpeg import (CONF_MJPEG_URL, CONF_STILL_IMAGE_URL, MjpegCamera) _LOGGER = logging.getLogger(__name__) @@ -15,12 +15,11 @@ DOMAIN = 'shinobi' shinobi = loader.get_component('shinobi') -CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Schema({ - vol.Optional(CONF_WHITELIST): cv.ensure_list, - vol.Optional(CONF_BLACKLIST): cv.ensure_list - }) -}, extra=vol.ALLOW_EXTRA) +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_WHITELIST, default=[]): cv.ensure_list, + vol.Optional(CONF_BLACKLIST, default=[]): cv.ensure_list +}) + @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): @@ -32,13 +31,13 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): filtered_monitors = [] - whitelist = config.get(CONF_WHITELIST, []) - blacklist = config.get(CONF_BLACKLIST, []) + whitelist = config.get(CONF_WHITELIST) + blacklist = config.get(CONF_BLACKLIST) - if whitelist and len(whitelist) > 0: + if len(whitelist) > 0: _LOGGER.debug('Applying whitelist: ' + str(whitelist)) filtered_monitors = [m for m in all_monitors if m['name'] in whitelist] - elif blacklist and len(blacklist) > 0: + elif len(blacklist) > 0: _LOGGER.debug('Applying blacklist: ' + str(blacklist)) filtered_monitors = [m for m in all_monitors if m['name'] not in blacklist] else: @@ -88,7 +87,7 @@ class ShinobiCamera(MjpegCamera): _LOGGER.warning('Could not get status for monitor {}'.format(self._monitor_id)) return _LOGGER.debug('Monitor {} is in status {}'.format(self._monitor_id, status_response['mode'])) - self._is_recording = status_response.get('status') == shinobi.SHINOBI_CAM_RECORDING + self._is_recording = status_response.get('status') == shinobi.SHINOBI_CAM_STATE['RECORDING'] @property def is_recording(self): diff --git a/custom_components/shinobi.py b/custom_components/shinobi.py index 4eae23c..005c17f 100644 --- a/custom_components/shinobi.py +++ b/custom_components/shinobi.py @@ -1,30 +1,31 @@ import asyncio import logging import requests -import json import voluptuous as vol import homeassistant.helpers.config_validation as cv -from homeassistant.const import ( - CONF_HOST, CONF_API_KEY, CONF_SSL) +from homeassistant.const import (CONF_HOST, CONF_API_KEY, CONF_SSL) _LOGGER = logging.getLogger(__name__) DOMAIN = 'shinobi' -DEFAULT_TIMEOUT = 10 DEFAULT_SSL = False +DEFAULT_TIMEOUT = 10 -SHINOBI_CAM_DISABLED = 'stop' -SHINOBI_CAM_WATCHING = 'start' -SHINOBI_CAM_RECORDING = 'record' +SHINOBI = {} + +SHINOBI_CAM_STATE = { + 'DISABLED': 'stop', + 'RECORDING': 'record', + 'WATCHING': 'start' +} CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Required(CONF_HOST): cv.string, vol.Required(CONF_API_KEY): cv.string, vol.Required('group_key'): cv.string, - vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean, - vol.Optional('monitors', default=[]): cv.ensure_list + vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean }) }, extra=vol.ALLOW_EXTRA) @@ -33,44 +34,44 @@ CONFIG_SCHEMA = vol.Schema({ def async_setup(hass, config): global SHINOBI - SHINOBI = {} conf = config[DOMAIN] - if conf[CONF_SSL]: + + if conf.get(CONF_SSL): schema = 'https' else: schema = 'http' - - server_origin = '{}://{}'.format(schema, conf[CONF_HOST]) - + + server_origin = '{}://{}'.format(schema, conf.get(CONF_HOST)) + SHINOBI['server_origin'] = server_origin - SHINOBI['api_key'] = conf.get(CONF_API_KEY, None) - SHINOBI['group_key'] = conf.get('group_key', None) - SHINOBI['monitors'] = conf.get('monitors') + SHINOBI['api_key'] = conf.get(CONF_API_KEY) + SHINOBI['group_key'] = conf.get('group_key') - hass.data[DOMAIN] = SHINOBI - - # unfortunately, the api does not return error codes. The only way to check if the credentials are working is to check the response of an (arbitrary) request (e.g. get all monitors) + # Unfortunately, the api does not return error codes. The only way to + # check if the credentials are working is to check the response of an + # (arbitrary) request (e.g. to get all monitors). try: check_creds_response = get_all_started_monitors() except: return False - # expected response contains a list with activated monitors (or an empty list) + # Expected response contains a list with activated monitors (or an empty + # list if no monitors activated). if isinstance(check_creds_response, list): return True else: - # response payload contains ok: false if authentication has not been successful + # Response payload contains {"ok": "false",…} if authentication has not been successful. if not check_creds_response.ok: _LOGGER.error('Wrong api_key or non existing group_key provided') else: - _LOGGER.error('Unknown error occured while retrieving monitors') + _LOGGER.error('Unknown error occurred while retrieving monitors') return False def _shinobi_request(api_path, method='get', data=None): - """Perform a Shinobi request.""" + """Perform a generic request to the Shinobi API.""" api_base = SHINOBI['server_origin'] + '/' + SHINOBI['api_key'] @@ -81,7 +82,7 @@ def _shinobi_request(api_path, method='get', data=None): response = req.json() except ValueError: _LOGGER.exception('JSON decode exception caught while attempting to ' - 'decode "{}"', req.text) + 'decode "{}"'.format(req.text)) return response @@ -91,14 +92,11 @@ def get_all_started_monitors(): get_monitors_path = '/smonitor/' + SHINOBI['group_key'] - response = _shinobi_request(get_monitors_path) + monitors = _shinobi_request(get_monitors_path) - # TODO is it necessary to save monitors globally in SHINOBI? - SHINOBI['monitors'] = response + _LOGGER.debug('Shinobi returned {} monitors: {}'.format(str(len(monitors)), str([monitor['name'] for monitor in monitors]))) - _LOGGER.debug('Shinobi returned {} monitors: {}'.format(str(len(SHINOBI['monitors'])), str([monitor['name'] for monitor in SHINOBI['monitors']]))) - - return SHINOBI['monitors'] + return monitors def get_monitor_state(monitor_id): @@ -108,9 +106,9 @@ def get_monitor_state(monitor_id): def set_monitor_state(monitor_id, mode): - """Get the state of a monitor.""" - if not (mode == SHINOBI_CAM_DISABLED or mode == SHINOBI_CAM_WATCHING or mode == SHINOBI_CAM_RECORDING): - raise ValueError('monitor state must be either {}, {} or {}'.format(SHINOBI_CAM_DISABLED, SHINOBI_CAM_WATCHING, SHINOBI_CAM_RECORDING)) + """Set the state of a monitor.""" + if not (mode in SHINOBI_CAM_STATE.values()): + raise ValueError('Monitor state must be one of the following values {}.'.format(SHINOBI_CAM_STATE.values())) api_path = '/monitor/{}/{}'.format(SHINOBI['group_key'], monitor_id) return _shinobi_request(api_path) @@ -121,5 +119,5 @@ def monitor_stream_url(monitor_id): def monitor_still_url(monitor_id): - """Get the url of still jpg images. Snapshots must be enabled in cam settings, see https://shinobi.video/docs/api#content-get-streams""" + """Get the url of still jpg images. Snapshots must be enabled in cam settings, see https://shinobi.video/docs/api#content-get-streams.""" return SHINOBI['server_origin'] + '/' + SHINOBI['api_key'] + '/jpeg/' + SHINOBI['group_key'] + '/' + monitor_id + '/s.jpg'