Set mqtt binary_sensor unavailable if expire_after specified (#34259)

* Set self._expired=True if expire_after specified

* Added test_expiration_on_discovery_and_discovery_update_of_binary_sensor to mqtt/test_binary_sensor.py

* Fixed flake8 error

* Fixed isort error
This commit is contained in:
Tom 2020-04-22 23:29:49 +02:00 committed by GitHub
parent a8cd7203df
commit d6ab36bf8e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 98 additions and 6 deletions

View file

@ -119,7 +119,11 @@ class MqttBinarySensor(
self._sub_state = None
self._expiration_trigger = None
self._delay_listener = None
self._expired = None
expire_after = config.get(CONF_EXPIRE_AFTER)
if expire_after is not None and expire_after > 0:
self._expired = True
else:
self._expired = None
device_config = config.get(CONF_DEVICE)
MqttAttributes.__init__(self, config)

View file

@ -4,7 +4,8 @@ from datetime import datetime, timedelta
import json
from unittest.mock import patch
from homeassistant.components import binary_sensor
from homeassistant.components import binary_sensor, mqtt
from homeassistant.components.mqtt.discovery import async_start
from homeassistant.const import (
EVENT_STATE_CHANGED,
STATE_OFF,
@ -37,7 +38,11 @@ from .test_common import (
help_test_update_with_json_attrs_not_dict,
)
from tests.common import async_fire_mqtt_message, async_fire_time_changed
from tests.common import (
MockConfigEntry,
async_fire_mqtt_message,
async_fire_time_changed,
)
DEFAULT_CONFIG = {
binary_sensor.DOMAIN: {
@ -70,8 +75,9 @@ async def test_setting_sensor_value_expires_availability_topic(hass, mqtt_mock,
async_fire_mqtt_message(hass, "availability-topic", "online")
# State should be unavailable since expire_after is defined and > 0
state = hass.states.get("binary_sensor.test")
assert state.state != STATE_UNAVAILABLE
assert state.state == STATE_UNAVAILABLE
await expires_helper(hass, mqtt_mock, caplog)
@ -92,15 +98,15 @@ async def test_setting_sensor_value_expires(hass, mqtt_mock, caplog):
},
)
# State should be unavailable since expire_after is defined and > 0
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_OFF
assert state.state == STATE_UNAVAILABLE
await expires_helper(hass, mqtt_mock, caplog)
async def expires_helper(hass, mqtt_mock, caplog):
"""Run the basic expiry code."""
now = datetime(2017, 1, 1, 1, tzinfo=dt_util.UTC)
with patch(("homeassistant.helpers.event.dt_util.utcnow"), return_value=now):
async_fire_time_changed(hass, now)
@ -460,6 +466,88 @@ async def test_discovery_update_binary_sensor(hass, mqtt_mock, caplog):
)
async def test_expiration_on_discovery_and_discovery_update_of_binary_sensor(
hass, mqtt_mock, caplog
):
"""Test that binary_sensor with expire_after set behaves correctly on discovery and discovery update."""
entry = MockConfigEntry(domain=mqtt.DOMAIN)
await async_start(hass, "homeassistant", {}, entry)
config = {
"name": "Test",
"state_topic": "test-topic",
"expire_after": 4,
"force_update": True,
}
config_msg = json.dumps(config)
# Set time and publish config message to create binary_sensor via discovery with 4 s expiry
now = datetime(2017, 1, 1, 1, tzinfo=dt_util.UTC)
with patch(("homeassistant.helpers.event.dt_util.utcnow"), return_value=now):
async_fire_time_changed(hass, now)
async_fire_mqtt_message(
hass, "homeassistant/binary_sensor/bla/config", config_msg
)
await hass.async_block_till_done()
# Test that binary_sensor is not available
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_UNAVAILABLE
# Publish state message
with patch(("homeassistant.helpers.event.dt_util.utcnow"), return_value=now):
async_fire_mqtt_message(hass, "test-topic", "ON")
await hass.async_block_till_done()
# Test that binary_sensor has correct state
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_ON
# Advance +3 seconds
now = now + timedelta(seconds=3)
with patch(("homeassistant.helpers.event.dt_util.utcnow"), return_value=now):
async_fire_time_changed(hass, now)
await hass.async_block_till_done()
# binary_sensor is not yet expired
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_ON
# Resend config message to update discovery
with patch(("homeassistant.helpers.event.dt_util.utcnow"), return_value=now):
async_fire_time_changed(hass, now)
async_fire_mqtt_message(
hass, "homeassistant/binary_sensor/bla/config", config_msg
)
await hass.async_block_till_done()
# Test that binary_sensor has not expired
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_ON
# Add +2 seconds
now = now + timedelta(seconds=2)
with patch(("homeassistant.helpers.event.dt_util.utcnow"), return_value=now):
async_fire_time_changed(hass, now)
await hass.async_block_till_done()
# Test that binary_sensor has expired
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_UNAVAILABLE
# Resend config message to update discovery
with patch(("homeassistant.helpers.event.dt_util.utcnow"), return_value=now):
async_fire_mqtt_message(
hass, "homeassistant/binary_sensor/bla/config", config_msg
)
await hass.async_block_till_done()
# Test that binary_sensor is still expired
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_UNAVAILABLE
async def test_discovery_broken(hass, mqtt_mock, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer",' ' "off_delay": -1 }'