core/tests/components/rflink/test_sensor.py

327 lines
10 KiB
Python

"""Test for RFlink sensor components.
Test setup of rflink sensor component/platform. Verify manual and
automatic sensor creation.
"""
import pytest
from homeassistant.components.rflink import (
CONF_RECONNECT_INTERVAL,
DATA_ENTITY_LOOKUP,
EVENT_KEY_COMMAND,
EVENT_KEY_SENSOR,
TMP_ENTITY,
)
from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass
from homeassistant.const import (
ATTR_ICON,
ATTR_UNIT_OF_MEASUREMENT,
PERCENTAGE,
STATE_UNKNOWN,
UnitOfPrecipitationDepth,
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant
from .test_init import mock_rflink
DOMAIN = "sensor"
CONFIG = {
"rflink": {
"port": "/dev/ttyABC0",
"ignore_devices": ["ignore_wildcard_*", "ignore_sensor"],
},
DOMAIN: {
"platform": "rflink",
"devices": {"test": {"name": "test", "sensor_type": "temperature"}},
},
}
async def test_default_setup(
hass: HomeAssistant, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test all basic functionality of the rflink sensor component."""
# setup mocking rflink module
event_callback, create, _, _ = await mock_rflink(hass, CONFIG, DOMAIN, monkeypatch)
# make sure arguments are passed
assert create.call_args_list[0][1]["ignore"]
# test default state of sensor loaded from config
config_sensor = hass.states.get("sensor.test")
assert config_sensor
assert config_sensor.state == "unknown"
assert (
config_sensor.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfTemperature.CELSIUS
)
# test event for config sensor
event_callback(
{
"id": "test",
"sensor": "temperature",
"value": 1,
"unit": UnitOfTemperature.CELSIUS,
}
)
await hass.async_block_till_done()
assert hass.states.get("sensor.test").state == "1"
# test event for new unconfigured sensor
event_callback(
{
"id": "test2",
"sensor": "temperature",
"value": 0,
"unit": UnitOfTemperature.CELSIUS,
}
)
await hass.async_block_till_done()
# test state of temp sensor
temp_sensor = hass.states.get("sensor.test2")
assert temp_sensor
assert temp_sensor.state == "0"
assert temp_sensor.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfTemperature.CELSIUS
assert (
ATTR_ICON not in temp_sensor.attributes
) # temperature uses SensorEntityDescription
# test event for new unconfigured sensor
event_callback({"id": "test3", "sensor": "battery", "value": "ok", "unit": None})
await hass.async_block_till_done()
# test state of battery sensor
bat_sensor = hass.states.get("sensor.test3")
assert bat_sensor
assert bat_sensor.state == "ok"
assert ATTR_UNIT_OF_MEASUREMENT not in bat_sensor.attributes
assert bat_sensor.attributes[ATTR_ICON] == "mdi:battery"
async def test_disable_automatic_add(
hass: HomeAssistant, monkeypatch: pytest.MonkeyPatch
) -> None:
"""If disabled new devices should not be automatically added."""
config = {
"rflink": {"port": "/dev/ttyABC0"},
DOMAIN: {"platform": "rflink", "automatic_add": False},
}
# setup mocking rflink module
event_callback, _, _, _ = await mock_rflink(hass, config, DOMAIN, monkeypatch)
# test event for new unconfigured sensor
event_callback(
{
"id": "test2",
"sensor": "temperature",
"value": 0,
"unit": UnitOfTemperature.CELSIUS,
}
)
await hass.async_block_till_done()
# make sure new device is not added
assert not hass.states.get("sensor.test2")
async def test_entity_availability(
hass: HomeAssistant, monkeypatch: pytest.MonkeyPatch
) -> None:
"""If Rflink device is disconnected, entities should become unavailable."""
# Make sure Rflink mock does not 'recover' to quickly from the
# disconnect or else the unavailability cannot be measured
config = CONFIG
failures = [True, True]
config[CONF_RECONNECT_INTERVAL] = 60
# Create platform and entities
_, _, _, disconnect_callback = await mock_rflink(
hass, config, DOMAIN, monkeypatch, failures=failures
)
# Entities are available by default
assert hass.states.get("sensor.test").state == STATE_UNKNOWN
# Mock a disconnect of the Rflink device
disconnect_callback()
# Wait for dispatch events to propagate
await hass.async_block_till_done()
# Entity should be unavailable
assert hass.states.get("sensor.test").state == "unavailable"
# Reconnect the Rflink device
disconnect_callback()
# Wait for dispatch events to propagate
await hass.async_block_till_done()
# Entities should be available again
assert hass.states.get("sensor.test").state == STATE_UNKNOWN
async def test_aliases(hass: HomeAssistant, monkeypatch: pytest.MonkeyPatch) -> None:
"""Validate the response to sensor's alias (with aliases)."""
config = {
"rflink": {"port": "/dev/ttyABC0"},
DOMAIN: {
"platform": "rflink",
"devices": {
"test_02": {
"name": "test_02",
"sensor_type": "humidity",
"aliases": ["test_alias_02_0"],
}
},
},
}
# setup mocking rflink module
event_callback, _, _, _ = await mock_rflink(hass, config, DOMAIN, monkeypatch)
# test default state of sensor loaded from config
config_sensor = hass.states.get("sensor.test_02")
assert config_sensor
assert config_sensor.state == "unknown"
# test event for config sensor
event_callback(
{
"id": "test_alias_02_0",
"sensor": "humidity",
"value": 65,
"unit": PERCENTAGE,
}
)
await hass.async_block_till_done()
# test state of new sensor
updated_sensor = hass.states.get("sensor.test_02")
assert updated_sensor
assert updated_sensor.state == "65"
assert updated_sensor.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE
async def test_race_condition(
hass: HomeAssistant, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test race condition for unknown components."""
config = {"rflink": {"port": "/dev/ttyABC0"}, DOMAIN: {"platform": "rflink"}}
tmp_entity = TMP_ENTITY.format("test3")
# setup mocking rflink module
event_callback, _, _, _ = await mock_rflink(hass, config, DOMAIN, monkeypatch)
# test event for new unconfigured sensor
event_callback({"id": "test3", "sensor": "battery", "value": "ok", "unit": ""})
event_callback({"id": "test3", "sensor": "battery", "value": "ko", "unit": ""})
# tmp_entity added to EVENT_KEY_SENSOR
assert tmp_entity in hass.data[DATA_ENTITY_LOOKUP][EVENT_KEY_SENSOR]["test3"]
# tmp_entity must no be added to EVENT_KEY_COMMAND
assert tmp_entity not in hass.data[DATA_ENTITY_LOOKUP][EVENT_KEY_COMMAND]["test3"]
await hass.async_block_till_done()
# test state of new sensor
updated_sensor = hass.states.get("sensor.test3")
assert updated_sensor
# test state of new sensor
new_sensor = hass.states.get(f"{DOMAIN}.test3")
assert new_sensor
assert new_sensor.state == "ok"
event_callback({"id": "test3", "sensor": "battery", "value": "ko", "unit": ""})
await hass.async_block_till_done()
# tmp_entity must be deleted from EVENT_KEY_COMMAND
assert tmp_entity not in hass.data[DATA_ENTITY_LOOKUP][EVENT_KEY_SENSOR]["test3"]
# test state of new sensor
new_sensor = hass.states.get(f"{DOMAIN}.test3")
assert new_sensor
assert new_sensor.state == "ko"
async def test_sensor_attributes(
hass: HomeAssistant, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Validate the sensor attributes."""
config = {
"rflink": {"port": "/dev/ttyABC0"},
DOMAIN: {
"platform": "rflink",
"devices": {
"my_meter_device_unique_id": {
"name": "meter_device",
"sensor_type": "meter_value",
},
"my_rain_device_unique_id": {
"name": "rain_device",
"sensor_type": "total_rain",
},
"my_humidity_device_unique_id": {
"name": "humidity_device",
"sensor_type": "humidity",
},
"my_temperature_device_unique_id": {
"name": "temperature_device",
"sensor_type": "temperature",
},
"another_temperature_device_unique_id": {
"name": "fahrenheit_device",
"sensor_type": "temperature",
"unit_of_measurement": "F",
},
},
},
}
# setup mocking rflink module
event_callback, _, _, _ = await mock_rflink(hass, config, DOMAIN, monkeypatch)
# test sensor loaded from config
meter_state = hass.states.get("sensor.meter_device")
assert meter_state
assert "device_class" not in meter_state.attributes
assert "state_class" not in meter_state.attributes
assert "unit_of_measurement" not in meter_state.attributes
rain_state = hass.states.get("sensor.rain_device")
assert rain_state
assert rain_state.attributes["device_class"] == SensorDeviceClass.PRECIPITATION
assert rain_state.attributes["state_class"] == SensorStateClass.TOTAL_INCREASING
assert (
rain_state.attributes["unit_of_measurement"]
== UnitOfPrecipitationDepth.MILLIMETERS
)
humidity_state = hass.states.get("sensor.humidity_device")
assert humidity_state
assert humidity_state.attributes["device_class"] == SensorDeviceClass.HUMIDITY
assert humidity_state.attributes["state_class"] == SensorStateClass.MEASUREMENT
assert humidity_state.attributes["unit_of_measurement"] == PERCENTAGE
temperature_state = hass.states.get("sensor.temperature_device")
assert temperature_state
assert temperature_state.attributes["device_class"] == SensorDeviceClass.TEMPERATURE
assert temperature_state.attributes["state_class"] == SensorStateClass.MEASUREMENT
assert (
temperature_state.attributes["unit_of_measurement"] == UnitOfTemperature.CELSIUS
)
fahrenheit_state = hass.states.get("sensor.fahrenheit_device")
assert fahrenheit_state
assert fahrenheit_state.attributes["device_class"] == SensorDeviceClass.TEMPERATURE
assert fahrenheit_state.attributes["state_class"] == SensorStateClass.MEASUREMENT
assert fahrenheit_state.attributes["unit_of_measurement"] == "F"