From e5c97fdcab35f391b9955de104b87fdf1868a6d7 Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Mon, 29 Oct 2018 08:03:10 +0100 Subject: [PATCH] Extract entity ids from all templates (#17902) --- .../components/binary_sensor/template.py | 39 +++++++++++++------ .../components/binary_sensor/test_template.py | 28 ++++++++++++- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/binary_sensor/template.py b/homeassistant/components/binary_sensor/template.py index 89547dffbc9..1f386fc2293 100644 --- a/homeassistant/components/binary_sensor/template.py +++ b/homeassistant/components/binary_sensor/template.py @@ -15,7 +15,7 @@ from homeassistant.components.binary_sensor import ( from homeassistant.const import ( ATTR_FRIENDLY_NAME, ATTR_ENTITY_ID, CONF_VALUE_TEMPLATE, CONF_ICON_TEMPLATE, CONF_ENTITY_PICTURE_TEMPLATE, - CONF_SENSORS, CONF_DEVICE_CLASS, EVENT_HOMEASSISTANT_START) + CONF_SENSORS, CONF_DEVICE_CLASS, EVENT_HOMEASSISTANT_START, MATCH_ALL) from homeassistant.exceptions import TemplateError import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import async_generate_entity_id @@ -55,22 +55,37 @@ async def async_setup_platform(hass, config, async_add_entities, icon_template = device_config.get(CONF_ICON_TEMPLATE) entity_picture_template = device_config.get( CONF_ENTITY_PICTURE_TEMPLATE) - entity_ids = (device_config.get(ATTR_ENTITY_ID) or - value_template.extract_entities()) + entity_ids = set() + manual_entity_ids = device_config.get(ATTR_ENTITY_ID) + + for template in ( + value_template, + icon_template, + entity_picture_template, + ): + if template is None: + continue + template.hass = hass + + if manual_entity_ids is not None: + continue + + template_entity_ids = template.extract_entities() + if template_entity_ids == MATCH_ALL: + entity_ids = MATCH_ALL + elif entity_ids != MATCH_ALL: + entity_ids |= set(template_entity_ids) + + if manual_entity_ids is not None: + entity_ids = manual_entity_ids + elif entity_ids != MATCH_ALL: + entity_ids = list(entity_ids) + friendly_name = device_config.get(ATTR_FRIENDLY_NAME, device) device_class = device_config.get(CONF_DEVICE_CLASS) delay_on = device_config.get(CONF_DELAY_ON) delay_off = device_config.get(CONF_DELAY_OFF) - if value_template is not None: - value_template.hass = hass - - if icon_template is not None: - icon_template.hass = hass - - if entity_picture_template is not None: - entity_picture_template.hass = hass - sensors.append( BinarySensorTemplate( hass, device, friendly_name, device_class, value_template, diff --git a/tests/components/binary_sensor/test_template.py b/tests/components/binary_sensor/test_template.py index 7307b222436..f448bcc47a2 100644 --- a/tests/components/binary_sensor/test_template.py +++ b/tests/components/binary_sensor/test_template.py @@ -106,7 +106,7 @@ class TestBinarySensorTemplate(unittest.TestCase): 'platform': 'template', 'sensors': { 'test_template_sensor': { - 'value_template': "State", + 'value_template': "{{ states.sensor.xyz.state }}", 'icon_template': "{% if " "states.binary_sensor.test_state.state == " @@ -137,7 +137,7 @@ class TestBinarySensorTemplate(unittest.TestCase): 'platform': 'template', 'sensors': { 'test_template_sensor': { - 'value_template': "State", + 'value_template': "{{ states.sensor.xyz.state }}", 'entity_picture_template': "{% if " "states.binary_sensor.test_state.state == " @@ -160,6 +160,30 @@ class TestBinarySensorTemplate(unittest.TestCase): state = self.hass.states.get('binary_sensor.test_template_sensor') assert state.attributes['entity_picture'] == '/local/sensor.png' + @mock.patch('homeassistant.components.binary_sensor.template.' + 'BinarySensorTemplate._async_render') + def test_match_all(self, _async_render): + """Test MATCH_ALL in template.""" + with assert_setup_component(1): + assert setup.setup_component(self.hass, 'binary_sensor', { + 'binary_sensor': { + 'platform': 'template', + 'sensors': { + 'match_all_template_sensor': { + 'value_template': "{{ 42 }}", + }, + } + } + }) + + self.hass.start() + self.hass.block_till_done() + init_calls = len(_async_render.mock_calls) + + self.hass.states.set('sensor.any_state', 'update') + self.hass.block_till_done() + assert len(_async_render.mock_calls) > init_calls + def test_attributes(self): """Test the attributes.""" vs = run_callback_threadsafe(