diff --git a/homeassistant/components/automation/template.py b/homeassistant/components/automation/template.py index c3d7c02aedd..6a60c855781 100644 --- a/homeassistant/components/automation/template.py +++ b/homeassistant/components/automation/template.py @@ -35,6 +35,23 @@ async def async_trigger(hass, config, action, automation_info): """Listen for state changes and calls action.""" nonlocal unsub_track_same + @callback + def call_action(): + """Call action with right context.""" + hass.async_run_job(action({ + 'trigger': { + 'platform': 'template', + 'entity_id': entity_id, + 'from_state': from_s, + 'to_state': to_s, + 'for': time_delta if not time_delta else period + }, + }, context=(to_s.context if to_s else None))) + + if not time_delta: + call_action() + return + variables = { 'trigger': { 'platform': 'template', @@ -44,16 +61,6 @@ async def async_trigger(hass, config, action, automation_info): }, } - @callback - def call_action(): - """Call action with right context.""" - hass.async_run_job(action( - variables, context=(to_s.context if to_s else None))) - - if not time_delta: - call_action() - return - try: if isinstance(time_delta, template.Template): period = vol.All( diff --git a/tests/components/automation/test_template.py b/tests/components/automation/test_template.py index 48503acbc5f..db61bab8e4c 100644 --- a/tests/components/automation/test_template.py +++ b/tests/components/automation/test_template.py @@ -251,7 +251,7 @@ async def test_if_fires_on_change_with_template_advanced(hass, calls): 'some': '{{ trigger.%s }}' % '}} - {{ trigger.'.join(( 'platform', 'entity_id', 'from_state.state', - 'to_state.state')) + 'to_state.state', 'for')) }, } } @@ -263,7 +263,7 @@ async def test_if_fires_on_change_with_template_advanced(hass, calls): await hass.async_block_till_done() assert 1 == len(calls) assert calls[0].context.parent_id == context.id - assert 'template - test.entity - hello - world' == \ + assert 'template - test.entity - hello - world - None' == \ calls[0].data['some'] @@ -424,7 +424,7 @@ async def test_wait_template_with_trigger(hass, calls): 'some': '{{ trigger.%s }}' % '}} - {{ trigger.'.join(( 'platform', 'entity_id', 'from_state.state', - 'to_state.state')) + 'to_state.state', 'for')) }} ], } @@ -437,7 +437,7 @@ async def test_wait_template_with_trigger(hass, calls): hass.states.async_set('test.entity', 'hello') await hass.async_block_till_done() assert 1 == len(calls) - assert 'template - test.entity - hello - world' == \ + assert 'template - test.entity - hello - world - None' == \ calls[0].data['some'] @@ -466,6 +466,122 @@ async def test_if_fires_on_change_with_for(hass, calls): assert 1 == len(calls) +async def test_if_fires_on_change_with_for_advanced(hass, calls): + """Test for firing on change with for advanced.""" + context = Context() + assert await async_setup_component(hass, automation.DOMAIN, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'template', + 'value_template': '{{ is_state("test.entity", "world") }}', + 'for': { + 'seconds': 5 + }, + }, + 'action': { + 'service': 'test.automation', + 'data_template': { + 'some': + '{{ trigger.%s }}' % '}} - {{ trigger.'.join(( + 'platform', 'entity_id', 'from_state.state', + 'to_state.state', 'for')) + }, + } + } + }) + + await hass.async_block_till_done() + + hass.states.async_set('test.entity', 'world', context=context) + await hass.async_block_till_done() + assert 0 == len(calls) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10)) + await hass.async_block_till_done() + assert 1 == len(calls) + assert calls[0].context.parent_id == context.id + assert 'template - test.entity - hello - world - 0:00:05' == \ + calls[0].data['some'] + + +async def test_if_fires_on_change_with_for_0(hass, calls): + """Test for firing on change with for: 0.""" + assert await async_setup_component(hass, automation.DOMAIN, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'template', + 'value_template': "{{ is_state('test.entity', 'world') }}", + 'for': { + 'seconds': 0 + }, + }, + 'action': { + 'service': 'test.automation' + } + } + }) + + hass.states.async_set('test.entity', 'world') + await hass.async_block_till_done() + assert 1 == len(calls) + + +async def test_if_fires_on_change_with_for_0_advanced(hass, calls): + """Test for firing on change with for: 0 advanced.""" + context = Context() + assert await async_setup_component(hass, automation.DOMAIN, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'template', + 'value_template': '{{ is_state("test.entity", "world") }}', + 'for': { + 'seconds': 0 + }, + }, + 'action': { + 'service': 'test.automation', + 'data_template': { + 'some': + '{{ trigger.%s }}' % '}} - {{ trigger.'.join(( + 'platform', 'entity_id', 'from_state.state', + 'to_state.state', 'for')) + }, + } + } + }) + + await hass.async_block_till_done() + + hass.states.async_set('test.entity', 'world', context=context) + await hass.async_block_till_done() + assert 1 == len(calls) + assert calls[0].context.parent_id == context.id + assert 'template - test.entity - hello - world - 0:00:00' == \ + calls[0].data['some'] + + +async def test_if_fires_on_change_with_for_2(hass, calls): + """Test for firing on change with for.""" + assert await async_setup_component(hass, automation.DOMAIN, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'template', + 'value_template': "{{ is_state('test.entity', 'world') }}", + 'for': 5, + }, + 'action': { + 'service': 'test.automation' + } + } + }) + + hass.states.async_set('test.entity', 'world') + await hass.async_block_till_done() + assert 0 == len(calls) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10)) + await hass.async_block_till_done() + assert 1 == len(calls) + + async def test_if_not_fires_on_change_with_for(hass, calls): """Test for firing on change with for.""" assert await async_setup_component(hass, automation.DOMAIN, {