Rewrite dyson sensor test (#45382)

This commit is contained in:
Xiaonan Shen 2021-01-22 02:43:52 +08:00 committed by GitHub
parent b68c287ff1
commit 5de8639798
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 236 additions and 405 deletions

View File

@ -5,6 +5,9 @@ from libpurecool.dyson_pure_cool import DysonPureCool
from libpurecool.dyson_pure_cool_link import DysonPureCoolLink from libpurecool.dyson_pure_cool_link import DysonPureCoolLink
from homeassistant.const import ( from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_ICON,
ATTR_UNIT_OF_MEASUREMENT,
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TEMPERATURE,
PERCENTAGE, PERCENTAGE,
@ -16,37 +19,41 @@ from homeassistant.helpers.entity import Entity
from . import DYSON_DEVICES, DysonEntity from . import DYSON_DEVICES, DysonEntity
SENSOR_UNITS = { SENSOR_ATTRIBUTES = {
"filter_life": TIME_HOURS, "air_quality": {ATTR_ICON: "mdi:fan"},
"carbon_filter_state": PERCENTAGE, "dust": {ATTR_ICON: "mdi:cloud"},
"hepa_filter_state": PERCENTAGE, "humidity": {
"combi_filter_state": PERCENTAGE, ATTR_DEVICE_CLASS: DEVICE_CLASS_HUMIDITY,
"humidity": PERCENTAGE, ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
} },
"temperature": {ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE},
SENSOR_ICONS = { "filter_life": {
"air_quality": "mdi:fan", ATTR_ICON: "mdi:filter-outline",
"dust": "mdi:cloud", ATTR_UNIT_OF_MEASUREMENT: TIME_HOURS,
"filter_life": "mdi:filter-outline", },
"carbon_filter_state": "mdi:filter-outline", "carbon_filter_state": {
"hepa_filter_state": "mdi:filter-outline", ATTR_ICON: "mdi:filter-outline",
"combi_filter_state": "mdi:filter-outline", ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
},
"combi_filter_state": {
ATTR_ICON: "mdi:filter-outline",
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
},
"hepa_filter_state": {
ATTR_ICON: "mdi:filter-outline",
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
},
} }
SENSOR_NAMES = { SENSOR_NAMES = {
"air_quality": "AQI", "air_quality": "AQI",
"dust": "Dust", "dust": "Dust",
"filter_life": "Filter Life",
"humidity": "Humidity", "humidity": "Humidity",
"carbon_filter_state": "Carbon Filter Remaining Life",
"hepa_filter_state": "HEPA Filter Remaining Life",
"combi_filter_state": "Combi Filter Remaining Life",
"temperature": "Temperature", "temperature": "Temperature",
} "filter_life": "Filter Life",
"carbon_filter_state": "Carbon Filter Remaining Life",
SENSOR_DEVICE_CLASSES = { "combi_filter_state": "Combi Filter Remaining Life",
"humidity": DEVICE_CLASS_HUMIDITY, "hepa_filter_state": "HEPA Filter Remaining Life",
"temperature": DEVICE_CLASS_TEMPERATURE,
} }
DYSON_SENSOR_DEVICES = "dyson_sensor_devices" DYSON_SENSOR_DEVICES = "dyson_sensor_devices"
@ -106,6 +113,7 @@ class DysonSensor(DysonEntity, Entity):
super().__init__(device, None) super().__init__(device, None)
self._old_value = None self._old_value = None
self._sensor_type = sensor_type self._sensor_type = sensor_type
self._attributes = SENSOR_ATTRIBUTES[sensor_type]
def on_message(self, message): def on_message(self, message):
"""Handle new messages which are received from the fan.""" """Handle new messages which are received from the fan."""
@ -127,17 +135,17 @@ class DysonSensor(DysonEntity, Entity):
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
"""Return the unit the value is expressed in.""" """Return the unit the value is expressed in."""
return SENSOR_UNITS.get(self._sensor_type) return self._attributes.get(ATTR_UNIT_OF_MEASUREMENT)
@property @property
def icon(self): def icon(self):
"""Return the icon for this sensor.""" """Return the icon for this sensor."""
return SENSOR_ICONS.get(self._sensor_type) return self._attributes.get(ATTR_ICON)
@property @property
def device_class(self): def device_class(self):
"""Return the device class of this sensor.""" """Return the device class of this sensor."""
return SENSOR_DEVICE_CLASSES.get(self._sensor_type) return self._attributes.get(ATTR_DEVICE_CLASS)
class DysonFilterLifeSensor(DysonSensor): class DysonFilterLifeSensor(DysonSensor):
@ -150,9 +158,7 @@ class DysonFilterLifeSensor(DysonSensor):
@property @property
def state(self): def state(self):
"""Return filter life in hours.""" """Return filter life in hours."""
if self._device.state: return int(self._device.state.filter_life)
return int(self._device.state.filter_life)
return None
class DysonCarbonFilterLifeSensor(DysonSensor): class DysonCarbonFilterLifeSensor(DysonSensor):
@ -165,9 +171,7 @@ class DysonCarbonFilterLifeSensor(DysonSensor):
@property @property
def state(self): def state(self):
"""Return filter life remaining in percent.""" """Return filter life remaining in percent."""
if self._device.state: return int(self._device.state.carbon_filter_state)
return int(self._device.state.carbon_filter_state)
return None
class DysonHepaFilterLifeSensor(DysonSensor): class DysonHepaFilterLifeSensor(DysonSensor):
@ -180,9 +184,7 @@ class DysonHepaFilterLifeSensor(DysonSensor):
@property @property
def state(self): def state(self):
"""Return filter life remaining in percent.""" """Return filter life remaining in percent."""
if self._device.state: return int(self._device.state.hepa_filter_state)
return int(self._device.state.hepa_filter_state)
return None
class DysonDustSensor(DysonSensor): class DysonDustSensor(DysonSensor):
@ -195,9 +197,7 @@ class DysonDustSensor(DysonSensor):
@property @property
def state(self): def state(self):
"""Return Dust value.""" """Return Dust value."""
if self._device.environmental_state: return self._device.environmental_state.dust
return self._device.environmental_state.dust
return None
class DysonHumiditySensor(DysonSensor): class DysonHumiditySensor(DysonSensor):
@ -210,11 +210,9 @@ class DysonHumiditySensor(DysonSensor):
@property @property
def state(self): def state(self):
"""Return Humidity value.""" """Return Humidity value."""
if self._device.environmental_state: if self._device.environmental_state.humidity == 0:
if self._device.environmental_state.humidity == 0: return STATE_OFF
return STATE_OFF return self._device.environmental_state.humidity
return self._device.environmental_state.humidity
return None
class DysonTemperatureSensor(DysonSensor): class DysonTemperatureSensor(DysonSensor):
@ -228,14 +226,12 @@ class DysonTemperatureSensor(DysonSensor):
@property @property
def state(self): def state(self):
"""Return Temperature value.""" """Return Temperature value."""
if self._device.environmental_state: temperature_kelvin = self._device.environmental_state.temperature
temperature_kelvin = self._device.environmental_state.temperature if temperature_kelvin == 0:
if temperature_kelvin == 0: return STATE_OFF
return STATE_OFF if self._unit == TEMP_CELSIUS:
if self._unit == TEMP_CELSIUS: return float(f"{(temperature_kelvin - 273.15):.1f}")
return float(f"{(temperature_kelvin - 273.15):.1f}") return float(f"{(temperature_kelvin * 9 / 5 - 459.67):.1f}")
return float(f"{(temperature_kelvin * 9 / 5 - 459.67):.1f}")
return None
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
@ -253,6 +249,4 @@ class DysonAirQualitySensor(DysonSensor):
@property @property
def state(self): def state(self):
"""Return Air Quality value.""" """Return Air Quality value."""
if self._device.environmental_state: return int(self._device.environmental_state.volatil_organic_compounds)
return int(self._device.environmental_state.volatil_organic_compounds)
return None

View File

@ -7,6 +7,8 @@ from unittest.mock import MagicMock
from libpurecool.dyson_device import DysonDevice from libpurecool.dyson_device import DysonDevice
from libpurecool.dyson_pure_cool import FanSpeed from libpurecool.dyson_pure_cool import FanSpeed
from homeassistant.components.dyson import CONF_LANGUAGE, DOMAIN
from homeassistant.const import CONF_DEVICES, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
SERIAL = "XX-XXXXX-XX" SERIAL = "XX-XXXXX-XX"
@ -15,6 +17,20 @@ ENTITY_NAME = "temp_name"
BASE_PATH = "homeassistant.components.dyson" BASE_PATH = "homeassistant.components.dyson"
CONFIG = {
DOMAIN: {
CONF_USERNAME: "user@example.com",
CONF_PASSWORD: "password",
CONF_LANGUAGE: "US",
CONF_DEVICES: [
{
"device_id": SERIAL,
"device_ip": "0.0.0.0",
}
],
}
}
def load_mock_device(device: DysonDevice) -> None: def load_mock_device(device: DysonDevice) -> None:
"""Load the mock with default values so it doesn't throw errors.""" """Load the mock with default values so it doesn't throw errors."""
@ -49,7 +65,13 @@ async def async_update_device(
hass: HomeAssistant, device: DysonDevice, state_type: Optional[Type] = None hass: HomeAssistant, device: DysonDevice, state_type: Optional[Type] = None
) -> None: ) -> None:
"""Update the device using callback function.""" """Update the device using callback function."""
callback = device.add_message_listener.call_args[0][0] callbacks = [args[0][0] for args in device.add_message_listener.call_args_list]
message = MagicMock(spec=state_type) message = MagicMock(spec=state_type)
await hass.async_add_executor_job(callback, message)
# Combining sync calls to avoid multiple executors
def _run_callbacks():
for callback in callbacks:
callback(message)
await hass.async_add_executor_job(_run_callbacks)
await hass.async_block_till_done() await hass.async_block_till_done()

View File

@ -4,16 +4,13 @@ from unittest.mock import patch
from libpurecool.dyson_device import DysonDevice from libpurecool.dyson_device import DysonDevice
import pytest import pytest
from homeassistant.components.dyson import CONF_LANGUAGE, DOMAIN from homeassistant.components.dyson import DOMAIN
from homeassistant.const import CONF_DEVICES, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from .common import SERIAL from .common import BASE_PATH, CONFIG
from tests.common import async_setup_component from tests.common import async_setup_component
BASE_PATH = "homeassistant.components.dyson"
@pytest.fixture() @pytest.fixture()
async def device(hass: HomeAssistant, request) -> DysonDevice: async def device(hass: HomeAssistant, request) -> DysonDevice:
@ -21,7 +18,10 @@ async def device(hass: HomeAssistant, request) -> DysonDevice:
platform = request.module.PLATFORM_DOMAIN platform = request.module.PLATFORM_DOMAIN
get_device = request.module.get_device get_device = request.module.get_device
if hasattr(request, "param"): if hasattr(request, "param"):
device = get_device(request.param) if isinstance(request.param, list):
device = get_device(*request.param)
else:
device = get_device(request.param)
else: else:
device = get_device() device = get_device()
with patch(f"{BASE_PATH}.DysonAccount.login", return_value=True), patch( with patch(f"{BASE_PATH}.DysonAccount.login", return_value=True), patch(
@ -31,19 +31,7 @@ async def device(hass: HomeAssistant, request) -> DysonDevice:
await async_setup_component( await async_setup_component(
hass, hass,
DOMAIN, DOMAIN,
{ CONFIG,
DOMAIN: {
CONF_USERNAME: "user@example.com",
CONF_PASSWORD: "password",
CONF_LANGUAGE: "US",
CONF_DEVICES: [
{
"device_id": SERIAL,
"device_ip": "0.0.0.0",
}
],
}
},
) )
await hass.async_block_till_done() await hass.async_block_till_done()

View File

@ -1,355 +1,182 @@
"""Test the Dyson sensor(s) component.""" """Test the Dyson sensor(s) component."""
import unittest from typing import List, Type
from unittest import mock
from unittest.mock import patch from unittest.mock import patch
from libpurecool.dyson_pure_cool import DysonPureCool from libpurecool.dyson_pure_cool import DysonPureCool
from libpurecool.dyson_pure_cool_link import DysonPureCoolLink from libpurecool.dyson_pure_cool_link import DysonPureCoolLink
import pytest
from homeassistant.components import dyson as dyson_parent from homeassistant.components.dyson import DOMAIN
from homeassistant.components.dyson import sensor as dyson from homeassistant.components.dyson.sensor import SENSOR_ATTRIBUTES, SENSOR_NAMES
from homeassistant.components.sensor import DOMAIN as PLATFORM_DOMAIN
from homeassistant.const import ( from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT, ATTR_UNIT_OF_MEASUREMENT,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_TEMPERATURE,
PERCENTAGE,
STATE_OFF, STATE_OFF,
TEMP_CELSIUS, TEMP_CELSIUS,
TEMP_FAHRENHEIT, TEMP_FAHRENHEIT,
TIME_HOURS,
) )
from homeassistant.helpers import discovery from homeassistant.core import HomeAssistant, callback
from homeassistant.setup import async_setup_component from homeassistant.helpers import entity_registry
from homeassistant.util.unit_system import IMPERIAL_SYSTEM, METRIC_SYSTEM, UnitSystem
from .common import load_mock_device from .common import (
BASE_PATH,
CONFIG,
ENTITY_NAME,
NAME,
SERIAL,
async_update_device,
get_basic_device,
)
from tests.common import get_test_home_assistant from tests.common import async_setup_component
ENTITY_ID_PREFIX = f"{PLATFORM_DOMAIN}.{ENTITY_NAME}"
MOCKED_VALUES = {
"filter_life": 100,
"dust": 5,
"humidity": 45,
"temperature_kelvin": 295,
"temperature": 21.9,
"air_quality": 5,
"hepa_filter_state": 50,
"combi_filter_state": 50,
"carbon_filter_state": 10,
}
MOCKED_UPDATED_VALUES = {
"filter_life": 30,
"dust": 2,
"humidity": 80,
"temperature_kelvin": 240,
"temperature": -33.1,
"air_quality": 3,
"hepa_filter_state": 30,
"combi_filter_state": 30,
"carbon_filter_state": 20,
}
def _get_dyson_purecool_device(): @callback
"""Return a valid device provide by Dyson web services.""" def _async_assign_values(
device = mock.Mock(spec=DysonPureCool) device: DysonPureCoolLink, values=MOCKED_VALUES, combi=False
load_mock_device(device) ) -> None:
return device """Assign mocked values to the device."""
if isinstance(device, DysonPureCool):
device.state.hepa_filter_state = values["hepa_filter_state"]
def _get_config(): device.state.carbon_filter_state = (
"""Return a config dictionary.""" "INV" if combi else values["carbon_filter_state"]
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"}
],
}
}
def _get_device_without_state():
"""Return a valid device provide by Dyson web services."""
device = mock.Mock(spec=DysonPureCoolLink)
device.name = "Device_name"
device.state = None
device.environmental_state = None
return device
def _get_with_state():
"""Return a valid device with state values."""
device = mock.Mock()
load_mock_device(device)
device.name = "Device_name"
device.state.filter_life = 100
device.environmental_state.dust = 5
device.environmental_state.humidity = 45
device.environmental_state.temperature = 295
device.environmental_state.volatil_organic_compounds = 2
return device
def _get_purecool_device():
"""Return a valid device with filters life state values."""
device = mock.Mock(spec=DysonPureCool)
load_mock_device(device)
device.name = "PureCool"
device.state.carbon_filter_state = "0096"
device.state.hepa_filter_state = "0056"
device.environmental_state.dust = 5
device.environmental_state.humidity = 45
device.environmental_state.temperature = 295
device.environmental_state.volatil_organic_compounds = 2
return device
def _get_purecool_humidify_device():
"""Return a valid device with filters life state values."""
device = mock.Mock(spec=DysonPureCool)
load_mock_device(device)
device.name = "PureCool_Humidify"
device.state.carbon_filter_state = "INV"
device.state.hepa_filter_state = "0075"
device.environmental_state.dust = 5
device.environmental_state.humidity = 45
device.environmental_state.temperature = 295
device.environmental_state.volatil_organic_compounds = 2
return device
def _get_with_standby_monitoring():
"""Return a valid device with state but with standby monitoring disable."""
device = mock.Mock()
load_mock_device(device)
device.name = "Device_name"
device.environmental_state.humidity = 0
device.environmental_state.temperature = 0
return device
class DysonTest(unittest.TestCase):
"""Dyson Sensor component test class."""
def setUp(self): # pylint: disable=invalid-name
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.addCleanup(self.tear_down_cleanup)
def tear_down_cleanup(self):
"""Stop everything that was started."""
self.hass.stop()
def test_setup_component_with_no_devices(self):
"""Test setup component with no devices."""
self.hass.data[dyson.DYSON_DEVICES] = []
add_entities = mock.MagicMock()
dyson.setup_platform(self.hass, None, add_entities)
add_entities.assert_not_called()
def test_setup_component(self):
"""Test setup component with devices."""
def _add_device(devices):
assert len(devices) == 5
assert devices[0].name == "Device_name Filter Life"
assert devices[1].name == "Device_name Dust"
assert devices[2].name == "Device_name Humidity"
assert devices[3].name == "Device_name Temperature"
assert devices[4].name == "Device_name AQI"
device_fan = _get_device_without_state()
device_non_fan = _get_with_state()
self.hass.data[dyson.DYSON_DEVICES] = [
device_fan,
device_non_fan,
]
dyson.setup_platform(self.hass, None, _add_device, mock.MagicMock())
def test_dyson_filter_life_sensor(self):
"""Test filter life sensor with no value."""
sensor = dyson.DysonFilterLifeSensor(_get_device_without_state())
sensor.hass = self.hass
sensor.entity_id = "sensor.dyson_1"
assert not sensor.should_poll
assert sensor.state is None
assert sensor.unit_of_measurement == TIME_HOURS
assert sensor.name == "Device_name Filter Life"
assert sensor.entity_id == "sensor.dyson_1"
sensor.on_message("message")
def test_dyson_filter_life_sensor_with_values(self):
"""Test filter sensor with values."""
sensor = dyson.DysonFilterLifeSensor(_get_with_state())
sensor.hass = self.hass
sensor.entity_id = "sensor.dyson_1"
assert not sensor.should_poll
assert sensor.state == 100
assert sensor.unit_of_measurement == TIME_HOURS
assert sensor.name == "Device_name Filter Life"
assert sensor.entity_id == "sensor.dyson_1"
sensor.on_message("message")
def test_dyson_dust_sensor(self):
"""Test dust sensor with no value."""
sensor = dyson.DysonDustSensor(_get_device_without_state())
sensor.hass = self.hass
sensor.entity_id = "sensor.dyson_1"
assert not sensor.should_poll
assert sensor.state is None
assert sensor.unit_of_measurement is None
assert sensor.name == "Device_name Dust"
assert sensor.entity_id == "sensor.dyson_1"
def test_dyson_dust_sensor_with_values(self):
"""Test dust sensor with values."""
sensor = dyson.DysonDustSensor(_get_with_state())
sensor.hass = self.hass
sensor.entity_id = "sensor.dyson_1"
assert not sensor.should_poll
assert sensor.state == 5
assert sensor.unit_of_measurement is None
assert sensor.name == "Device_name Dust"
assert sensor.entity_id == "sensor.dyson_1"
def test_dyson_humidity_sensor(self):
"""Test humidity sensor with no value."""
sensor = dyson.DysonHumiditySensor(_get_device_without_state())
sensor.hass = self.hass
sensor.entity_id = "sensor.dyson_1"
assert not sensor.should_poll
assert sensor.state is None
assert sensor.unit_of_measurement == PERCENTAGE
assert sensor.name == "Device_name Humidity"
assert sensor.entity_id == "sensor.dyson_1"
assert sensor.device_class == DEVICE_CLASS_HUMIDITY
def test_dyson_humidity_sensor_with_values(self):
"""Test humidity sensor with values."""
sensor = dyson.DysonHumiditySensor(_get_with_state())
sensor.hass = self.hass
sensor.entity_id = "sensor.dyson_1"
assert not sensor.should_poll
assert sensor.state == 45
assert sensor.unit_of_measurement == PERCENTAGE
assert sensor.name == "Device_name Humidity"
assert sensor.entity_id == "sensor.dyson_1"
def test_dyson_humidity_standby_monitoring(self):
"""Test humidity sensor while device is in standby monitoring."""
sensor = dyson.DysonHumiditySensor(_get_with_standby_monitoring())
sensor.hass = self.hass
sensor.entity_id = "sensor.dyson_1"
assert not sensor.should_poll
assert sensor.state == STATE_OFF
assert sensor.unit_of_measurement == PERCENTAGE
assert sensor.name == "Device_name Humidity"
assert sensor.entity_id == "sensor.dyson_1"
def test_dyson_temperature_sensor(self):
"""Test temperature sensor with no value."""
sensor = dyson.DysonTemperatureSensor(_get_device_without_state(), TEMP_CELSIUS)
sensor.hass = self.hass
sensor.entity_id = "sensor.dyson_1"
assert not sensor.should_poll
assert sensor.state is None
assert sensor.unit_of_measurement == TEMP_CELSIUS
assert sensor.name == "Device_name Temperature"
assert sensor.entity_id == "sensor.dyson_1"
assert sensor.device_class == DEVICE_CLASS_TEMPERATURE
def test_dyson_temperature_sensor_with_values(self):
"""Test temperature sensor with values."""
sensor = dyson.DysonTemperatureSensor(_get_with_state(), TEMP_CELSIUS)
sensor.hass = self.hass
sensor.entity_id = "sensor.dyson_1"
assert not sensor.should_poll
assert sensor.state == 21.9
assert sensor.unit_of_measurement == TEMP_CELSIUS
assert sensor.name == "Device_name Temperature"
assert sensor.entity_id == "sensor.dyson_1"
sensor = dyson.DysonTemperatureSensor(_get_with_state(), TEMP_FAHRENHEIT)
sensor.hass = self.hass
sensor.entity_id = "sensor.dyson_1"
assert not sensor.should_poll
assert sensor.state == 71.3
assert sensor.unit_of_measurement == TEMP_FAHRENHEIT
assert sensor.name == "Device_name Temperature"
assert sensor.entity_id == "sensor.dyson_1"
def test_dyson_temperature_standby_monitoring(self):
"""Test temperature sensor while device is in standby monitoring."""
sensor = dyson.DysonTemperatureSensor(
_get_with_standby_monitoring(), TEMP_CELSIUS
) )
sensor.hass = self.hass device.environmental_state.humidity = values["humidity"]
sensor.entity_id = "sensor.dyson_1" device.environmental_state.temperature = values["temperature_kelvin"]
assert not sensor.should_poll else: # DysonPureCoolLink
assert sensor.state == STATE_OFF device.state.filter_life = values["filter_life"]
assert sensor.unit_of_measurement == TEMP_CELSIUS device.environmental_state.dust = values["dust"]
assert sensor.name == "Device_name Temperature" device.environmental_state.humidity = values["humidity"]
assert sensor.entity_id == "sensor.dyson_1" device.environmental_state.temperature = values["temperature_kelvin"]
device.environmental_state.volatil_organic_compounds = values["air_quality"]
def test_dyson_air_quality_sensor(self):
"""Test air quality sensor with no value."""
sensor = dyson.DysonAirQualitySensor(_get_device_without_state())
sensor.hass = self.hass
sensor.entity_id = "sensor.dyson_1"
assert not sensor.should_poll
assert sensor.state is None
assert sensor.unit_of_measurement is None
assert sensor.name == "Device_name AQI"
assert sensor.entity_id == "sensor.dyson_1"
def test_dyson_air_quality_sensor_with_values(self):
"""Test air quality sensor with values."""
sensor = dyson.DysonAirQualitySensor(_get_with_state())
sensor.hass = self.hass
sensor.entity_id = "sensor.dyson_1"
assert not sensor.should_poll
assert sensor.state == 2
assert sensor.unit_of_measurement is None
assert sensor.name == "Device_name AQI"
assert sensor.entity_id == "sensor.dyson_1"
@patch("libpurecool.dyson.DysonAccount.login", return_value=True) @callback
@patch( def get_device(spec: Type[DysonPureCoolLink], combi=False) -> DysonPureCoolLink:
"libpurecool.dyson.DysonAccount.devices", """Return a device of the given type."""
return_value=[_get_dyson_purecool_device()], device = get_basic_device(spec)
_async_assign_values(device, combi=combi)
return device
@callback
def _async_get_entity_id(sensor_type: str) -> str:
"""Get the expected entity id from the type of the sensor."""
sensor_name = SENSOR_NAMES[sensor_type]
entity_id_suffix = sensor_name.lower().replace(" ", "_")
return f"{ENTITY_ID_PREFIX}_{entity_id_suffix}"
@pytest.mark.parametrize(
"device,sensors",
[
(
DysonPureCoolLink,
["filter_life", "dust", "humidity", "temperature", "air_quality"],
),
(
DysonPureCool,
["hepa_filter_state", "carbon_filter_state", "humidity", "temperature"],
),
(
[DysonPureCool, True],
["combi_filter_state", "humidity", "temperature"],
),
],
indirect=["device"],
) )
async def test_purecool_component_setup_only_once(devices, login, hass): async def test_sensors(
"""Test if entities are created only once.""" hass: HomeAssistant, device: DysonPureCoolLink, sensors: List[str]
config = _get_config() ) -> None:
await async_setup_component(hass, dyson_parent.DOMAIN, config) """Test the sensors."""
await hass.async_block_till_done() # Temperature is given by the device in kelvin
discovery.load_platform(hass, "sensor", dyson_parent.DOMAIN, {}, config) # Make sure no other sensors are set up
await hass.async_block_till_done() assert len(hass.states.async_all()) == len(sensors)
assert len(hass.data[dyson.DYSON_SENSOR_DEVICES]) == 4 er = await entity_registry.async_get_registry(hass)
for sensor in sensors:
entity_id = _async_get_entity_id(sensor)
# Test unique id
assert er.async_get(entity_id).unique_id == f"{SERIAL}-{sensor}"
# Test state
state = hass.states.get(entity_id)
assert state.state == str(MOCKED_VALUES[sensor])
assert state.name == f"{NAME} {SENSOR_NAMES[sensor]}"
# Test attributes
attributes = state.attributes
for attr, value in SENSOR_ATTRIBUTES[sensor].items():
assert attributes[attr] == value
# Test data update
_async_assign_values(device, MOCKED_UPDATED_VALUES)
await async_update_device(hass, device)
for sensor in sensors:
state = hass.states.get(_async_get_entity_id(sensor))
assert state.state == str(MOCKED_UPDATED_VALUES[sensor])
@patch("libpurecool.dyson.DysonAccount.login", return_value=True) @pytest.mark.parametrize("device", [DysonPureCoolLink], indirect=True)
@patch( async def test_sensors_off(hass: HomeAssistant, device: DysonPureCoolLink) -> None:
"libpurecool.dyson.DysonAccount.devices", """Test the case where temperature and humidity are not available."""
return_value=[_get_purecool_device()], device.environmental_state.temperature = 0
device.environmental_state.humidity = 0
await async_update_device(hass, device)
assert hass.states.get(f"{ENTITY_ID_PREFIX}_temperature").state == STATE_OFF
assert hass.states.get(f"{ENTITY_ID_PREFIX}_humidity").state == STATE_OFF
@pytest.mark.parametrize(
"unit_system,temp_unit,temperature",
[(METRIC_SYSTEM, TEMP_CELSIUS, 21.9), (IMPERIAL_SYSTEM, TEMP_FAHRENHEIT, 71.3)],
) )
async def test_dyson_purecool_filter_state_sensor(devices, login, hass): async def test_temperature(
"""Test filter sensor with values.""" hass: HomeAssistant, unit_system: UnitSystem, temp_unit: str, temperature: float
config = _get_config() ) -> None:
await async_setup_component(hass, dyson_parent.DOMAIN, config) """Test the temperature sensor in different units."""
await hass.async_block_till_done() hass.config.units = unit_system
state = hass.states.get("sensor.purecool_hepa_filter_remaining_life") device = get_device(DysonPureCoolLink)
assert state is not None with patch(f"{BASE_PATH}.DysonAccount.login", return_value=True), patch(
assert state.state == "56" f"{BASE_PATH}.DysonAccount.devices", return_value=[device]
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE ), patch(f"{BASE_PATH}.DYSON_PLATFORMS", [PLATFORM_DOMAIN]):
assert state.name == "PureCool HEPA Filter Remaining Life" # DYSON_PLATFORMS is patched so that only the platform being tested is set up
await async_setup_component(
hass,
DOMAIN,
CONFIG,
)
await hass.async_block_till_done()
state = hass.states.get("sensor.purecool_carbon_filter_remaining_life") state = hass.states.get(f"{ENTITY_ID_PREFIX}_temperature")
assert state is not None assert state.state == str(temperature)
assert state.state == "96" assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == temp_unit
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE
assert state.name == "PureCool Carbon Filter Remaining Life"
@patch("libpurecool.dyson.DysonAccount.login", return_value=True)
@patch(
"libpurecool.dyson.DysonAccount.devices",
return_value=[_get_purecool_humidify_device()],
)
async def test_dyson_purecool_humidify_filter_state_sensor(devices, login, hass):
"""Test filter sensor with values."""
config = _get_config()
await async_setup_component(hass, dyson_parent.DOMAIN, config)
await hass.async_block_till_done()
state = hass.states.get("sensor.purecool_humidify_combi_filter_remaining_life")
assert state is not None
assert state.state == "75"
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE
assert state.name == "PureCool_Humidify Combi Filter Remaining Life"