Auto convert xml, change out the template for jsonpath

This commit is contained in:
J. Nick Koston
2020-02-14 04:24:10 +00:00
parent 5bbb5f43cb
commit 648aa5f969
5 changed files with 81 additions and 82 deletions

View File

@@ -2,7 +2,7 @@
"domain": "rest", "domain": "rest",
"name": "RESTful", "name": "RESTful",
"documentation": "https://www.home-assistant.io/integrations/rest", "documentation": "https://www.home-assistant.io/integrations/rest",
"requirements": ["xmltodict==0.12.0"], "requirements": ["jsonpath==0.82", "xmltodict==0.12.0"],
"dependencies": [], "dependencies": [],
"codeowners": [] "codeowners": []
} }

View File

@@ -1,9 +1,9 @@
"""Support for RESTful API sensors.""" """Support for RESTful API sensors."""
import ast
import json import json
import logging import logging
from xml.parsers.expat import ExpatError from xml.parsers.expat import ExpatError
from jsonpath import jsonpath
import requests import requests
from requests.auth import HTTPBasicAuth, HTTPDigestAuth from requests.auth import HTTPBasicAuth, HTTPDigestAuth
import voluptuous as vol import voluptuous as vol
@@ -41,11 +41,9 @@ DEFAULT_VERIFY_SSL = True
DEFAULT_FORCE_UPDATE = False DEFAULT_FORCE_UPDATE = False
DEFAULT_TIMEOUT = 10 DEFAULT_TIMEOUT = 10
CONF_CONVERT_XML = "convert_xml"
DEFAULT_CONVERT_XML = False
CONF_JSON_ATTRS = "json_attributes" CONF_JSON_ATTRS = "json_attributes"
CONF_JSON_ATTRS_TEMPLATE = "json_attributes_template" CONF_JSON_ATTRS_PATH = "json_attributes_path"
METHODS = ["POST", "GET"] METHODS = ["POST", "GET"]
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
@@ -57,7 +55,6 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
), ),
vol.Optional(CONF_HEADERS): vol.Schema({cv.string: cv.string}), vol.Optional(CONF_HEADERS): vol.Schema({cv.string: cv.string}),
vol.Optional(CONF_JSON_ATTRS, default=[]): cv.ensure_list_csv, vol.Optional(CONF_JSON_ATTRS, default=[]): cv.ensure_list_csv,
vol.Optional(CONF_CONVERT_XML, default=DEFAULT_CONVERT_XML): cv.boolean,
vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(METHODS), vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(METHODS),
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_PASSWORD): cv.string,
@@ -65,7 +62,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_USERNAME): cv.string, vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_JSON_ATTRS_TEMPLATE): cv.template, vol.Optional(CONF_JSON_ATTRS_PATH): 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,
vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean, vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean,
@@ -93,14 +90,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
device_class = config.get(CONF_DEVICE_CLASS) device_class = config.get(CONF_DEVICE_CLASS)
value_template = config.get(CONF_VALUE_TEMPLATE) value_template = config.get(CONF_VALUE_TEMPLATE)
json_attrs = config.get(CONF_JSON_ATTRS) json_attrs = config.get(CONF_JSON_ATTRS)
convert_xml = config.get(CONF_CONVERT_XML) json_attrs_path = config.get(CONF_JSON_ATTRS_PATH)
json_attrs_template = config.get(CONF_JSON_ATTRS_TEMPLATE)
force_update = config.get(CONF_FORCE_UPDATE) force_update = config.get(CONF_FORCE_UPDATE)
timeout = config.get(CONF_TIMEOUT) timeout = config.get(CONF_TIMEOUT)
if json_attrs_template is not None:
json_attrs_template.hass = hass
if value_template is not None: if value_template is not None:
value_template.hass = hass value_template.hass = hass
@@ -134,8 +127,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
json_attrs, json_attrs,
force_update, force_update,
resource_template, resource_template,
convert_xml, json_attrs_path,
json_attrs_template,
) )
], ],
True, True,
@@ -156,8 +148,7 @@ class RestSensor(Entity):
json_attrs, json_attrs,
force_update, force_update,
resource_template, resource_template,
convert_xml, json_attrs_path,
json_attrs_template,
): ):
"""Initialize the REST sensor.""" """Initialize the REST sensor."""
self._hass = hass self._hass = hass
@@ -171,8 +162,7 @@ class RestSensor(Entity):
self._attributes = None self._attributes = None
self._force_update = force_update self._force_update = force_update
self._resource_template = resource_template self._resource_template = resource_template
self._convert_xml = convert_xml self._json_attrs_path = json_attrs_path
self._json_attrs_template = json_attrs_template
@property @property
def name(self): def name(self):
@@ -211,9 +201,9 @@ class RestSensor(Entity):
self.rest.update() self.rest.update()
value = self.rest.data value = self.rest.data
json_dict = None content_type = self.rest.headers.get("content-type")
if self._convert_xml: if content_type and content_type.startswith("text/xml"):
try: try:
value = json.dumps(xmltodict.parse(value)) value = json.dumps(xmltodict.parse(value))
except ExpatError: except ExpatError:
@@ -227,14 +217,8 @@ class RestSensor(Entity):
if value: if value:
try: try:
json_dict = json.loads(value) json_dict = json.loads(value)
if self._json_attrs_template is not None: if self._json_attrs_path is not None:
# render_with_possible_json_value returns single quoted json_dict = jsonpath(json_dict, self._json_attrs_path)
# strings so we cannot use json.loads to read it back here
json_dict = ast.literal_eval(
self._json_attrs_template.render_with_possible_json_value(
value, None
)
)
if isinstance(json_dict, list): if isinstance(json_dict, list):
json_dict = json_dict[0] json_dict = json_dict[0]
if isinstance(json_dict, dict): if isinstance(json_dict, dict):
@@ -278,6 +262,7 @@ class RestData:
self._verify_ssl = verify_ssl self._verify_ssl = verify_ssl
self._timeout = timeout self._timeout = timeout
self.data = None self.data = None
self.headers = None
def set_url(self, url): def set_url(self, url):
"""Set url.""" """Set url."""
@@ -297,6 +282,8 @@ class RestData:
verify=self._verify_ssl, verify=self._verify_ssl,
) )
self.data = response.text self.data = response.text
self.headers = response.headers
except requests.exceptions.RequestException as ex: except requests.exceptions.RequestException as ex:
_LOGGER.error("Error fetching data: %s failed with %s", self._resource, ex) _LOGGER.error("Error fetching data: %s failed with %s", self._resource, ex)
self.data = None self.data = None
self.headers = None

View File

@@ -742,6 +742,7 @@ iperf3==0.1.11
# homeassistant.components.route53 # homeassistant.components.route53
ipify==1.0.0 ipify==1.0.0
# homeassistant.components.rest
# homeassistant.components.verisure # homeassistant.components.verisure
jsonpath==0.82 jsonpath==0.82

View File

@@ -278,6 +278,7 @@ iaqualink==0.3.1
# homeassistant.components.influxdb # homeassistant.components.influxdb
influxdb==5.2.3 influxdb==5.2.3
# homeassistant.components.rest
# homeassistant.components.verisure # homeassistant.components.verisure
jsonpath==0.82 jsonpath==0.82

View File

@@ -6,6 +6,7 @@ import pytest
from pytest import raises from pytest import raises
import requests import requests
from requests.exceptions import RequestException, Timeout from requests.exceptions import RequestException, Timeout
from requests.structures import CaseInsensitiveDict
import requests_mock import requests_mock
import homeassistant.components.rest.sensor as rest import homeassistant.components.rest.sensor as rest
@@ -184,7 +185,6 @@ class TestRestSensorSetup(unittest.TestCase):
"unit_of_measurement": DATA_MEGABYTES, "unit_of_measurement": DATA_MEGABYTES,
"verify_ssl": "true", "verify_ssl": "true",
"timeout": 30, "timeout": 30,
"convert_xml": True,
"authentication": "basic", "authentication": "basic",
"username": "my username", "username": "my username",
"password": "my password", "password": "my password",
@@ -206,19 +206,18 @@ class TestRestSensor(unittest.TestCase):
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", "rest.RestData.update",
side_effect=self.update_side_effect( side_effect=self.update_side_effect(
'{ "key": "' + self.initial_state + '" }' '{ "key": "' + self.initial_state + '" }',
CaseInsensitiveDict({"Content-Type": "application/json"}),
), ),
) )
self.name = "foo" self.name = "foo"
self.unit_of_measurement = DATA_MEGABYTES self.unit_of_measurement = DATA_MEGABYTES
self.device_class = None self.device_class = None
self.value_template = template("{{ value_json.key }}") self.value_template = template("{{ value_json.key }}")
self.json_attrs_template = template("{{ value_json }}") self.json_attrs_path = None
self.value_template.hass = self.hass self.value_template.hass = self.hass
self.json_attrs_template.hass = self.hass
self.force_update = False self.force_update = False
self.resource_template = None self.resource_template = None
self.convert_xml = False
self.sensor = rest.RestSensor( self.sensor = rest.RestSensor(
self.hass, self.hass,
@@ -230,17 +229,17 @@ class TestRestSensor(unittest.TestCase):
[], [],
self.force_update, self.force_update,
self.resource_template, self.resource_template,
self.convert_xml, self.json_attrs_path,
self.json_attrs_template,
) )
def tearDown(self): def tearDown(self):
"""Stop everything that was started.""" """Stop everything that was started."""
self.hass.stop() self.hass.stop()
def update_side_effect(self, data): def update_side_effect(self, data, headers):
"""Side effect function for mocking RestData.update().""" """Side effect function for mocking RestData.update()."""
self.rest.data = data self.rest.data = data
self.rest.headers = headers
def test_name(self): def test_name(self):
"""Test the name.""" """Test the name."""
@@ -262,7 +261,8 @@ class TestRestSensor(unittest.TestCase):
def test_update_when_value_is_none(self): def test_update_when_value_is_none(self):
"""Test state gets updated to unknown when sensor returns no data.""" """Test state gets updated to unknown when sensor returns no data."""
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", side_effect=self.update_side_effect(None) "rest.RestData.update",
side_effect=self.update_side_effect(None, CaseInsensitiveDict()),
) )
self.sensor.update() self.sensor.update()
assert self.sensor.state is None assert self.sensor.state is None
@@ -272,7 +272,10 @@ class TestRestSensor(unittest.TestCase):
"""Test state gets updated when sensor returns a new status.""" """Test state gets updated when sensor returns a new status."""
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", "rest.RestData.update",
side_effect=self.update_side_effect('{ "key": "updated_state" }'), side_effect=self.update_side_effect(
'{ "key": "updated_state" }',
CaseInsensitiveDict({"Content-Type": "application/json"}),
),
) )
self.sensor.update() self.sensor.update()
assert "updated_state" == self.sensor.state assert "updated_state" == self.sensor.state
@@ -281,7 +284,10 @@ class TestRestSensor(unittest.TestCase):
def test_update_with_no_template(self): def test_update_with_no_template(self):
"""Test update when there is no value template.""" """Test update when there is no value template."""
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", side_effect=self.update_side_effect("plain_state") "rest.RestData.update",
side_effect=self.update_side_effect(
"plain_state", CaseInsensitiveDict({"Content-Type": "application/json"})
),
) )
self.sensor = rest.RestSensor( self.sensor = rest.RestSensor(
self.hass, self.hass,
@@ -293,8 +299,7 @@ class TestRestSensor(unittest.TestCase):
[], [],
self.force_update, self.force_update,
self.resource_template, self.resource_template,
self.convert_xml, self.json_attrs_path,
self.json_attrs_template,
) )
self.sensor.update() self.sensor.update()
assert "plain_state" == self.sensor.state assert "plain_state" == self.sensor.state
@@ -304,7 +309,10 @@ class TestRestSensor(unittest.TestCase):
"""Test attributes get extracted from a JSON result.""" """Test attributes get extracted from a JSON result."""
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", "rest.RestData.update",
side_effect=self.update_side_effect('{ "key": "some_json_value" }'), side_effect=self.update_side_effect(
'{ "key": "some_json_value" }',
CaseInsensitiveDict({"Content-Type": "application/json"}),
),
) )
self.sensor = rest.RestSensor( self.sensor = rest.RestSensor(
self.hass, self.hass,
@@ -316,8 +324,7 @@ class TestRestSensor(unittest.TestCase):
["key"], ["key"],
self.force_update, self.force_update,
self.resource_template, self.resource_template,
self.convert_xml, self.json_attrs_path,
self.json_attrs_template,
) )
self.sensor.update() self.sensor.update()
assert "some_json_value" == self.sensor.device_state_attributes["key"] assert "some_json_value" == self.sensor.device_state_attributes["key"]
@@ -326,7 +333,10 @@ class TestRestSensor(unittest.TestCase):
"""Test attributes get extracted from a JSON list[0] result.""" """Test attributes get extracted from a JSON list[0] result."""
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", "rest.RestData.update",
side_effect=self.update_side_effect('[{ "key": "another_value" }]'), side_effect=self.update_side_effect(
'[{ "key": "another_value" }]',
CaseInsensitiveDict({"Content-Type": "application/json"}),
),
) )
self.sensor = rest.RestSensor( self.sensor = rest.RestSensor(
self.hass, self.hass,
@@ -338,8 +348,7 @@ class TestRestSensor(unittest.TestCase):
["key"], ["key"],
self.force_update, self.force_update,
self.resource_template, self.resource_template,
self.convert_xml, self.json_attrs_path,
self.json_attrs_template,
) )
self.sensor.update() self.sensor.update()
assert "another_value" == self.sensor.device_state_attributes["key"] assert "another_value" == self.sensor.device_state_attributes["key"]
@@ -348,7 +357,10 @@ class TestRestSensor(unittest.TestCase):
def test_update_with_json_attrs_no_data(self, mock_logger): def test_update_with_json_attrs_no_data(self, mock_logger):
"""Test attributes when no JSON result fetched.""" """Test attributes when no JSON result fetched."""
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", side_effect=self.update_side_effect(None) "rest.RestData.update",
side_effect=self.update_side_effect(
None, CaseInsensitiveDict({"Content-Type": "application/json"})
),
) )
self.sensor = rest.RestSensor( self.sensor = rest.RestSensor(
self.hass, self.hass,
@@ -360,8 +372,7 @@ class TestRestSensor(unittest.TestCase):
["key"], ["key"],
self.force_update, self.force_update,
self.resource_template, self.resource_template,
self.convert_xml, self.json_attrs_path,
self.json_attrs_template,
) )
self.sensor.update() self.sensor.update()
assert {} == self.sensor.device_state_attributes assert {} == self.sensor.device_state_attributes
@@ -372,7 +383,10 @@ class TestRestSensor(unittest.TestCase):
"""Test attributes get extracted from a JSON result.""" """Test attributes get extracted from a JSON result."""
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", "rest.RestData.update",
side_effect=self.update_side_effect('["list", "of", "things"]'), side_effect=self.update_side_effect(
'["list", "of", "things"]',
CaseInsensitiveDict({"Content-Type": "application/json"}),
),
) )
self.sensor = rest.RestSensor( self.sensor = rest.RestSensor(
self.hass, self.hass,
@@ -384,8 +398,7 @@ class TestRestSensor(unittest.TestCase):
["key"], ["key"],
self.force_update, self.force_update,
self.resource_template, self.resource_template,
self.convert_xml, self.json_attrs_path,
self.json_attrs_template,
) )
self.sensor.update() self.sensor.update()
assert {} == self.sensor.device_state_attributes assert {} == self.sensor.device_state_attributes
@@ -396,7 +409,10 @@ class TestRestSensor(unittest.TestCase):
"""Test attributes get extracted from a JSON result.""" """Test attributes get extracted from a JSON result."""
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", "rest.RestData.update",
side_effect=self.update_side_effect("This is text rather than JSON data."), side_effect=self.update_side_effect(
"This is text rather than JSON data.",
CaseInsensitiveDict({"Content-Type": "text/plain"}),
),
) )
self.sensor = rest.RestSensor( self.sensor = rest.RestSensor(
self.hass, self.hass,
@@ -408,8 +424,7 @@ class TestRestSensor(unittest.TestCase):
["key"], ["key"],
self.force_update, self.force_update,
self.resource_template, self.resource_template,
self.convert_xml, self.json_attrs_path,
self.json_attrs_template,
) )
self.sensor.update() self.sensor.update()
assert {} == self.sensor.device_state_attributes assert {} == self.sensor.device_state_attributes
@@ -421,7 +436,8 @@ class TestRestSensor(unittest.TestCase):
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", "rest.RestData.update",
side_effect=self.update_side_effect( side_effect=self.update_side_effect(
'{ "key": "json_state_updated_value" }' '{ "key": "json_state_updated_value" }',
CaseInsensitiveDict({"Content-Type": "application/json"}),
), ),
) )
self.sensor = rest.RestSensor( self.sensor = rest.RestSensor(
@@ -434,8 +450,7 @@ class TestRestSensor(unittest.TestCase):
["key"], ["key"],
self.force_update, self.force_update,
self.resource_template, self.resource_template,
self.convert_xml, self.json_attrs_path,
self.json_attrs_template,
) )
self.sensor.update() self.sensor.update()
@@ -444,17 +459,17 @@ class TestRestSensor(unittest.TestCase):
"json_state_updated_value" == self.sensor.device_state_attributes["key"] "json_state_updated_value" == self.sensor.device_state_attributes["key"]
), self.force_update ), self.force_update
def test_update_with_json_attrs_with_json_attrs_template(self): def test_update_with_json_attrs_with_json_attrs_path(self):
"""Test attributes get extracted from a JSON result with a template for the attributes.""" """Test attributes get extracted from a JSON result with a template for the attributes."""
json_attrs_template = template("{{ value_json.toplevel.second_level }}") json_attrs_path = "$.toplevel.second_level"
json_attrs_template.hass = self.hass
value_template = template("{{ value_json.toplevel.master_value }}") value_template = template("{{ value_json.toplevel.master_value }}")
value_template.hass = self.hass value_template.hass = self.hass
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", "rest.RestData.update",
side_effect=self.update_side_effect( side_effect=self.update_side_effect(
'{ "toplevel": {"master_value": "master", "second_level": {"some_json_key": "some_json_value", "some_json_key2": "some_json_value2" } } }' '{ "toplevel": {"master_value": "master", "second_level": {"some_json_key": "some_json_value", "some_json_key2": "some_json_value2" } } }',
CaseInsensitiveDict({"Content-Type": "application/json"}),
), ),
) )
self.sensor = rest.RestSensor( self.sensor = rest.RestSensor(
@@ -467,8 +482,7 @@ class TestRestSensor(unittest.TestCase):
["some_json_key", "some_json_key2"], ["some_json_key", "some_json_key2"],
self.force_update, self.force_update,
self.resource_template, self.resource_template,
self.convert_xml, json_attrs_path,
json_attrs_template,
) )
self.sensor.update() self.sensor.update()
@@ -478,18 +492,17 @@ class TestRestSensor(unittest.TestCase):
) )
assert "master" == self.sensor.state assert "master" == self.sensor.state
def test_update_with_xml_convert_json_attrs_with_json_attrs_template(self): def test_update_with_xml_convert_json_attrs_with_json_attrs_path(self):
"""Test attributes get extracted from a JSON result that was converted from XML with a template for the attributes.""" """Test attributes get extracted from a JSON result that was converted from XML with a template for the attributes."""
json_attrs_template = template("{{ value_json.toplevel.second_level }}") json_attrs_path = "$.toplevel.second_level"
json_attrs_template.hass = self.hass
value_template = template("{{ value_json.toplevel.master_value }}") value_template = template("{{ value_json.toplevel.master_value }}")
value_template.hass = self.hass value_template.hass = self.hass
convert_xml = True
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", "rest.RestData.update",
side_effect=self.update_side_effect( side_effect=self.update_side_effect(
"<toplevel><master_value>master</master_value><second_level><some_json_key>some_json_value</some_json_key><some_json_key2>some_json_value2</some_json_key2></second_level></toplevel>" "<toplevel><master_value>master</master_value><second_level><some_json_key>some_json_value</some_json_key><some_json_key2>some_json_value2</some_json_key2></second_level></toplevel>",
CaseInsensitiveDict({"Content-Type": "text/xml+svg"}),
), ),
) )
self.sensor = rest.RestSensor( self.sensor = rest.RestSensor(
@@ -502,8 +515,7 @@ class TestRestSensor(unittest.TestCase):
["some_json_key", "some_json_key2"], ["some_json_key", "some_json_key2"],
self.force_update, self.force_update,
self.resource_template, self.resource_template,
convert_xml, json_attrs_path,
json_attrs_template,
) )
self.sensor.update() self.sensor.update()
@@ -515,16 +527,15 @@ class TestRestSensor(unittest.TestCase):
def test_update_with_xml_convert_json_attrs_with_jsonattr_template(self): def test_update_with_xml_convert_json_attrs_with_jsonattr_template(self):
"""Test attributes get extracted from a JSON result that was converted from XML.""" """Test attributes get extracted from a JSON result that was converted from XML."""
json_attrs_template = template("{{ value_json.response }}") json_attrs_path = "$.response"
json_attrs_template.hass = self.hass
value_template = template("{{ value_json.response.bss.wlan }}") value_template = template("{{ value_json.response.bss.wlan }}")
value_template.hass = self.hass value_template.hass = self.hass
convert_xml = True
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", "rest.RestData.update",
side_effect=self.update_side_effect( side_effect=self.update_side_effect(
'<?xml version="1.0" encoding="utf-8"?><response><scan>0</scan><ver>12556</ver><count>48</count><ssid>alexander</ssid><bss><valid>0</valid><name>0</name><privacy>0</privacy><wlan>bogus</wlan><strength>0</strength></bss><led0>0</led0><led1>0</led1><led2>0</led2><led3>0</led3><led4>0</led4><led5>0</led5><led6>0</led6><led7>0</led7><btn0>up</btn0><btn1>up</btn1><btn2>up</btn2><btn3>up</btn3><pot0>0</pot0><usr0>0</usr0><temp0>0x0XF0x0XF</temp0><time0> 0</time0></response>' '<?xml version="1.0" encoding="utf-8"?><response><scan>0</scan><ver>12556</ver><count>48</count><ssid>alexander</ssid><bss><valid>0</valid><name>0</name><privacy>0</privacy><wlan>bogus</wlan><strength>0</strength></bss><led0>0</led0><led1>0</led1><led2>0</led2><led3>0</led3><led4>0</led4><led5>0</led5><led6>0</led6><led7>0</led7><btn0>up</btn0><btn1>up</btn1><btn2>up</btn2><btn3>up</btn3><pot0>0</pot0><usr0>0</usr0><temp0>0x0XF0x0XF</temp0><time0> 0</time0></response>',
CaseInsensitiveDict({"Content-Type": "text/xml"}),
), ),
) )
self.sensor = rest.RestSensor( self.sensor = rest.RestSensor(
@@ -537,8 +548,7 @@ class TestRestSensor(unittest.TestCase):
["led0", "led1", "temp0", "time0", "ver"], ["led0", "led1", "temp0", "time0", "ver"],
self.force_update, self.force_update,
self.resource_template, self.resource_template,
convert_xml, json_attrs_path,
json_attrs_template,
) )
self.sensor.update() self.sensor.update()
@@ -554,11 +564,12 @@ class TestRestSensor(unittest.TestCase):
"""Test attributes get extracted from a XML result with bad xml.""" """Test attributes get extracted from a XML result with bad xml."""
value_template = template("{{ value_json.toplevel.master_value }}") value_template = template("{{ value_json.toplevel.master_value }}")
value_template.hass = self.hass value_template.hass = self.hass
convert_xml = True
self.rest.update = Mock( self.rest.update = Mock(
"rest.RestData.update", "rest.RestData.update",
side_effect=self.update_side_effect("this is not xml"), side_effect=self.update_side_effect(
"this is not xml", CaseInsensitiveDict({"Content-Type": "text/xml"})
),
) )
self.sensor = rest.RestSensor( self.sensor = rest.RestSensor(
self.hass, self.hass,
@@ -570,8 +581,7 @@ class TestRestSensor(unittest.TestCase):
["key"], ["key"],
self.force_update, self.force_update,
self.resource_template, self.resource_template,
convert_xml, self.json_attrs_path,
self.json_attrs_template,
) )
self.sensor.update() self.sensor.update()