"""Test the Dyson air quality component.""" import json from unittest import mock import asynctest from libpurecool.dyson_pure_cool import DysonPureCool from libpurecool.dyson_pure_state_v2 import DysonEnvironmentalSensorV2State import homeassistant.components.dyson.air_quality as dyson from homeassistant.components import dyson as dyson_parent from homeassistant.components.air_quality import ( DOMAIN as AIQ_DOMAIN, ATTR_PM_2_5, ATTR_PM_10, ATTR_NO2, ) from homeassistant.helpers import discovery from homeassistant.setup import async_setup_component def _get_dyson_purecool_device(): """Return a valid device as provided by the Dyson web services.""" device = mock.Mock(spec=DysonPureCool) device.serial = "XX-XXXXX-XX" device.name = "Living room" device.connect = mock.Mock(return_value=True) device.auto_connect = mock.Mock(return_value=True) device.environmental_state.particulate_matter_25 = "0014" device.environmental_state.particulate_matter_10 = "0025" device.environmental_state.nitrogen_dioxide = "0042" device.environmental_state.volatile_organic_compounds = "0035" return device def _get_config(): """Return a config dictionary.""" return { dyson_parent.DOMAIN: { dyson_parent.CONF_USERNAME: "email", dyson_parent.CONF_PASSWORD: "password", dyson_parent.CONF_LANGUAGE: "GB", dyson_parent.CONF_DEVICES: [ {"device_id": "XX-XXXXX-XX", "device_ip": "192.168.0.1"} ], } } @asynctest.patch("libpurecool.dyson.DysonAccount.login", return_value=True) @asynctest.patch( "libpurecool.dyson.DysonAccount.devices", return_value=[_get_dyson_purecool_device()], ) async def test_purecool_aiq_attributes(devices, login, hass): """Test state attributes.""" await async_setup_component(hass, dyson_parent.DOMAIN, _get_config()) await hass.async_block_till_done() fan_state = hass.states.get("air_quality.living_room") attributes = fan_state.attributes assert fan_state.state == "14" assert attributes[ATTR_PM_2_5] == 14 assert attributes[ATTR_PM_10] == 25 assert attributes[ATTR_NO2] == 42 assert attributes[dyson.ATTR_VOC] == 35 @asynctest.patch("libpurecool.dyson.DysonAccount.login", return_value=True) @asynctest.patch( "libpurecool.dyson.DysonAccount.devices", return_value=[_get_dyson_purecool_device()], ) async def test_purecool_aiq_update_state(devices, login, hass): """Test state update.""" device = devices.return_value[0] await async_setup_component(hass, dyson_parent.DOMAIN, _get_config()) await hass.async_block_till_done() event = { "msg": "ENVIRONMENTAL-CURRENT-SENSOR-DATA", "time": "2019-03-29T10:00:01.000Z", "data": { "pm10": "0080", "p10r": "0151", "hact": "0040", "va10": "0055", "p25r": "0161", "noxl": "0069", "pm25": "0035", "sltm": "OFF", "tact": "2960", }, } device.environmental_state = DysonEnvironmentalSensorV2State(json.dumps(event)) for call in device.add_message_listener.call_args_list: callback = call[0][0] if type(callback.__self__) == dyson.DysonAirSensor: callback(device.environmental_state) await hass.async_block_till_done() fan_state = hass.states.get("air_quality.living_room") attributes = fan_state.attributes assert fan_state.state == "35" assert attributes[ATTR_PM_2_5] == 35 assert attributes[ATTR_PM_10] == 80 assert attributes[ATTR_NO2] == 69 assert attributes[dyson.ATTR_VOC] == 55 @asynctest.patch("libpurecool.dyson.DysonAccount.login", return_value=True) @asynctest.patch( "libpurecool.dyson.DysonAccount.devices", return_value=[_get_dyson_purecool_device()], ) async def test_purecool_component_setup_only_once(devices, login, hass): """Test if entities are created only once.""" config = _get_config() await async_setup_component(hass, dyson_parent.DOMAIN, config) await hass.async_block_till_done() discovery.load_platform(hass, AIQ_DOMAIN, dyson_parent.DOMAIN, {}, config) await hass.async_block_till_done() assert len(hass.data[dyson.DYSON_AIQ_DEVICES]) == 1 @asynctest.patch("libpurecool.dyson.DysonAccount.login", return_value=True) @asynctest.patch( "libpurecool.dyson.DysonAccount.devices", return_value=[_get_dyson_purecool_device()], ) async def test_purecool_aiq_without_discovery(devices, login, hass): """Test if component correctly returns if discovery not set.""" await async_setup_component(hass, dyson_parent.DOMAIN, _get_config()) await hass.async_block_till_done() add_entities_mock = mock.MagicMock() dyson.setup_platform(hass, None, add_entities_mock, None) assert add_entities_mock.call_count == 0 @asynctest.patch("libpurecool.dyson.DysonAccount.login", return_value=True) @asynctest.patch( "libpurecool.dyson.DysonAccount.devices", return_value=[_get_dyson_purecool_device()], ) async def test_purecool_aiq_empty_environment_state(devices, login, hass): """Test device with empty environmental state.""" await async_setup_component(hass, dyson_parent.DOMAIN, _get_config()) await hass.async_block_till_done() device = hass.data[dyson.DYSON_AIQ_DEVICES][0] device._device.environmental_state = None assert device.state is None assert device.particulate_matter_2_5 is None assert device.particulate_matter_10 is None assert device.nitrogen_dioxide is None assert device.volatile_organic_compounds is None