diff --git a/homeassistant/components/rest/sensor.py b/homeassistant/components/rest/sensor.py index 01d974e7006..41adb855903 100644 --- a/homeassistant/components/rest/sensor.py +++ b/homeassistant/components/rest/sensor.py @@ -16,6 +16,7 @@ from homeassistant.const import ( CONF_PASSWORD, CONF_PAYLOAD, CONF_RESOURCE, + CONF_RESOURCE_TEMPLATE, CONF_UNIT_OF_MEASUREMENT, CONF_USERNAME, CONF_TIMEOUT, @@ -42,7 +43,8 @@ METHODS = ["POST", "GET"] PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { - vol.Required(CONF_RESOURCE): cv.url, + vol.Exclusive(CONF_RESOURCE, CONF_RESOURCE): cv.url, + vol.Exclusive(CONF_RESOURCE_TEMPLATE, CONF_RESOURCE): cv.template, vol.Optional(CONF_AUTHENTICATION): vol.In( [HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION] ), @@ -62,11 +64,16 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( } ) +PLATFORM_SCHEMA = vol.All( + cv.has_at_least_one_key(CONF_RESOURCE, CONF_RESOURCE_TEMPLATE), PLATFORM_SCHEMA +) + def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the RESTful sensor.""" name = config.get(CONF_NAME) resource = config.get(CONF_RESOURCE) + resource_template = config.get(CONF_RESOURCE_TEMPLATE) method = config.get(CONF_METHOD) payload = config.get(CONF_PAYLOAD) verify_ssl = config.get(CONF_VERIFY_SSL) @@ -83,6 +90,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None): if value_template is not None: value_template.hass = hass + if resource_template is not None: + resource_template.hass = hass + resource = resource_template.render() + if username and password: if config.get(CONF_AUTHENTICATION) == HTTP_DIGEST_AUTHENTICATION: auth = HTTPDigestAuth(username, password) @@ -108,6 +119,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): value_template, json_attrs, force_update, + resource_template, ) ], True, @@ -127,6 +139,7 @@ class RestSensor(Entity): value_template, json_attrs, force_update, + resource_template, ): """Initialize the REST sensor.""" self._hass = hass @@ -139,6 +152,7 @@ class RestSensor(Entity): self._json_attrs = json_attrs self._attributes = None self._force_update = force_update + self._resource_template = resource_template @property def name(self): @@ -172,6 +186,9 @@ class RestSensor(Entity): def update(self): """Get the latest data from REST API and update the state.""" + if self._resource_template is not None: + self.rest.set_url(self._resource_template.render()) + self.rest.update() value = self.rest.data @@ -217,6 +234,10 @@ class RestData: self._timeout = timeout self.data = None + def set_url(self, url): + """Set url.""" + self._request.prepare_url(url, None) + def update(self): """Get the latest data from REST service with provided method.""" _LOGGER.debug("Updating from %s", self._request.url) diff --git a/homeassistant/const.py b/homeassistant/const.py index 592f6b60bc6..cac0386b812 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -124,6 +124,7 @@ CONF_RECIPIENT = "recipient" CONF_REGION = "region" CONF_RESOURCE = "resource" CONF_RESOURCES = "resources" +CONF_RESOURCE_TEMPLATE = "resource_template" CONF_RGB = "rgb" CONF_ROOM = "room" CONF_SCAN_INTERVAL = "scan_interval" diff --git a/tests/components/rest/test_sensor.py b/tests/components/rest/test_sensor.py index d117678ccc7..50acb053347 100644 --- a/tests/components/rest/test_sensor.py +++ b/tests/components/rest/test_sensor.py @@ -76,6 +76,40 @@ class TestRestSensorSetup(unittest.TestCase): ) assert 2 == mock_req.call_count + @requests_mock.Mocker() + def test_setup_minimum_resource_template(self, mock_req): + """Test setup with minimum configuration (resource_template).""" + mock_req.get("http://localhost", status_code=200) + with assert_setup_component(1, "sensor"): + assert setup_component( + self.hass, + "sensor", + { + "sensor": { + "platform": "rest", + "resource_template": "http://localhost", + } + }, + ) + assert mock_req.call_count == 2 + + @requests_mock.Mocker() + def test_setup_duplicate_resource(self, mock_req): + """Test setup with duplicate resources.""" + mock_req.get("http://localhost", status_code=200) + with assert_setup_component(0, "sensor"): + assert setup_component( + self.hass, + "sensor", + { + "sensor": { + "platform": "rest", + "resource": "http://localhost", + "resource_template": "http://localhost", + } + }, + ) + @requests_mock.Mocker() def test_setup_get(self, mock_req): """Test setup with valid configuration.""" @@ -152,6 +186,7 @@ class TestRestSensor(unittest.TestCase): self.value_template = template("{{ value_json.key }}") self.value_template.hass = self.hass self.force_update = False + self.resource_template = None self.sensor = rest.RestSensor( self.hass, @@ -162,6 +197,7 @@ class TestRestSensor(unittest.TestCase): self.value_template, [], self.force_update, + self.resource_template, ) def tearDown(self): @@ -222,6 +258,7 @@ class TestRestSensor(unittest.TestCase): None, [], self.force_update, + self.resource_template, ) self.sensor.update() assert "plain_state" == self.sensor.state @@ -242,6 +279,7 @@ class TestRestSensor(unittest.TestCase): None, ["key"], self.force_update, + self.resource_template, ) self.sensor.update() assert "some_json_value" == self.sensor.device_state_attributes["key"] @@ -261,6 +299,7 @@ class TestRestSensor(unittest.TestCase): None, ["key"], self.force_update, + self.resource_template, ) self.sensor.update() assert {} == self.sensor.device_state_attributes @@ -282,6 +321,7 @@ class TestRestSensor(unittest.TestCase): None, ["key"], self.force_update, + self.resource_template, ) self.sensor.update() assert {} == self.sensor.device_state_attributes @@ -303,6 +343,7 @@ class TestRestSensor(unittest.TestCase): None, ["key"], self.force_update, + self.resource_template, ) self.sensor.update() assert {} == self.sensor.device_state_attributes @@ -326,6 +367,7 @@ class TestRestSensor(unittest.TestCase): self.value_template, ["key"], self.force_update, + self.resource_template, ) self.sensor.update()