From 3f4ce70414cc24f69d2a22f2dfecea35cdd8b6a9 Mon Sep 17 00:00:00 2001 From: Phil Bruckner Date: Tue, 2 Jul 2019 10:29:38 -0500 Subject: [PATCH] Fix 'same state' monitoring in state trigger (#24904) --- homeassistant/components/automation/state.py | 2 +- tests/components/automation/test_state.py | 101 +++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/automation/state.py b/homeassistant/components/automation/state.py index f4d7f69c07a..a627566ca1c 100644 --- a/homeassistant/components/automation/state.py +++ b/homeassistant/components/automation/state.py @@ -58,7 +58,7 @@ async def async_trigger(hass, config, action, automation_info): unsub_track_same[entity] = async_track_same_state( hass, time_delta, call_action, lambda _, _2, to_state: to_state.state == to_s.state, - entity_ids=entity_id) + entity_ids=entity) unsub = async_track_state_change( hass, entity_id, state_automation_listener, from_state, to_state) diff --git a/tests/components/automation/test_state.py b/tests/components/automation/test_state.py index 4ce695afeb9..0c2797c96d4 100644 --- a/tests/components/automation/test_state.py +++ b/tests/components/automation/test_state.py @@ -648,3 +648,104 @@ async def test_wait_template_with_trigger(hass, calls): assert 1 == len(calls) assert 'state - test.entity - hello - world' == \ calls[0].data['some'] + + +async def test_if_fires_on_entities_change_no_overlap(hass, calls): + """Test for firing on entities change with no overlap.""" + assert await async_setup_component(hass, automation.DOMAIN, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'state', + 'entity_id': [ + 'test.entity_1', + 'test.entity_2', + ], + 'to': 'world', + 'for': { + 'seconds': 5 + }, + }, + 'action': { + 'service': 'test.automation', + 'data_template': { + 'some': '{{ trigger.entity_id }}', + }, + } + } + }) + await hass.async_block_till_done() + + utcnow = dt_util.utcnow() + with patch('homeassistant.core.dt_util.utcnow') as mock_utcnow: + mock_utcnow.return_value = utcnow + hass.states.async_set('test.entity_1', 'world') + await hass.async_block_till_done() + mock_utcnow.return_value += timedelta(seconds=10) + async_fire_time_changed(hass, mock_utcnow.return_value) + await hass.async_block_till_done() + assert 1 == len(calls) + assert 'test.entity_1' == calls[0].data['some'] + + hass.states.async_set('test.entity_2', 'world') + await hass.async_block_till_done() + mock_utcnow.return_value += timedelta(seconds=10) + async_fire_time_changed(hass, mock_utcnow.return_value) + await hass.async_block_till_done() + assert 2 == len(calls) + assert 'test.entity_2' == calls[1].data['some'] + + +async def test_if_fires_on_entities_change_overlap(hass, calls): + """Test for firing on entities change with overlap.""" + assert await async_setup_component(hass, automation.DOMAIN, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'state', + 'entity_id': [ + 'test.entity_1', + 'test.entity_2', + ], + 'to': 'world', + 'for': { + 'seconds': 5 + }, + }, + 'action': { + 'service': 'test.automation', + 'data_template': { + 'some': '{{ trigger.entity_id }}', + }, + } + } + }) + await hass.async_block_till_done() + + utcnow = dt_util.utcnow() + with patch('homeassistant.core.dt_util.utcnow') as mock_utcnow: + mock_utcnow.return_value = utcnow + hass.states.async_set('test.entity_1', 'world') + await hass.async_block_till_done() + mock_utcnow.return_value += timedelta(seconds=1) + async_fire_time_changed(hass, mock_utcnow.return_value) + hass.states.async_set('test.entity_2', 'world') + await hass.async_block_till_done() + mock_utcnow.return_value += timedelta(seconds=1) + async_fire_time_changed(hass, mock_utcnow.return_value) + hass.states.async_set('test.entity_2', 'hello') + await hass.async_block_till_done() + mock_utcnow.return_value += timedelta(seconds=1) + async_fire_time_changed(hass, mock_utcnow.return_value) + hass.states.async_set('test.entity_2', 'world') + await hass.async_block_till_done() + assert 0 == len(calls) + mock_utcnow.return_value += timedelta(seconds=3) + async_fire_time_changed(hass, mock_utcnow.return_value) + await hass.async_block_till_done() + assert 1 == len(calls) + assert 'test.entity_1' == calls[0].data['some'] + + mock_utcnow.return_value += timedelta(seconds=3) + async_fire_time_changed(hass, mock_utcnow.return_value) + await hass.async_block_till_done() + assert 2 == len(calls) + assert 'test.entity_2' == calls[1].data['some']