Auth and headers support for REST sensor (#3592)

* Add auth and header support

* Update header part
This commit is contained in:
Fabian Affolter 2016-10-04 10:07:17 +02:00 committed by Paulus Schoutsen
parent 74b0e4cb45
commit a072047d9d
4 changed files with 56 additions and 12 deletions

View file

@ -5,15 +5,19 @@ For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.rest/ https://home-assistant.io/components/binary_sensor.rest/
""" """
import logging import logging
import json
import voluptuous as vol import voluptuous as vol
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
BinarySensorDevice, SENSOR_CLASSES_SCHEMA, PLATFORM_SCHEMA) BinarySensorDevice, SENSOR_CLASSES_SCHEMA, PLATFORM_SCHEMA)
from homeassistant.components.sensor.rest import RestData from homeassistant.components.sensor.rest import RestData
from homeassistant.const import ( from homeassistant.const import (
CONF_PAYLOAD, CONF_NAME, CONF_VALUE_TEMPLATE, CONF_METHOD, CONF_RESOURCE, CONF_PAYLOAD, CONF_NAME, CONF_VALUE_TEMPLATE, CONF_METHOD, CONF_RESOURCE,
CONF_SENSOR_CLASS, CONF_VERIFY_SSL) CONF_SENSOR_CLASS, CONF_VERIFY_SSL, CONF_USERNAME, CONF_PASSWORD,
CONF_HEADERS, CONF_AUTHENTICATION, HTTP_BASIC_AUTHENTICATION,
HTTP_DIGEST_AUTHENTICATION)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -24,16 +28,21 @@ DEFAULT_VERIFY_SSL = True
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_RESOURCE): cv.url, vol.Required(CONF_RESOURCE): cv.url,
vol.Optional(CONF_AUTHENTICATION):
vol.In([HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION]),
vol.Optional(CONF_HEADERS): cv.string,
vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(['POST', 'GET']), vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(['POST', 'GET']),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string,
vol.Optional(CONF_PAYLOAD): cv.string, vol.Optional(CONF_PAYLOAD): cv.string,
vol.Optional(CONF_SENSOR_CLASS): SENSOR_CLASSES_SCHEMA, vol.Optional(CONF_SENSOR_CLASS): SENSOR_CLASSES_SCHEMA,
vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template, vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean, vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
}) })
# pylint: disable=unused-variable # pylint: disable=unused-variable, too-many-locals
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the REST binary sensor.""" """Setup the REST binary sensor."""
name = config.get(CONF_NAME) name = config.get(CONF_NAME)
@ -41,11 +50,23 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
method = config.get(CONF_METHOD) method = config.get(CONF_METHOD)
payload = config.get(CONF_PAYLOAD) payload = config.get(CONF_PAYLOAD)
verify_ssl = config.get(CONF_VERIFY_SSL) verify_ssl = config.get(CONF_VERIFY_SSL)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
headers = json.loads(config.get(CONF_HEADERS, '{}'))
sensor_class = config.get(CONF_SENSOR_CLASS) sensor_class = config.get(CONF_SENSOR_CLASS)
value_template = config.get(CONF_VALUE_TEMPLATE) value_template = config.get(CONF_VALUE_TEMPLATE)
if value_template is not None: if value_template is not None:
value_template.hass = hass value_template.hass = hass
rest = RestData(method, resource, payload, verify_ssl)
if username and password:
if config.get(CONF_AUTHENTICATION) == HTTP_DIGEST_AUTHENTICATION:
auth = HTTPDigestAuth(username, password)
else:
auth = HTTPBasicAuth(username, password)
else:
auth = None
rest = RestData(method, resource, auth, headers, payload, verify_ssl)
rest.update() rest.update()
if rest.data is None: if rest.data is None:

View file

@ -43,6 +43,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
host = config.get(CONF_HOST) host = config.get(CONF_HOST)
method = 'GET' method = 'GET'
payload = None payload = None
auth = None
headers = None
verify_ssl = config.get(CONF_VERIFY_SSL) verify_ssl = config.get(CONF_VERIFY_SSL)
use_ssl = config.get(CONF_SSL) use_ssl = config.get(CONF_SSL)
@ -53,7 +55,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
resource = "{}{}{}".format(uri_scheme, host, _ENDPOINT) resource = "{}{}{}".format(uri_scheme, host, _ENDPOINT)
rest = RestData(method, resource, payload, verify_ssl) rest = RestData(method, resource, auth, headers, payload, verify_ssl)
rest.update() rest.update()
if rest.data is None: if rest.data is None:

View file

@ -1,5 +1,5 @@
""" """
Support for REST API sensors. Support for RESTful API sensors.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.rest/ https://home-assistant.io/components/sensor.rest/
@ -8,11 +8,14 @@ import logging
import voluptuous as vol import voluptuous as vol
import requests import requests
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import ( from homeassistant.const import (
CONF_PAYLOAD, CONF_NAME, CONF_VALUE_TEMPLATE, CONF_METHOD, CONF_RESOURCE, CONF_PAYLOAD, CONF_NAME, CONF_VALUE_TEMPLATE, CONF_METHOD, CONF_RESOURCE,
CONF_UNIT_OF_MEASUREMENT, STATE_UNKNOWN, CONF_VERIFY_SSL) CONF_UNIT_OF_MEASUREMENT, STATE_UNKNOWN, CONF_VERIFY_SSL, CONF_USERNAME,
CONF_PASSWORD, CONF_AUTHENTICATION, HTTP_BASIC_AUTHENTICATION,
HTTP_DIGEST_AUTHENTICATION, CONF_HEADERS)
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
@ -24,16 +27,21 @@ DEFAULT_VERIFY_SSL = True
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_RESOURCE): cv.url, vol.Required(CONF_RESOURCE): cv.url,
vol.Optional(CONF_AUTHENTICATION):
vol.In([HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION]),
vol.Optional(CONF_HEADERS): {cv.string: cv.string},
vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(['POST', 'GET']), vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(['POST', 'GET']),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string,
vol.Optional(CONF_PAYLOAD): cv.string, vol.Optional(CONF_PAYLOAD): cv.string,
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template, vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean, vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
}) })
# pylint: disable=unused-variable # pylint: disable=unused-variable, too-many-locals
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the RESTful sensor.""" """Setup the RESTful sensor."""
name = config.get(CONF_NAME) name = config.get(CONF_NAME)
@ -41,11 +49,22 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
method = config.get(CONF_METHOD) method = config.get(CONF_METHOD)
payload = config.get(CONF_PAYLOAD) payload = config.get(CONF_PAYLOAD)
verify_ssl = config.get(CONF_VERIFY_SSL) verify_ssl = config.get(CONF_VERIFY_SSL)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
headers = config.get(CONF_HEADERS)
unit = config.get(CONF_UNIT_OF_MEASUREMENT) unit = config.get(CONF_UNIT_OF_MEASUREMENT)
value_template = config.get(CONF_VALUE_TEMPLATE) value_template = config.get(CONF_VALUE_TEMPLATE)
if value_template is not None: if value_template is not None:
value_template.hass = hass value_template.hass = hass
rest = RestData(method, resource, payload, verify_ssl)
if username and password:
if config.get(CONF_AUTHENTICATION) == HTTP_DIGEST_AUTHENTICATION:
auth = HTTPDigestAuth(username, password)
else:
auth = HTTPBasicAuth(username, password)
else:
auth = None
rest = RestData(method, resource, auth, headers, payload, verify_ssl)
rest.update() rest.update()
if rest.data is None: if rest.data is None:
@ -102,9 +121,10 @@ class RestSensor(Entity):
class RestData(object): class RestData(object):
"""Class for handling the data retrieval.""" """Class for handling the data retrieval."""
def __init__(self, method, resource, data, verify_ssl): def __init__(self, method, resource, auth, headers, data, verify_ssl):
"""Initialize the data object.""" """Initialize the data object."""
self._request = requests.Request(method, resource, data=data).prepare() self._request = requests.Request(
method, resource, headers=headers, auth=auth, data=data).prepare()
self._verify_ssl = verify_ssl self._verify_ssl = verify_ssl
self.data = None self.data = None
@ -112,8 +132,8 @@ class RestData(object):
"""Get the latest data from REST service with GET method.""" """Get the latest data from REST service with GET method."""
try: try:
with requests.Session() as sess: with requests.Session() as sess:
response = sess.send(self._request, timeout=10, response = sess.send(
verify=self._verify_ssl) self._request, timeout=10, verify=self._verify_ssl)
self.data = response.text self.data = response.text
except requests.exceptions.RequestException: except requests.exceptions.RequestException:

View file

@ -87,6 +87,7 @@ CONF_EVENT = 'event'
CONF_FILE_PATH = 'file_path' CONF_FILE_PATH = 'file_path'
CONF_FILENAME = 'filename' CONF_FILENAME = 'filename'
CONF_FRIENDLY_NAME = 'friendly_name' CONF_FRIENDLY_NAME = 'friendly_name'
CONF_HEADERS = 'headers'
CONF_HOST = 'host' CONF_HOST = 'host'
CONF_HOSTS = 'hosts' CONF_HOSTS = 'hosts'
CONF_ICON = 'icon' CONF_ICON = 'icon'