hass-core/homeassistant/components/zoneminder.py
tobygray 24b7fd3694 zoneminder: fix incorrect use of logging.exception. (#7675)
Prior to this change the zoneminder component was attempting to
use logging.exception outside of exception handling code. This
would lead to the traceback module throwing an exception when
trying to work out the traceback for the exception.

This fixes the issue by changing the exception call into a
plain error logging call.
2017-05-21 11:11:33 +02:00

130 lines
3.5 KiB
Python
Executable file

"""
Support for ZoneMinder.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/zoneminder/
"""
import logging
from urllib.parse import urljoin
import requests
import voluptuous as vol
from homeassistant.const import (
CONF_PATH, CONF_HOST, CONF_SSL, CONF_PASSWORD, CONF_USERNAME)
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'
LOGIN_RETRIES = 2
ZM = {}
CONFIG_SCHEMA = vol.Schema({
DOMAIN: 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
})
}, extra=vol.ALLOW_EXTRA)
def setup(hass, config):
"""Set up the ZoneMinder component."""
global ZM
ZM = {}
conf = config[DOMAIN]
if conf[CONF_SSL]:
schema = 'https'
else:
schema = 'http'
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()
# pylint: disable=no-member
def login():
"""Login to the ZoneMinder API."""
_LOGGER.debug("Attempting to login to ZoneMinder")
login_post = {'view': 'console', 'action': 'login'}
if ZM['username']:
login_post['username'] = ZM['username']
if ZM['password']:
login_post['password'] = ZM['password']
req = requests.post(ZM['url'] + '/index.php', data=login_post)
ZM['cookies'] = req.cookies
# Login calls returns a 200 response on both failure and success.
# The only way to tell if you logged in correctly is to issue an api call.
req = requests.get(
ZM['url'] + 'api/host/getVersion.json', cookies=ZM['cookies'],
timeout=DEFAULT_TIMEOUT)
if not req.ok:
_LOGGER.error("Connection error logging into ZoneMinder")
return False
return True
def _zm_request(method, api_url, data=None):
"""Perform a Zoneminder request."""
# Since the API uses sessions that expire, sometimes we need to re-auth
# if the call fails.
for _ in range(LOGIN_RETRIES):
req = requests.request(
method, urljoin(ZM['url'], api_url), data=data,
cookies=ZM['cookies'], timeout=DEFAULT_TIMEOUT)
if not req.ok:
login()
else:
break
else:
_LOGGER.error("Unable to get API response from ZoneMinder")
try:
return req.json()
except ValueError:
_LOGGER.exception('JSON decode exception caught while attempting to '
'decode "%s"', req.text)
# pylint: disable=no-member
def get_state(api_url):
"""Get a state from the ZoneMinder API service."""
return _zm_request('get', api_url)
# pylint: disable=no-member
def change_state(api_url, post_data):
"""Update a state using the Zoneminder API."""
return _zm_request('post', api_url, data=post_data)