Add for option for template triggers (#24330)
This commit is contained in:
parent
d858e1be05
commit
61dabae6ab
2 changed files with 133 additions and 12 deletions
|
@ -4,8 +4,10 @@ import logging
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.const import CONF_VALUE_TEMPLATE, CONF_PLATFORM
|
||||
from homeassistant.helpers.event import async_track_template
|
||||
from homeassistant.const import CONF_VALUE_TEMPLATE, CONF_PLATFORM, CONF_FOR
|
||||
from homeassistant.helpers import condition
|
||||
from homeassistant.helpers.event import (
|
||||
async_track_same_state, async_track_template)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -13,6 +15,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||
TRIGGER_SCHEMA = IF_ACTION_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_PLATFORM): 'template',
|
||||
vol.Required(CONF_VALUE_TEMPLATE): cv.template,
|
||||
vol.Optional(CONF_FOR): vol.All(cv.time_period, cv.positive_timedelta),
|
||||
})
|
||||
|
||||
|
||||
|
@ -20,10 +23,17 @@ async def async_trigger(hass, config, action, automation_info):
|
|||
"""Listen for state changes based on configuration."""
|
||||
value_template = config.get(CONF_VALUE_TEMPLATE)
|
||||
value_template.hass = hass
|
||||
time_delta = config.get(CONF_FOR)
|
||||
unsub_track_same = None
|
||||
|
||||
@callback
|
||||
def template_listener(entity_id, from_s, to_s):
|
||||
"""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',
|
||||
|
@ -33,4 +43,24 @@ async def async_trigger(hass, config, action, automation_info):
|
|||
},
|
||||
}, context=(to_s.context if to_s else None)))
|
||||
|
||||
return async_track_template(hass, value_template, template_listener)
|
||||
if not time_delta:
|
||||
call_action()
|
||||
return
|
||||
|
||||
unsub_track_same = async_track_same_state(
|
||||
hass, time_delta, call_action,
|
||||
lambda _, _2, _3: condition.async_template(hass, value_template),
|
||||
value_template.extract_entities())
|
||||
|
||||
unsub = async_track_template(
|
||||
hass, value_template, template_listener)
|
||||
|
||||
@callback
|
||||
def async_remove():
|
||||
"""Remove state listeners async."""
|
||||
unsub()
|
||||
if unsub_track_same:
|
||||
# pylint: disable=not-callable
|
||||
unsub_track_same()
|
||||
|
||||
return async_remove
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
"""The tests for the Template automation."""
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import Context
|
||||
from homeassistant.setup import async_setup_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
import homeassistant.components.automation as automation
|
||||
|
||||
from tests.common import (assert_setup_component, mock_component)
|
||||
from tests.common import (
|
||||
async_fire_time_changed, assert_setup_component, mock_component)
|
||||
from tests.components.automation import common
|
||||
from tests.common import async_mock_service
|
||||
|
||||
|
@ -434,3 +438,90 @@ async def test_wait_template_with_trigger(hass, calls):
|
|||
assert 1 == len(calls)
|
||||
assert 'template - test.entity - hello - world' == \
|
||||
calls[0].data['some']
|
||||
|
||||
|
||||
async def test_if_fires_on_change_with_for(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': {
|
||||
'seconds': 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, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
'value_template': "{{ is_state('test.entity', 'world') }}",
|
||||
'for': {
|
||||
'seconds': 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=4))
|
||||
await hass.async_block_till_done()
|
||||
assert 0 == len(calls)
|
||||
hass.states.async_set('test.entity', 'hello')
|
||||
await hass.async_block_till_done()
|
||||
assert 0 == len(calls)
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=6))
|
||||
await hass.async_block_till_done()
|
||||
assert 0 == len(calls)
|
||||
|
||||
|
||||
async def test_if_not_fires_when_turned_off_with_for(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': {
|
||||
'seconds': 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=4))
|
||||
await hass.async_block_till_done()
|
||||
assert 0 == len(calls)
|
||||
await common.async_turn_off(hass)
|
||||
await hass.async_block_till_done()
|
||||
assert 0 == len(calls)
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=6))
|
||||
await hass.async_block_till_done()
|
||||
assert 0 == len(calls)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue