2019-04-03 15:40:03 +00:00
|
|
|
"""Support for RESTful API sensors."""
|
Unpacking RESTful sensor JSON results into attributes. (#10753)
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* sensor.envirophat: add missing requirement (#7451)
Adding requirements that is not explicitly pulled in by the library
that manages the Enviro pHAT.
* PyPI Openzwave (#7415)
* Remove default zwave config path
PYOZW now has much more comprehensive default handling for the config
path (in src-lib/libopenzwave/libopenzwave.pyx:getConfig()). It looks in
the same place we were looking, plus _many_ more. It will certainly do a
much better job of finding the config files than we will (and will be
updated as the library is changed, so we don't end up chasing it). The
getConfig() method has been there for a while, but was subsntially
improved recently.
This change simply leaves the config_path as None if it is not
specified, which will trigger the default handling in PYOZW.
* Install python-openzwave from PyPI
As of version 0.4, python-openzwave supports installation from PyPI,
which means we can use our 'normal' dependency management tooling to
install it. Yay.
This uses the default 'embed' build (which goes and downloads
statically sources to avoid having to compile anything locally). Check
out the python-openzwave readme for more details.
* Add python-openzwave deps to .travis.yml
Python OpenZwave require the libudev headers to build. This adds the
libudev-dev package to Travis runs via the 'apt' addon for Travis.
Thanks to @MartinHjelmare for this fix.
* Update docker build for PyPI openzwave
Now that PYOZW can be install from PyPI, the docker image build process
can be simplified to remove the explicit compilation of PYOZW.
* Add datadog component (#7158)
* Add datadog component
* Improve test_invalid_config datadog test
* Use assert_setup_component for test setup
* Fix object type for default KNX port
#7429 describes a TypeError that is raised if the port is omitted in the config for the KNX component (integer is required (got type str)). This commit changes the default port from a string to an integer. I expect this will resolve that issue...
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Fixed breaks cause by manual upstream merge.
* Added one extra blank line to make PyLint happy.
* Switched json_attributes to be a list of keys rather than a boolean.
The value of json_attributes can now be either a comma sepaated list
of key names or a YAML list of key names. Only matching keys in a
retuned JSON dictionary will be mapped to sensor attributes.
Updated test cases to handle json_attributes being a list.
Also fixed two minor issues arrising from manual merge with 0.58 master.
* Added an explicit default value to the json_attributes config entry.
* Removed self.update() from __init__() body.
* Expended unit tests for error cases of json_attributes processing.
* Align quotes
2017-12-03 15:30:25 +00:00
|
|
|
import json
|
2019-12-09 11:09:49 +00:00
|
|
|
import logging
|
2020-02-16 05:10:23 +00:00
|
|
|
from xml.parsers.expat import ExpatError
|
2016-02-19 05:27:50 +00:00
|
|
|
|
2020-02-16 05:10:23 +00:00
|
|
|
from jsonpath import jsonpath
|
2015-09-22 23:15:16 +00:00
|
|
|
import requests
|
2020-03-04 16:32:38 +00:00
|
|
|
from requests import Session
|
2016-10-04 08:07:17 +00:00
|
|
|
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
|
2019-12-09 11:09:49 +00:00
|
|
|
import voluptuous as vol
|
2020-02-16 05:10:23 +00:00
|
|
|
import xmltodict
|
2015-09-13 20:41:16 +00:00
|
|
|
|
2019-12-09 11:09:49 +00:00
|
|
|
from homeassistant.components.sensor import DEVICE_CLASSES_SCHEMA, PLATFORM_SCHEMA
|
2016-08-20 23:28:45 +00:00
|
|
|
from homeassistant.const import (
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_AUTHENTICATION,
|
2019-12-09 11:09:49 +00:00
|
|
|
CONF_DEVICE_CLASS,
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_FORCE_UPDATE,
|
|
|
|
CONF_HEADERS,
|
|
|
|
CONF_METHOD,
|
2019-12-09 11:09:49 +00:00
|
|
|
CONF_NAME,
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_PASSWORD,
|
|
|
|
CONF_PAYLOAD,
|
|
|
|
CONF_RESOURCE,
|
2019-10-23 05:43:28 +00:00
|
|
|
CONF_RESOURCE_TEMPLATE,
|
2019-12-09 11:09:49 +00:00
|
|
|
CONF_TIMEOUT,
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_UNIT_OF_MEASUREMENT,
|
|
|
|
CONF_USERNAME,
|
|
|
|
CONF_VALUE_TEMPLATE,
|
|
|
|
CONF_VERIFY_SSL,
|
|
|
|
HTTP_BASIC_AUTHENTICATION,
|
|
|
|
HTTP_DIGEST_AUTHENTICATION,
|
|
|
|
)
|
2018-09-21 13:54:50 +00:00
|
|
|
from homeassistant.exceptions import PlatformNotReady
|
2016-08-20 23:28:45 +00:00
|
|
|
import homeassistant.helpers.config_validation as cv
|
2019-12-09 11:09:49 +00:00
|
|
|
from homeassistant.helpers.entity import Entity
|
2015-09-13 20:41:16 +00:00
|
|
|
|
2016-09-03 23:45:49 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
DEFAULT_METHOD = "GET"
|
|
|
|
DEFAULT_NAME = "REST Sensor"
|
2016-09-03 23:45:49 +00:00
|
|
|
DEFAULT_VERIFY_SSL = True
|
2017-12-09 07:18:45 +00:00
|
|
|
DEFAULT_FORCE_UPDATE = False
|
2019-02-26 18:23:46 +00:00
|
|
|
DEFAULT_TIMEOUT = 10
|
2016-08-20 23:28:45 +00:00
|
|
|
|
2020-02-16 05:10:23 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_JSON_ATTRS = "json_attributes"
|
2020-02-16 05:10:23 +00:00
|
|
|
CONF_JSON_ATTRS_PATH = "json_attributes_path"
|
2019-07-31 19:25:30 +00:00
|
|
|
METHODS = ["POST", "GET"]
|
|
|
|
|
|
|
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|
|
|
{
|
2019-10-23 05:43:28 +00:00
|
|
|
vol.Exclusive(CONF_RESOURCE, CONF_RESOURCE): cv.url,
|
|
|
|
vol.Exclusive(CONF_RESOURCE_TEMPLATE, CONF_RESOURCE): cv.template,
|
2019-07-31 19:25:30 +00:00
|
|
|
vol.Optional(CONF_AUTHENTICATION): vol.In(
|
|
|
|
[HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION]
|
|
|
|
),
|
|
|
|
vol.Optional(CONF_HEADERS): vol.Schema({cv.string: cv.string}),
|
|
|
|
vol.Optional(CONF_JSON_ATTRS, default=[]): cv.ensure_list_csv,
|
|
|
|
vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(METHODS),
|
|
|
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
|
|
vol.Optional(CONF_PASSWORD): cv.string,
|
|
|
|
vol.Optional(CONF_PAYLOAD): cv.string,
|
|
|
|
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
|
|
|
|
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
|
|
|
|
vol.Optional(CONF_USERNAME): cv.string,
|
2020-02-16 05:10:23 +00:00
|
|
|
vol.Optional(CONF_JSON_ATTRS_PATH): cv.string,
|
2019-07-31 19:25:30 +00:00
|
|
|
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
|
|
|
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
|
|
|
|
vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean,
|
|
|
|
vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
|
|
|
|
}
|
|
|
|
)
|
2016-08-20 23:28:45 +00:00
|
|
|
|
2019-10-23 05:43:28 +00:00
|
|
|
PLATFORM_SCHEMA = vol.All(
|
|
|
|
cv.has_at_least_one_key(CONF_RESOURCE, CONF_RESOURCE_TEMPLATE), PLATFORM_SCHEMA
|
|
|
|
)
|
|
|
|
|
2015-09-13 20:41:16 +00:00
|
|
|
|
2018-08-24 14:37:30 +00:00
|
|
|
def setup_platform(hass, config, add_entities, discovery_info=None):
|
2017-05-02 16:18:47 +00:00
|
|
|
"""Set up the RESTful sensor."""
|
2016-08-20 23:28:45 +00:00
|
|
|
name = config.get(CONF_NAME)
|
|
|
|
resource = config.get(CONF_RESOURCE)
|
2019-10-23 05:43:28 +00:00
|
|
|
resource_template = config.get(CONF_RESOURCE_TEMPLATE)
|
2016-08-20 23:28:45 +00:00
|
|
|
method = config.get(CONF_METHOD)
|
|
|
|
payload = config.get(CONF_PAYLOAD)
|
2016-09-03 23:45:49 +00:00
|
|
|
verify_ssl = config.get(CONF_VERIFY_SSL)
|
2016-10-04 08:07:17 +00:00
|
|
|
username = config.get(CONF_USERNAME)
|
|
|
|
password = config.get(CONF_PASSWORD)
|
|
|
|
headers = config.get(CONF_HEADERS)
|
2016-08-20 23:28:45 +00:00
|
|
|
unit = config.get(CONF_UNIT_OF_MEASUREMENT)
|
2019-01-16 18:03:53 +00:00
|
|
|
device_class = config.get(CONF_DEVICE_CLASS)
|
2016-08-20 23:28:45 +00:00
|
|
|
value_template = config.get(CONF_VALUE_TEMPLATE)
|
Unpacking RESTful sensor JSON results into attributes. (#10753)
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* sensor.envirophat: add missing requirement (#7451)
Adding requirements that is not explicitly pulled in by the library
that manages the Enviro pHAT.
* PyPI Openzwave (#7415)
* Remove default zwave config path
PYOZW now has much more comprehensive default handling for the config
path (in src-lib/libopenzwave/libopenzwave.pyx:getConfig()). It looks in
the same place we were looking, plus _many_ more. It will certainly do a
much better job of finding the config files than we will (and will be
updated as the library is changed, so we don't end up chasing it). The
getConfig() method has been there for a while, but was subsntially
improved recently.
This change simply leaves the config_path as None if it is not
specified, which will trigger the default handling in PYOZW.
* Install python-openzwave from PyPI
As of version 0.4, python-openzwave supports installation from PyPI,
which means we can use our 'normal' dependency management tooling to
install it. Yay.
This uses the default 'embed' build (which goes and downloads
statically sources to avoid having to compile anything locally). Check
out the python-openzwave readme for more details.
* Add python-openzwave deps to .travis.yml
Python OpenZwave require the libudev headers to build. This adds the
libudev-dev package to Travis runs via the 'apt' addon for Travis.
Thanks to @MartinHjelmare for this fix.
* Update docker build for PyPI openzwave
Now that PYOZW can be install from PyPI, the docker image build process
can be simplified to remove the explicit compilation of PYOZW.
* Add datadog component (#7158)
* Add datadog component
* Improve test_invalid_config datadog test
* Use assert_setup_component for test setup
* Fix object type for default KNX port
#7429 describes a TypeError that is raised if the port is omitted in the config for the KNX component (integer is required (got type str)). This commit changes the default port from a string to an integer. I expect this will resolve that issue...
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Fixed breaks cause by manual upstream merge.
* Added one extra blank line to make PyLint happy.
* Switched json_attributes to be a list of keys rather than a boolean.
The value of json_attributes can now be either a comma sepaated list
of key names or a YAML list of key names. Only matching keys in a
retuned JSON dictionary will be mapped to sensor attributes.
Updated test cases to handle json_attributes being a list.
Also fixed two minor issues arrising from manual merge with 0.58 master.
* Added an explicit default value to the json_attributes config entry.
* Removed self.update() from __init__() body.
* Expended unit tests for error cases of json_attributes processing.
* Align quotes
2017-12-03 15:30:25 +00:00
|
|
|
json_attrs = config.get(CONF_JSON_ATTRS)
|
2020-02-16 05:10:23 +00:00
|
|
|
json_attrs_path = config.get(CONF_JSON_ATTRS_PATH)
|
2017-12-09 07:18:45 +00:00
|
|
|
force_update = config.get(CONF_FORCE_UPDATE)
|
2019-02-26 18:23:46 +00:00
|
|
|
timeout = config.get(CONF_TIMEOUT)
|
Unpacking RESTful sensor JSON results into attributes. (#10753)
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* sensor.envirophat: add missing requirement (#7451)
Adding requirements that is not explicitly pulled in by the library
that manages the Enviro pHAT.
* PyPI Openzwave (#7415)
* Remove default zwave config path
PYOZW now has much more comprehensive default handling for the config
path (in src-lib/libopenzwave/libopenzwave.pyx:getConfig()). It looks in
the same place we were looking, plus _many_ more. It will certainly do a
much better job of finding the config files than we will (and will be
updated as the library is changed, so we don't end up chasing it). The
getConfig() method has been there for a while, but was subsntially
improved recently.
This change simply leaves the config_path as None if it is not
specified, which will trigger the default handling in PYOZW.
* Install python-openzwave from PyPI
As of version 0.4, python-openzwave supports installation from PyPI,
which means we can use our 'normal' dependency management tooling to
install it. Yay.
This uses the default 'embed' build (which goes and downloads
statically sources to avoid having to compile anything locally). Check
out the python-openzwave readme for more details.
* Add python-openzwave deps to .travis.yml
Python OpenZwave require the libudev headers to build. This adds the
libudev-dev package to Travis runs via the 'apt' addon for Travis.
Thanks to @MartinHjelmare for this fix.
* Update docker build for PyPI openzwave
Now that PYOZW can be install from PyPI, the docker image build process
can be simplified to remove the explicit compilation of PYOZW.
* Add datadog component (#7158)
* Add datadog component
* Improve test_invalid_config datadog test
* Use assert_setup_component for test setup
* Fix object type for default KNX port
#7429 describes a TypeError that is raised if the port is omitted in the config for the KNX component (integer is required (got type str)). This commit changes the default port from a string to an integer. I expect this will resolve that issue...
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Fixed breaks cause by manual upstream merge.
* Added one extra blank line to make PyLint happy.
* Switched json_attributes to be a list of keys rather than a boolean.
The value of json_attributes can now be either a comma sepaated list
of key names or a YAML list of key names. Only matching keys in a
retuned JSON dictionary will be mapped to sensor attributes.
Updated test cases to handle json_attributes being a list.
Also fixed two minor issues arrising from manual merge with 0.58 master.
* Added an explicit default value to the json_attributes config entry.
* Removed self.update() from __init__() body.
* Expended unit tests for error cases of json_attributes processing.
* Align quotes
2017-12-03 15:30:25 +00:00
|
|
|
|
2016-09-28 04:29:55 +00:00
|
|
|
if value_template is not None:
|
|
|
|
value_template.hass = hass
|
2016-10-04 08:07:17 +00:00
|
|
|
|
2019-10-23 05:43:28 +00:00
|
|
|
if resource_template is not None:
|
|
|
|
resource_template.hass = hass
|
|
|
|
resource = resource_template.render()
|
|
|
|
|
2016-10-04 08:07:17 +00:00
|
|
|
if username and password:
|
|
|
|
if config.get(CONF_AUTHENTICATION) == HTTP_DIGEST_AUTHENTICATION:
|
|
|
|
auth = HTTPDigestAuth(username, password)
|
|
|
|
else:
|
|
|
|
auth = HTTPBasicAuth(username, password)
|
|
|
|
else:
|
|
|
|
auth = None
|
2019-07-31 19:25:30 +00:00
|
|
|
rest = RestData(method, resource, auth, headers, payload, verify_ssl, timeout)
|
2016-01-02 21:29:33 +00:00
|
|
|
rest.update()
|
2018-09-21 13:54:50 +00:00
|
|
|
if rest.data is None:
|
|
|
|
raise PlatformNotReady
|
2015-09-14 08:06:40 +00:00
|
|
|
|
2018-09-21 13:54:50 +00:00
|
|
|
# Must update the sensor now (including fetching the rest resource) to
|
|
|
|
# ensure it's updating its state.
|
2019-07-31 19:25:30 +00:00
|
|
|
add_entities(
|
|
|
|
[
|
|
|
|
RestSensor(
|
|
|
|
hass,
|
|
|
|
rest,
|
|
|
|
name,
|
|
|
|
unit,
|
|
|
|
device_class,
|
|
|
|
value_template,
|
|
|
|
json_attrs,
|
|
|
|
force_update,
|
2019-10-23 05:43:28 +00:00
|
|
|
resource_template,
|
2020-02-16 05:10:23 +00:00
|
|
|
json_attrs_path,
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
|
|
|
],
|
|
|
|
True,
|
|
|
|
)
|
2015-09-13 20:41:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
class RestSensor(Entity):
|
2016-03-08 15:46:34 +00:00
|
|
|
"""Implementation of a REST sensor."""
|
2015-09-13 20:41:16 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
hass,
|
|
|
|
rest,
|
|
|
|
name,
|
|
|
|
unit_of_measurement,
|
|
|
|
device_class,
|
|
|
|
value_template,
|
|
|
|
json_attrs,
|
|
|
|
force_update,
|
2019-10-23 05:43:28 +00:00
|
|
|
resource_template,
|
2020-02-16 05:10:23 +00:00
|
|
|
json_attrs_path,
|
2019-07-31 19:25:30 +00:00
|
|
|
):
|
2016-09-03 23:45:49 +00:00
|
|
|
"""Initialize the REST sensor."""
|
2015-12-11 22:19:49 +00:00
|
|
|
self._hass = hass
|
2015-09-13 20:41:16 +00:00
|
|
|
self.rest = rest
|
|
|
|
self._name = name
|
2019-01-24 07:20:20 +00:00
|
|
|
self._state = None
|
2015-09-13 20:41:16 +00:00
|
|
|
self._unit_of_measurement = unit_of_measurement
|
2019-01-16 18:03:53 +00:00
|
|
|
self._device_class = device_class
|
2015-12-11 22:19:49 +00:00
|
|
|
self._value_template = value_template
|
Unpacking RESTful sensor JSON results into attributes. (#10753)
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* sensor.envirophat: add missing requirement (#7451)
Adding requirements that is not explicitly pulled in by the library
that manages the Enviro pHAT.
* PyPI Openzwave (#7415)
* Remove default zwave config path
PYOZW now has much more comprehensive default handling for the config
path (in src-lib/libopenzwave/libopenzwave.pyx:getConfig()). It looks in
the same place we were looking, plus _many_ more. It will certainly do a
much better job of finding the config files than we will (and will be
updated as the library is changed, so we don't end up chasing it). The
getConfig() method has been there for a while, but was subsntially
improved recently.
This change simply leaves the config_path as None if it is not
specified, which will trigger the default handling in PYOZW.
* Install python-openzwave from PyPI
As of version 0.4, python-openzwave supports installation from PyPI,
which means we can use our 'normal' dependency management tooling to
install it. Yay.
This uses the default 'embed' build (which goes and downloads
statically sources to avoid having to compile anything locally). Check
out the python-openzwave readme for more details.
* Add python-openzwave deps to .travis.yml
Python OpenZwave require the libudev headers to build. This adds the
libudev-dev package to Travis runs via the 'apt' addon for Travis.
Thanks to @MartinHjelmare for this fix.
* Update docker build for PyPI openzwave
Now that PYOZW can be install from PyPI, the docker image build process
can be simplified to remove the explicit compilation of PYOZW.
* Add datadog component (#7158)
* Add datadog component
* Improve test_invalid_config datadog test
* Use assert_setup_component for test setup
* Fix object type for default KNX port
#7429 describes a TypeError that is raised if the port is omitted in the config for the KNX component (integer is required (got type str)). This commit changes the default port from a string to an integer. I expect this will resolve that issue...
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Fixed breaks cause by manual upstream merge.
* Added one extra blank line to make PyLint happy.
* Switched json_attributes to be a list of keys rather than a boolean.
The value of json_attributes can now be either a comma sepaated list
of key names or a YAML list of key names. Only matching keys in a
retuned JSON dictionary will be mapped to sensor attributes.
Updated test cases to handle json_attributes being a list.
Also fixed two minor issues arrising from manual merge with 0.58 master.
* Added an explicit default value to the json_attributes config entry.
* Removed self.update() from __init__() body.
* Expended unit tests for error cases of json_attributes processing.
* Align quotes
2017-12-03 15:30:25 +00:00
|
|
|
self._json_attrs = json_attrs
|
|
|
|
self._attributes = None
|
2017-12-09 07:18:45 +00:00
|
|
|
self._force_update = force_update
|
2019-10-23 05:43:28 +00:00
|
|
|
self._resource_template = resource_template
|
2020-02-16 05:10:23 +00:00
|
|
|
self._json_attrs_path = json_attrs_path
|
2015-09-13 20:41:16 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
2016-03-08 15:46:34 +00:00
|
|
|
"""Return the name of the sensor."""
|
2015-09-13 20:41:16 +00:00
|
|
|
return self._name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def unit_of_measurement(self):
|
2016-03-08 15:46:34 +00:00
|
|
|
"""Return the unit the value is expressed in."""
|
2015-09-13 20:41:16 +00:00
|
|
|
return self._unit_of_measurement
|
|
|
|
|
2019-01-16 18:03:53 +00:00
|
|
|
@property
|
|
|
|
def device_class(self):
|
|
|
|
"""Return the class of this sensor."""
|
|
|
|
return self._device_class
|
|
|
|
|
2017-10-23 21:29:41 +00:00
|
|
|
@property
|
|
|
|
def available(self):
|
|
|
|
"""Return if the sensor data are available."""
|
|
|
|
return self.rest.data is not None
|
|
|
|
|
2015-09-13 20:41:16 +00:00
|
|
|
@property
|
|
|
|
def state(self):
|
2016-03-08 15:46:34 +00:00
|
|
|
"""Return the state of the device."""
|
2015-09-13 20:41:16 +00:00
|
|
|
return self._state
|
|
|
|
|
2017-12-09 07:18:45 +00:00
|
|
|
@property
|
|
|
|
def force_update(self):
|
|
|
|
"""Force update."""
|
|
|
|
return self._force_update
|
|
|
|
|
2015-09-13 20:41:16 +00:00
|
|
|
def update(self):
|
2016-03-08 15:46:34 +00:00
|
|
|
"""Get the latest data from REST API and update the state."""
|
2019-10-23 05:43:28 +00:00
|
|
|
if self._resource_template is not None:
|
|
|
|
self.rest.set_url(self._resource_template.render())
|
|
|
|
|
2015-09-13 20:41:16 +00:00
|
|
|
self.rest.update()
|
|
|
|
value = self.rest.data
|
2020-02-21 20:11:25 +00:00
|
|
|
_LOGGER.debug("Data fetched from resource: %s", value)
|
2020-02-28 19:41:41 +00:00
|
|
|
if self.rest.headers is not None:
|
|
|
|
# If the http request failed, headers will be None
|
|
|
|
content_type = self.rest.headers.get("content-type")
|
|
|
|
|
2020-03-02 07:22:01 +00:00
|
|
|
if content_type and (
|
|
|
|
content_type.startswith("text/xml")
|
|
|
|
or content_type.startswith("application/xml")
|
|
|
|
):
|
2020-02-28 19:41:41 +00:00
|
|
|
try:
|
|
|
|
value = json.dumps(xmltodict.parse(value))
|
|
|
|
_LOGGER.debug("JSON converted from XML: %s", value)
|
|
|
|
except ExpatError:
|
|
|
|
_LOGGER.warning(
|
|
|
|
"REST xml result could not be parsed and converted to JSON."
|
|
|
|
)
|
|
|
|
_LOGGER.debug("Erroneous XML: %s", value)
|
2015-09-13 20:41:16 +00:00
|
|
|
|
Unpacking RESTful sensor JSON results into attributes. (#10753)
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* sensor.envirophat: add missing requirement (#7451)
Adding requirements that is not explicitly pulled in by the library
that manages the Enviro pHAT.
* PyPI Openzwave (#7415)
* Remove default zwave config path
PYOZW now has much more comprehensive default handling for the config
path (in src-lib/libopenzwave/libopenzwave.pyx:getConfig()). It looks in
the same place we were looking, plus _many_ more. It will certainly do a
much better job of finding the config files than we will (and will be
updated as the library is changed, so we don't end up chasing it). The
getConfig() method has been there for a while, but was subsntially
improved recently.
This change simply leaves the config_path as None if it is not
specified, which will trigger the default handling in PYOZW.
* Install python-openzwave from PyPI
As of version 0.4, python-openzwave supports installation from PyPI,
which means we can use our 'normal' dependency management tooling to
install it. Yay.
This uses the default 'embed' build (which goes and downloads
statically sources to avoid having to compile anything locally). Check
out the python-openzwave readme for more details.
* Add python-openzwave deps to .travis.yml
Python OpenZwave require the libudev headers to build. This adds the
libudev-dev package to Travis runs via the 'apt' addon for Travis.
Thanks to @MartinHjelmare for this fix.
* Update docker build for PyPI openzwave
Now that PYOZW can be install from PyPI, the docker image build process
can be simplified to remove the explicit compilation of PYOZW.
* Add datadog component (#7158)
* Add datadog component
* Improve test_invalid_config datadog test
* Use assert_setup_component for test setup
* Fix object type for default KNX port
#7429 describes a TypeError that is raised if the port is omitted in the config for the KNX component (integer is required (got type str)). This commit changes the default port from a string to an integer. I expect this will resolve that issue...
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Fixed breaks cause by manual upstream merge.
* Added one extra blank line to make PyLint happy.
* Switched json_attributes to be a list of keys rather than a boolean.
The value of json_attributes can now be either a comma sepaated list
of key names or a YAML list of key names. Only matching keys in a
retuned JSON dictionary will be mapped to sensor attributes.
Updated test cases to handle json_attributes being a list.
Also fixed two minor issues arrising from manual merge with 0.58 master.
* Added an explicit default value to the json_attributes config entry.
* Removed self.update() from __init__() body.
* Expended unit tests for error cases of json_attributes processing.
* Align quotes
2017-12-03 15:30:25 +00:00
|
|
|
if self._json_attrs:
|
|
|
|
self._attributes = {}
|
2018-03-05 23:30:28 +00:00
|
|
|
if value:
|
|
|
|
try:
|
|
|
|
json_dict = json.loads(value)
|
2020-02-16 05:10:23 +00:00
|
|
|
if self._json_attrs_path is not None:
|
|
|
|
json_dict = jsonpath(json_dict, self._json_attrs_path)
|
|
|
|
# jsonpath will always store the result in json_dict[0]
|
|
|
|
# so the next line happens to work exactly as needed to
|
|
|
|
# find the result
|
2019-11-26 21:10:58 +00:00
|
|
|
if isinstance(json_dict, list):
|
|
|
|
json_dict = json_dict[0]
|
2018-03-05 23:30:28 +00:00
|
|
|
if isinstance(json_dict, dict):
|
2019-07-31 19:25:30 +00:00
|
|
|
attrs = {
|
|
|
|
k: json_dict[k] for k in self._json_attrs if k in json_dict
|
|
|
|
}
|
2018-03-05 23:30:28 +00:00
|
|
|
self._attributes = attrs
|
|
|
|
else:
|
2019-11-26 21:10:58 +00:00
|
|
|
_LOGGER.warning(
|
|
|
|
"JSON result was not a dictionary"
|
|
|
|
" or list with 0th element a dictionary"
|
|
|
|
)
|
2018-03-05 23:30:28 +00:00
|
|
|
except ValueError:
|
|
|
|
_LOGGER.warning("REST result could not be parsed as JSON")
|
|
|
|
_LOGGER.debug("Erroneous JSON: %s", value)
|
|
|
|
else:
|
|
|
|
_LOGGER.warning("Empty reply found when expecting JSON data")
|
2019-01-24 07:20:20 +00:00
|
|
|
if value is not None and self._value_template is not None:
|
2019-07-31 19:25:30 +00:00
|
|
|
value = self._value_template.render_with_possible_json_value(value, None)
|
2015-12-25 21:34:30 +00:00
|
|
|
|
|
|
|
self._state = value
|
2015-09-13 20:41:16 +00:00
|
|
|
|
Unpacking RESTful sensor JSON results into attributes. (#10753)
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* sensor.envirophat: add missing requirement (#7451)
Adding requirements that is not explicitly pulled in by the library
that manages the Enviro pHAT.
* PyPI Openzwave (#7415)
* Remove default zwave config path
PYOZW now has much more comprehensive default handling for the config
path (in src-lib/libopenzwave/libopenzwave.pyx:getConfig()). It looks in
the same place we were looking, plus _many_ more. It will certainly do a
much better job of finding the config files than we will (and will be
updated as the library is changed, so we don't end up chasing it). The
getConfig() method has been there for a while, but was subsntially
improved recently.
This change simply leaves the config_path as None if it is not
specified, which will trigger the default handling in PYOZW.
* Install python-openzwave from PyPI
As of version 0.4, python-openzwave supports installation from PyPI,
which means we can use our 'normal' dependency management tooling to
install it. Yay.
This uses the default 'embed' build (which goes and downloads
statically sources to avoid having to compile anything locally). Check
out the python-openzwave readme for more details.
* Add python-openzwave deps to .travis.yml
Python OpenZwave require the libudev headers to build. This adds the
libudev-dev package to Travis runs via the 'apt' addon for Travis.
Thanks to @MartinHjelmare for this fix.
* Update docker build for PyPI openzwave
Now that PYOZW can be install from PyPI, the docker image build process
can be simplified to remove the explicit compilation of PYOZW.
* Add datadog component (#7158)
* Add datadog component
* Improve test_invalid_config datadog test
* Use assert_setup_component for test setup
* Fix object type for default KNX port
#7429 describes a TypeError that is raised if the port is omitted in the config for the KNX component (integer is required (got type str)). This commit changes the default port from a string to an integer. I expect this will resolve that issue...
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Added support for extracting JSON attributes from RESTful values
Setting the json_attributes configuration option to true on the
RESTful sensor will cause the result of the REST request to be parsed
as a JSON string and if successful the resulting dictionary will be
used for the attributes of the sensor.
* Added requirement that RESTful JSON results used as attributes must be
objects, not lists.
* Expanded test coverage to test REFTful JSON attributes with and
without a value template.
* Fixed breaks cause by manual upstream merge.
* Added one extra blank line to make PyLint happy.
* Switched json_attributes to be a list of keys rather than a boolean.
The value of json_attributes can now be either a comma sepaated list
of key names or a YAML list of key names. Only matching keys in a
retuned JSON dictionary will be mapped to sensor attributes.
Updated test cases to handle json_attributes being a list.
Also fixed two minor issues arrising from manual merge with 0.58 master.
* Added an explicit default value to the json_attributes config entry.
* Removed self.update() from __init__() body.
* Expended unit tests for error cases of json_attributes processing.
* Align quotes
2017-12-03 15:30:25 +00:00
|
|
|
@property
|
|
|
|
def device_state_attributes(self):
|
|
|
|
"""Return the state attributes."""
|
|
|
|
return self._attributes
|
|
|
|
|
2015-09-13 20:41:16 +00:00
|
|
|
|
2018-07-20 08:45:20 +00:00
|
|
|
class RestData:
|
2016-01-02 21:29:33 +00:00
|
|
|
"""Class for handling the data retrieval."""
|
2015-09-13 20:41:16 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
def __init__(
|
|
|
|
self, method, resource, auth, headers, data, verify_ssl, timeout=DEFAULT_TIMEOUT
|
|
|
|
):
|
2016-03-08 15:46:34 +00:00
|
|
|
"""Initialize the data object."""
|
2019-11-26 07:22:11 +00:00
|
|
|
self._method = method
|
|
|
|
self._resource = resource
|
|
|
|
self._auth = auth
|
|
|
|
self._headers = headers
|
|
|
|
self._request_data = data
|
2015-10-01 03:45:48 +00:00
|
|
|
self._verify_ssl = verify_ssl
|
2019-02-26 18:23:46 +00:00
|
|
|
self._timeout = timeout
|
2020-03-04 16:32:38 +00:00
|
|
|
self._http_session = Session()
|
2015-12-25 21:34:30 +00:00
|
|
|
self.data = None
|
2020-02-16 05:10:23 +00:00
|
|
|
self.headers = None
|
2015-09-22 23:15:16 +00:00
|
|
|
|
2020-03-04 16:32:38 +00:00
|
|
|
def __del__(self):
|
|
|
|
"""Destroy the http session on destroy."""
|
|
|
|
self._http_session.close()
|
|
|
|
|
2019-10-23 05:43:28 +00:00
|
|
|
def set_url(self, url):
|
|
|
|
"""Set url."""
|
2019-11-26 07:22:11 +00:00
|
|
|
self._resource = url
|
2019-10-23 05:43:28 +00:00
|
|
|
|
2015-09-22 23:15:16 +00:00
|
|
|
def update(self):
|
2016-10-31 04:51:03 +00:00
|
|
|
"""Get the latest data from REST service with provided method."""
|
2019-11-26 07:22:11 +00:00
|
|
|
_LOGGER.debug("Updating from %s", self._resource)
|
2015-09-22 23:15:16 +00:00
|
|
|
try:
|
2020-03-04 16:32:38 +00:00
|
|
|
response = self._http_session.request(
|
2019-11-26 07:22:11 +00:00
|
|
|
self._method,
|
|
|
|
self._resource,
|
|
|
|
headers=self._headers,
|
|
|
|
auth=self._auth,
|
|
|
|
data=self._request_data,
|
|
|
|
timeout=self._timeout,
|
|
|
|
verify=self._verify_ssl,
|
|
|
|
)
|
2015-12-11 22:19:49 +00:00
|
|
|
self.data = response.text
|
2020-02-16 05:10:23 +00:00
|
|
|
self.headers = response.headers
|
2018-05-11 10:28:28 +00:00
|
|
|
except requests.exceptions.RequestException as ex:
|
2019-11-26 07:22:11 +00:00
|
|
|
_LOGGER.error("Error fetching data: %s failed with %s", self._resource, ex)
|
2015-12-25 21:34:30 +00:00
|
|
|
self.data = None
|
2020-02-16 05:10:23 +00:00
|
|
|
self.headers = None
|