mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Fix delay_on
and delay_off
restarting when a new trigger occurs during the delay (#145050)
This commit is contained in:
parent
0362012bb3
commit
3e0aab55a8
@ -352,6 +352,8 @@ class TriggerBinarySensorEntity(TriggerEntity, BinarySensorEntity, RestoreEntity
|
|||||||
self._to_render_simple.append(key)
|
self._to_render_simple.append(key)
|
||||||
self._parse_result.add(key)
|
self._parse_result.add(key)
|
||||||
|
|
||||||
|
self._last_delay_from: bool | None = None
|
||||||
|
self._last_delay_to: bool | None = None
|
||||||
self._delay_cancel: CALLBACK_TYPE | None = None
|
self._delay_cancel: CALLBACK_TYPE | None = None
|
||||||
self._auto_off_cancel: CALLBACK_TYPE | None = None
|
self._auto_off_cancel: CALLBACK_TYPE | None = None
|
||||||
self._auto_off_time: datetime | None = None
|
self._auto_off_time: datetime | None = None
|
||||||
@ -388,6 +390,20 @@ class TriggerBinarySensorEntity(TriggerEntity, BinarySensorEntity, RestoreEntity
|
|||||||
"""Handle update of the data."""
|
"""Handle update of the data."""
|
||||||
self._process_data()
|
self._process_data()
|
||||||
|
|
||||||
|
raw = self._rendered.get(CONF_STATE)
|
||||||
|
state = template.result_as_boolean(raw)
|
||||||
|
|
||||||
|
key = CONF_DELAY_ON if state else CONF_DELAY_OFF
|
||||||
|
delay = self._rendered.get(key) or self._config.get(key)
|
||||||
|
|
||||||
|
if (
|
||||||
|
self._delay_cancel
|
||||||
|
and delay
|
||||||
|
and self._attr_is_on == self._last_delay_from
|
||||||
|
and state == self._last_delay_to
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
if self._delay_cancel:
|
if self._delay_cancel:
|
||||||
self._delay_cancel()
|
self._delay_cancel()
|
||||||
self._delay_cancel = None
|
self._delay_cancel = None
|
||||||
@ -401,12 +417,6 @@ class TriggerBinarySensorEntity(TriggerEntity, BinarySensorEntity, RestoreEntity
|
|||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
return
|
return
|
||||||
|
|
||||||
raw = self._rendered.get(CONF_STATE)
|
|
||||||
state = template.result_as_boolean(raw)
|
|
||||||
|
|
||||||
key = CONF_DELAY_ON if state else CONF_DELAY_OFF
|
|
||||||
delay = self._rendered.get(key) or self._config.get(key)
|
|
||||||
|
|
||||||
# state without delay. None means rendering failed.
|
# state without delay. None means rendering failed.
|
||||||
if self._attr_is_on == state or state is None or delay is None:
|
if self._attr_is_on == state or state is None or delay is None:
|
||||||
self._set_state(state)
|
self._set_state(state)
|
||||||
@ -422,6 +432,8 @@ class TriggerBinarySensorEntity(TriggerEntity, BinarySensorEntity, RestoreEntity
|
|||||||
return
|
return
|
||||||
|
|
||||||
# state with delay. Cancelled if new trigger received
|
# state with delay. Cancelled if new trigger received
|
||||||
|
self._last_delay_from = self._attr_is_on
|
||||||
|
self._last_delay_to = state
|
||||||
self._delay_cancel = async_call_later(
|
self._delay_cancel = async_call_later(
|
||||||
self.hass, delay.total_seconds(), partial(self._set_state, state)
|
self.hass, delay.total_seconds(), partial(self._set_state, state)
|
||||||
)
|
)
|
||||||
|
@ -1225,6 +1225,62 @@ async def test_template_with_trigger_templated_delay_on(hass: HomeAssistant) ->
|
|||||||
assert state.state == STATE_OFF
|
assert state.state == STATE_OFF
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(("count", "domain"), [(1, "template")])
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("config", "delay_state"),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"template": {
|
||||||
|
"trigger": {"platform": "event", "event_type": "test_event"},
|
||||||
|
"binary_sensor": {
|
||||||
|
"name": "test",
|
||||||
|
"state": "{{ trigger.event.data.beer == 2 }}",
|
||||||
|
"device_class": "motion",
|
||||||
|
"delay_on": '{{ ({ "seconds": 10 }) }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
STATE_ON,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"template": {
|
||||||
|
"trigger": {"platform": "event", "event_type": "test_event"},
|
||||||
|
"binary_sensor": {
|
||||||
|
"name": "test",
|
||||||
|
"state": "{{ trigger.event.data.beer != 2 }}",
|
||||||
|
"device_class": "motion",
|
||||||
|
"delay_off": '{{ ({ "seconds": 10 }) }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
STATE_OFF,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.usefixtures("start_ha")
|
||||||
|
async def test_trigger_template_delay_with_multiple_triggers(
|
||||||
|
hass: HomeAssistant, delay_state: str
|
||||||
|
) -> None:
|
||||||
|
"""Test trigger based binary sensor with multiple triggers occurring during the delay."""
|
||||||
|
future = dt_util.utcnow()
|
||||||
|
for _ in range(10):
|
||||||
|
# State should still be unknown
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == STATE_UNKNOWN
|
||||||
|
|
||||||
|
hass.bus.async_fire("test_event", {"beer": 2}, context=Context())
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
future += timedelta(seconds=1)
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == delay_state
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(("count", "domain"), [(1, "template")])
|
@pytest.mark.parametrize(("count", "domain"), [(1, "template")])
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"config",
|
"config",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user