"""Test for RFlink sensor components. Test setup of rflink sensor component/platform. Verify manual and automatic sensor creation. """ 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 .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, monkeypatch): """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, monkeypatch): """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, monkeypatch): """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, monkeypatch): """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, monkeypatch): """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, monkeypatch): """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"