mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Add an option to template delay_on/off in template binary sensor (#43259)
This commit is contained in:
parent
14aba1f9de
commit
6a5546afc1
@ -46,8 +46,8 @@ SENSOR_SCHEMA = vol.All(
|
|||||||
vol.Optional(ATTR_FRIENDLY_NAME): cv.string,
|
vol.Optional(ATTR_FRIENDLY_NAME): cv.string,
|
||||||
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
||||||
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
|
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
|
||||||
vol.Optional(CONF_DELAY_ON): cv.positive_time_period,
|
vol.Optional(CONF_DELAY_ON): vol.Any(cv.positive_time_period, cv.template),
|
||||||
vol.Optional(CONF_DELAY_OFF): cv.positive_time_period,
|
vol.Optional(CONF_DELAY_OFF): vol.Any(cv.positive_time_period, cv.template),
|
||||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
@ -71,8 +71,8 @@ async def _async_create_entities(hass, config):
|
|||||||
|
|
||||||
friendly_name = device_config.get(ATTR_FRIENDLY_NAME, device)
|
friendly_name = device_config.get(ATTR_FRIENDLY_NAME, device)
|
||||||
device_class = device_config.get(CONF_DEVICE_CLASS)
|
device_class = device_config.get(CONF_DEVICE_CLASS)
|
||||||
delay_on = device_config.get(CONF_DELAY_ON)
|
delay_on_raw = device_config.get(CONF_DELAY_ON)
|
||||||
delay_off = device_config.get(CONF_DELAY_OFF)
|
delay_off_raw = device_config.get(CONF_DELAY_OFF)
|
||||||
unique_id = device_config.get(CONF_UNIQUE_ID)
|
unique_id = device_config.get(CONF_UNIQUE_ID)
|
||||||
|
|
||||||
sensors.append(
|
sensors.append(
|
||||||
@ -85,8 +85,8 @@ async def _async_create_entities(hass, config):
|
|||||||
icon_template,
|
icon_template,
|
||||||
entity_picture_template,
|
entity_picture_template,
|
||||||
availability_template,
|
availability_template,
|
||||||
delay_on,
|
delay_on_raw,
|
||||||
delay_off,
|
delay_off_raw,
|
||||||
attribute_templates,
|
attribute_templates,
|
||||||
unique_id,
|
unique_id,
|
||||||
)
|
)
|
||||||
@ -115,8 +115,8 @@ class BinarySensorTemplate(TemplateEntity, BinarySensorEntity):
|
|||||||
icon_template,
|
icon_template,
|
||||||
entity_picture_template,
|
entity_picture_template,
|
||||||
availability_template,
|
availability_template,
|
||||||
delay_on,
|
delay_on_raw,
|
||||||
delay_off,
|
delay_off_raw,
|
||||||
attribute_templates,
|
attribute_templates,
|
||||||
unique_id,
|
unique_id,
|
||||||
):
|
):
|
||||||
@ -133,8 +133,10 @@ class BinarySensorTemplate(TemplateEntity, BinarySensorEntity):
|
|||||||
self._template = value_template
|
self._template = value_template
|
||||||
self._state = None
|
self._state = None
|
||||||
self._delay_cancel = None
|
self._delay_cancel = None
|
||||||
self._delay_on = delay_on
|
self._delay_on = None
|
||||||
self._delay_off = delay_off
|
self._delay_on_raw = delay_on_raw
|
||||||
|
self._delay_off = None
|
||||||
|
self._delay_off_raw = delay_off_raw
|
||||||
self._unique_id = unique_id
|
self._unique_id = unique_id
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
@ -142,6 +144,22 @@ class BinarySensorTemplate(TemplateEntity, BinarySensorEntity):
|
|||||||
|
|
||||||
self.add_template_attribute("_state", self._template, None, self._update_state)
|
self.add_template_attribute("_state", self._template, None, self._update_state)
|
||||||
|
|
||||||
|
if self._delay_on_raw is not None:
|
||||||
|
try:
|
||||||
|
self._delay_on = cv.positive_time_period(self._delay_on_raw)
|
||||||
|
except vol.Invalid:
|
||||||
|
self.add_template_attribute(
|
||||||
|
"_delay_on", self._delay_on_raw, cv.positive_time_period
|
||||||
|
)
|
||||||
|
|
||||||
|
if self._delay_off_raw is not None:
|
||||||
|
try:
|
||||||
|
self._delay_off = cv.positive_time_period(self._delay_off_raw)
|
||||||
|
except vol.Invalid:
|
||||||
|
self.add_template_attribute(
|
||||||
|
"_delay_off", self._delay_off_raw, cv.positive_time_period
|
||||||
|
)
|
||||||
|
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@ -383,6 +383,269 @@ async def test_template_delay_off(hass):
|
|||||||
assert state.state == "on"
|
assert state.state == "on"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_template_with_templated_delay_on(hass):
|
||||||
|
"""Test binary sensor template with template delay on."""
|
||||||
|
config = {
|
||||||
|
"binary_sensor": {
|
||||||
|
"platform": "template",
|
||||||
|
"sensors": {
|
||||||
|
"test": {
|
||||||
|
"friendly_name": "virtual thingy",
|
||||||
|
"value_template": "{{ states.sensor.test_state.state == 'on' }}",
|
||||||
|
"device_class": "motion",
|
||||||
|
"delay_on": '{{ ({ "seconds": 6 / 2 }) }}',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await setup.async_setup_component(hass, binary_sensor.DOMAIN, config)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
await hass.async_start()
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test_state", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
future = dt_util.utcnow() + timedelta(seconds=3)
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
# check with time changes
|
||||||
|
hass.states.async_set("sensor.test_state", "off")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test_state", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test_state", "off")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
future = dt_util.utcnow() + timedelta(seconds=3)
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_template_with_templated_delay_off(hass):
|
||||||
|
"""Test binary sensor template with template delay off."""
|
||||||
|
config = {
|
||||||
|
"binary_sensor": {
|
||||||
|
"platform": "template",
|
||||||
|
"sensors": {
|
||||||
|
"test": {
|
||||||
|
"friendly_name": "virtual thingy",
|
||||||
|
"value_template": "{{ states.sensor.test_state.state == 'on' }}",
|
||||||
|
"device_class": "motion",
|
||||||
|
"delay_off": '{{ ({ "seconds": 6 / 2 }) }}',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hass.states.async_set("sensor.test_state", "on")
|
||||||
|
await setup.async_setup_component(hass, binary_sensor.DOMAIN, config)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
await hass.async_start()
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test_state", "off")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
future = dt_util.utcnow() + timedelta(seconds=3)
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
# check with time changes
|
||||||
|
hass.states.async_set("sensor.test_state", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test_state", "off")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test_state", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
future = dt_util.utcnow() + timedelta(seconds=3)
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_template_with_delay_on_based_on_input(hass):
|
||||||
|
"""Test binary sensor template with template delay on based on input number."""
|
||||||
|
config = {
|
||||||
|
"binary_sensor": {
|
||||||
|
"platform": "template",
|
||||||
|
"sensors": {
|
||||||
|
"test": {
|
||||||
|
"friendly_name": "virtual thingy",
|
||||||
|
"value_template": "{{ states.sensor.test_state.state == 'on' }}",
|
||||||
|
"device_class": "motion",
|
||||||
|
"delay_on": '{{ ({ "seconds": states("input_number.delay")|int }) }}',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await setup.async_setup_component(hass, binary_sensor.DOMAIN, config)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
await hass.async_start()
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test_state", "off")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
hass.states.async_set("input_number.delay", 3)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test_state", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
future = dt_util.utcnow() + timedelta(seconds=3)
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
# set input to 4 seconds
|
||||||
|
hass.states.async_set("sensor.test_state", "off")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
hass.states.async_set("input_number.delay", 4)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test_state", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
future = dt_util.utcnow() + timedelta(seconds=2)
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
future = dt_util.utcnow() + timedelta(seconds=4)
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_template_with_delay_off_based_on_input(hass):
|
||||||
|
"""Test binary sensor template with template delay off based on input number."""
|
||||||
|
config = {
|
||||||
|
"binary_sensor": {
|
||||||
|
"platform": "template",
|
||||||
|
"sensors": {
|
||||||
|
"test": {
|
||||||
|
"friendly_name": "virtual thingy",
|
||||||
|
"value_template": "{{ states.sensor.test_state.state == 'on' }}",
|
||||||
|
"device_class": "motion",
|
||||||
|
"delay_off": '{{ ({ "seconds": states("input_number.delay")|int }) }}',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await setup.async_setup_component(hass, binary_sensor.DOMAIN, config)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
await hass.async_start()
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test_state", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
hass.states.async_set("input_number.delay", 3)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test_state", "off")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
future = dt_util.utcnow() + timedelta(seconds=3)
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
# set input to 4 seconds
|
||||||
|
hass.states.async_set("sensor.test_state", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
hass.states.async_set("input_number.delay", 4)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.test_state", "off")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
future = dt_util.utcnow() + timedelta(seconds=2)
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "on"
|
||||||
|
|
||||||
|
future = dt_util.utcnow() + timedelta(seconds=4)
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.test")
|
||||||
|
assert state.state == "off"
|
||||||
|
|
||||||
|
|
||||||
async def test_available_without_availability_template(hass):
|
async def test_available_without_availability_template(hass):
|
||||||
"""Ensure availability is true without an availability_template."""
|
"""Ensure availability is true without an availability_template."""
|
||||||
config = {
|
config = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user