Guest User

jsonrest.py

a guest
Feb 28th, 2018
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.08 KB | None | 0 0
  1. """
  2. Support for RESTful API sensors.
  3.  
  4. For more details about this platform, please refer to the documentation at
  5. https://home-assistant.io/components/sensor.rest/
  6.  
  7. Modified to parse a JSON reply and store data as attributes
  8. """
  9. import logging
  10.  
  11. import voluptuous as vol
  12. import json
  13. import requests
  14. from requests.auth import HTTPBasicAuth, HTTPDigestAuth
  15.  
  16. from homeassistant.components.sensor import PLATFORM_SCHEMA
  17. from homeassistant.const import (
  18.     CONF_PAYLOAD, CONF_NAME, CONF_VALUE_TEMPLATE, CONF_METHOD, CONF_RESOURCE,
  19.     CONF_UNIT_OF_MEASUREMENT, STATE_UNKNOWN, STATE_ON, CONF_VERIFY_SSL, CONF_USERNAME,
  20.     CONF_PASSWORD, CONF_AUTHENTICATION, HTTP_BASIC_AUTHENTICATION,
  21.     HTTP_DIGEST_AUTHENTICATION, CONF_HEADERS)
  22. from homeassistant.helpers.entity import Entity
  23. import homeassistant.helpers.config_validation as cv
  24.  
  25. _LOGGER = logging.getLogger(__name__)
  26.  
  27. DEFAULT_METHOD = 'GET'
  28. DEFAULT_NAME = 'JSON REST Sensor'
  29. DEFAULT_VERIFY_SSL = True
  30.  
  31. PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
  32.     vol.Required(CONF_RESOURCE): cv.url,
  33.     vol.Optional(CONF_AUTHENTICATION):
  34.         vol.In([HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION]),
  35.     vol.Optional(CONF_HEADERS): {cv.string: cv.string},
  36.     vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(['POST', 'GET']),
  37.     vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
  38.     vol.Optional(CONF_PASSWORD): cv.string,
  39.     vol.Optional(CONF_PAYLOAD): cv.string,
  40.     vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
  41.     vol.Optional(CONF_USERNAME): cv.string,
  42.     vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
  43.     vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
  44. })
  45.  
  46.  
  47. def setup_platform(hass, config, add_devices, discovery_info=None):
  48.     """Set up the RESTful sensor."""
  49.     name = config.get(CONF_NAME)
  50.     resource = config.get(CONF_RESOURCE)
  51.     method = config.get(CONF_METHOD)
  52.     payload = config.get(CONF_PAYLOAD)
  53.     verify_ssl = config.get(CONF_VERIFY_SSL)
  54.     username = config.get(CONF_USERNAME)
  55.     password = config.get(CONF_PASSWORD)
  56.     headers = config.get(CONF_HEADERS)
  57.     unit = config.get(CONF_UNIT_OF_MEASUREMENT)
  58.     value_template = config.get(CONF_VALUE_TEMPLATE)
  59.     if value_template is not None:
  60.         value_template.hass = hass
  61.  
  62.     if username and password:
  63.         if config.get(CONF_AUTHENTICATION) == HTTP_DIGEST_AUTHENTICATION:
  64.             auth = HTTPDigestAuth(username, password)
  65.         else:
  66.             auth = HTTPBasicAuth(username, password)
  67.     else:
  68.         auth = None
  69.     rest = JSONRestData(method, resource, auth, headers, payload, verify_ssl)
  70.     rest.update()
  71.  
  72.     if rest.data is None:
  73.         _LOGGER.error("Unable to fetch REST data")
  74.         return False
  75.  
  76.     add_devices([JSONRestSensor(hass, rest, name, unit, value_template)])
  77.  
  78.  
  79. class JSONRestSensor(Entity):
  80.     """Implementation of a REST sensor."""
  81.  
  82.     def __init__(self, hass, rest, name, unit_of_measurement, value_template):
  83.         """Initialize the REST sensor."""
  84.         self._hass = hass
  85.         self.rest = rest
  86.         self._name = name
  87.         self._attributes = {}
  88.         self._state = STATE_UNKNOWN
  89.         self._unit_of_measurement = unit_of_measurement
  90.         self._value_template = value_template
  91.         self.update()
  92.  
  93.     @property
  94.     def name(self):
  95.         """Return the name of the sensor."""
  96.         return self._name
  97.  
  98.     @property
  99.     def unit_of_measurement(self):
  100.         """Return the unit the value is expressed in."""
  101.         return self._unit_of_measurement
  102.  
  103.     @property
  104.     def state(self):
  105.         """Return the state of the device."""
  106.         return self._state
  107.    
  108.     def update(self):
  109.         """Get the latest data from REST API and update the state."""
  110.         self.rest.update()
  111.         value = self.rest.data
  112.         _LOGGER.debug("Raw REST data: %s" % value)
  113.  
  114.         if value is None:
  115.             _LOGGER.debug("value is None -> state UNKNOWN")
  116.             value = STATE_UNKNOWN
  117.         elif self._value_template is not None:
  118.             value = self._value_template.render_with_possible_json_value(
  119.                 value, STATE_UNKNOWN)
  120.  
  121.         self._state = value
  122.         # if the attributes were parsed, set the state as STATE_ON as a workaround for HA 0.57 state limit
  123.         if len(value) >= 255:
  124.             _LOGGER.debug("value > 255. Setting STATE_ON instead")
  125.             self._state = STATE_ON
  126.    
  127.         """ Parse the return text as JSON and save the json as an attribute. """
  128.         try:
  129.             _LOGGER.debug("Parsing attributes...")
  130.             attributes = json.loads(value)
  131.             if isinstance(attributes, list):
  132.                 _LOGGER.debug("Parsed attributes form a list. Adding it as 'list'")
  133.                 self._attributes['list'] = attributes
  134.             else:
  135.                 _LOGGER.debug("Attributes are not a list. Hopefully they are a dict")
  136.                 self._attributes = attributes
  137.         except json.JSONDecodeError:
  138.             _LOGGER.debug("Error decoding JSON. Resetting attributes")
  139.             self._attributes = {}  
  140.  
  141.  
  142.     @property
  143.     def state_attributes(self):
  144.         """Return the attributes of the entity.
  145.  
  146.           Provide the parsed JSON data (if any).
  147.        """
  148.  
  149.         return self._attributes
  150.  
  151.  
  152. class JSONRestData(object):
  153.     """Class for handling the data retrieval."""
  154.  
  155.     def __init__(self, method, resource, auth, headers, data, verify_ssl):
  156.         """Initialize the data object."""
  157.         self._request = requests.Request(
  158.             method, resource, headers=headers, auth=auth, data=data).prepare()
  159.         self._verify_ssl = verify_ssl
  160.         self.data = None
  161.  
  162.     def update(self):
  163.         """Get the latest data from REST service with provided method."""
  164.         try:
  165.             with requests.Session() as sess:
  166.                 response = sess.send(
  167.                     self._request, timeout=10, verify=self._verify_ssl)
  168.  
  169.             self.data = response.text
  170.         except requests.exceptions.RequestException:
  171.             _LOGGER.error("Error fetching data: %s", self._request)
  172.             self.data = None
Advertisement
Add Comment
Please, Sign In to add comment