diff --git a/homeassistant/components/blebox/__init__.py b/homeassistant/components/blebox/__init__.py index 0f4bd1c1490..35a334f36f3 100644 --- a/homeassistant/components/blebox/__init__.py +++ b/homeassistant/components/blebox/__init__.py @@ -18,7 +18,6 @@ from .const import DEFAULT_SETUP_TIMEOUT, DOMAIN, PRODUCT _LOGGER = logging.getLogger(__name__) PLATFORMS = [ - Platform.AIR_QUALITY, Platform.BUTTON, Platform.CLIMATE, Platform.COVER, diff --git a/homeassistant/components/blebox/air_quality.py b/homeassistant/components/blebox/air_quality.py deleted file mode 100644 index daadbc831b6..00000000000 --- a/homeassistant/components/blebox/air_quality.py +++ /dev/null @@ -1,43 +0,0 @@ -"""BleBox air quality entity.""" -from datetime import timedelta - -from homeassistant.components.air_quality import AirQualityEntity -from homeassistant.config_entries import ConfigEntry -from homeassistant.core import HomeAssistant -from homeassistant.helpers.entity_platform import AddEntitiesCallback - -from . import BleBoxEntity, create_blebox_entities - -SCAN_INTERVAL = timedelta(seconds=5) - - -async def async_setup_entry( - hass: HomeAssistant, - config_entry: ConfigEntry, - async_add_entities: AddEntitiesCallback, -) -> None: - """Set up a BleBox air quality entity.""" - create_blebox_entities( - hass, config_entry, async_add_entities, BleBoxAirQualityEntity, "air_qualities" - ) - - -class BleBoxAirQualityEntity(BleBoxEntity, AirQualityEntity): - """Representation of a BleBox air quality feature.""" - - _attr_icon = "mdi:blur" - - @property - def particulate_matter_0_1(self): - """Return the particulate matter 0.1 level.""" - return self._feature.pm1 - - @property - def particulate_matter_2_5(self): - """Return the particulate matter 2.5 level.""" - return self._feature.pm2_5 - - @property - def particulate_matter_10(self): - """Return the particulate matter 10 level.""" - return self._feature.pm10 diff --git a/homeassistant/components/blebox/manifest.json b/homeassistant/components/blebox/manifest.json index 49d44db8f01..328f15abdac 100644 --- a/homeassistant/components/blebox/manifest.json +++ b/homeassistant/components/blebox/manifest.json @@ -3,7 +3,7 @@ "name": "BleBox devices", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/blebox", - "requirements": ["blebox_uniapi==2.0.2"], + "requirements": ["blebox_uniapi==2.1.0"], "codeowners": ["@bbx-a", "@riokuu"], "iot_class": "local_polling", "loggers": ["blebox_uniapi"] diff --git a/homeassistant/components/blebox/sensor.py b/homeassistant/components/blebox/sensor.py index 663af970e3e..f3c0c393fd9 100644 --- a/homeassistant/components/blebox/sensor.py +++ b/homeassistant/components/blebox/sensor.py @@ -1,15 +1,46 @@ """BleBox sensor entities.""" -from homeassistant.components.sensor import SensorDeviceClass, SensorEntity +from dataclasses import dataclass + +from homeassistant.components.sensor import ( + SensorDeviceClass, + SensorEntity, + SensorEntityDescription, +) from homeassistant.config_entries import ConfigEntry -from homeassistant.const import TEMP_CELSIUS +from homeassistant.const import CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, TEMP_CELSIUS from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import BleBoxEntity, create_blebox_entities -BLEBOX_TO_UNIT_MAP = {"celsius": TEMP_CELSIUS} -BLEBOX_TO_SENSOR_DEVICE_CLASS = {"temperature": SensorDeviceClass.TEMPERATURE} +@dataclass +class BleboxSensorEntityDescription(SensorEntityDescription): + """Class describing Blebox sensor entities.""" + + +SENSOR_TYPES = ( + BleboxSensorEntityDescription( + key="pm1", + device_class=SensorDeviceClass.PM1, + native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + BleboxSensorEntityDescription( + key="pm2_5", + device_class=SensorDeviceClass.PM25, + native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + BleboxSensorEntityDescription( + key="pm10", + device_class=SensorDeviceClass.PM10, + native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + BleboxSensorEntityDescription( + key="temperature", + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=TEMP_CELSIUS, + ), +) async def async_setup_entry( @@ -30,10 +61,13 @@ class BleBoxSensorEntity(BleBoxEntity, SensorEntity): def __init__(self, feature): """Initialize a BleBox sensor feature.""" super().__init__(feature) - self._attr_native_unit_of_measurement = BLEBOX_TO_UNIT_MAP[feature.unit] - self._attr_device_class = BLEBOX_TO_SENSOR_DEVICE_CLASS[feature.device_class] + + for description in SENSOR_TYPES: + if description.key == feature.device_class: + self.entity_description = description + break @property def native_value(self): """Return the state.""" - return self._feature.current + return self._feature.native_value diff --git a/requirements_all.txt b/requirements_all.txt index 3b1914d986b..788463b3f54 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -419,7 +419,7 @@ bleak-retry-connector==2.1.3 bleak==0.18.1 # homeassistant.components.blebox -blebox_uniapi==2.0.2 +blebox_uniapi==2.1.0 # homeassistant.components.blink blinkpy==0.19.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 4e5e957c2f1..b0c3f7c4a4a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -343,7 +343,7 @@ bleak-retry-connector==2.1.3 bleak==0.18.1 # homeassistant.components.blebox -blebox_uniapi==2.0.2 +blebox_uniapi==2.1.0 # homeassistant.components.blink blinkpy==0.19.2 diff --git a/tests/components/blebox/test_air_quality.py b/tests/components/blebox/test_air_quality.py deleted file mode 100644 index 8b5bc67d4bc..00000000000 --- a/tests/components/blebox/test_air_quality.py +++ /dev/null @@ -1,93 +0,0 @@ -"""Blebox air_quality tests.""" -import logging -from unittest.mock import AsyncMock, PropertyMock - -import blebox_uniapi -import pytest - -from homeassistant.components.air_quality import ATTR_PM_0_1, ATTR_PM_2_5, ATTR_PM_10 -from homeassistant.const import ATTR_ICON, STATE_UNKNOWN -from homeassistant.helpers import device_registry as dr - -from .conftest import async_setup_entity, mock_feature - - -@pytest.fixture(name="airsensor") -def airsensor_fixture(): - """Return a default air quality fixture.""" - feature = mock_feature( - "air_qualities", - blebox_uniapi.air_quality.AirQuality, - unique_id="BleBox-airSensor-1afe34db9437-0.air", - full_name="airSensor-0.air", - device_class=None, - pm1=None, - pm2_5=None, - pm10=None, - ) - product = feature.product - type(product).name = PropertyMock(return_value="My air sensor") - type(product).model = PropertyMock(return_value="airSensor") - return (feature, "air_quality.airsensor_0_air") - - -async def test_init(airsensor, hass, config): - """Test airSensor default state.""" - - _, entity_id = airsensor - entry = await async_setup_entity(hass, config, entity_id) - assert entry.unique_id == "BleBox-airSensor-1afe34db9437-0.air" - - state = hass.states.get(entity_id) - assert state.name == "airSensor-0.air" - - assert ATTR_PM_0_1 not in state.attributes - assert ATTR_PM_2_5 not in state.attributes - assert ATTR_PM_10 not in state.attributes - - assert state.attributes[ATTR_ICON] == "mdi:blur" - - assert state.state == STATE_UNKNOWN - - device_registry = dr.async_get(hass) - device = device_registry.async_get(entry.device_id) - - assert device.name == "My air sensor" - assert device.identifiers == {("blebox", "abcd0123ef5678")} - assert device.manufacturer == "BleBox" - assert device.model == "airSensor" - assert device.sw_version == "1.23" - - -async def test_update(airsensor, hass, config): - """Test air quality sensor state after update.""" - - feature_mock, entity_id = airsensor - - def initial_update(): - feature_mock.pm1 = 49 - feature_mock.pm2_5 = 222 - feature_mock.pm10 = 333 - - feature_mock.async_update = AsyncMock(side_effect=initial_update) - await async_setup_entity(hass, config, entity_id) - - state = hass.states.get(entity_id) - - assert state.attributes[ATTR_PM_0_1] == 49 - assert state.attributes[ATTR_PM_2_5] == 222 - assert state.attributes[ATTR_PM_10] == 333 - - assert state.state == "222" - - -async def test_update_failure(airsensor, hass, config, caplog): - """Test that update failures are logged.""" - - caplog.set_level(logging.ERROR) - - feature_mock, entity_id = airsensor - feature_mock.async_update = AsyncMock(side_effect=blebox_uniapi.error.ClientError) - await async_setup_entity(hass, config, entity_id) - - assert f"Updating '{feature_mock.full_name}' failed: " in caplog.text diff --git a/tests/components/blebox/test_sensor.py b/tests/components/blebox/test_sensor.py index b7f6d421a12..d876da8b0b6 100644 --- a/tests/components/blebox/test_sensor.py +++ b/tests/components/blebox/test_sensor.py @@ -9,6 +9,7 @@ from homeassistant.components.sensor import SensorDeviceClass from homeassistant.const import ( ATTR_DEVICE_CLASS, ATTR_UNIT_OF_MEASUREMENT, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, STATE_UNKNOWN, TEMP_CELSIUS, ) @@ -17,9 +18,27 @@ from homeassistant.helpers import device_registry as dr from .conftest import async_setup_entity, mock_feature +@pytest.fixture(name="airsensor") +def airsensor_fixture(): + """Return a default AirQuality sensor mock.""" + feature = mock_feature( + "sensors", + blebox_uniapi.sensor.AirQuality, + unique_id="BleBox-airSensor-1afe34db9437-0.air", + full_name="airSensor-0.air", + device_class="pm1", + unit="concentration_of_mp", + native_value=None, + ) + product = feature.product + type(product).name = PropertyMock(return_value="My air sensor") + type(product).model = PropertyMock(return_value="airSensor") + return (feature, "sensor.airsensor_0_air") + + @pytest.fixture(name="tempsensor") def tempsensor_fixture(): - """Return a default sensor mock.""" + """Return a default Temperature sensor mock.""" feature = mock_feature( "sensors", blebox_uniapi.sensor.Temperature, @@ -28,6 +47,7 @@ def tempsensor_fixture(): device_class="temperature", unit="celsius", current=None, + native_value=None, ) product = feature.product type(product).name = PropertyMock(return_value="My temperature sensor") @@ -65,7 +85,7 @@ async def test_update(tempsensor, hass, config): feature_mock, entity_id = tempsensor def initial_update(): - feature_mock.current = 25.18 + feature_mock.native_value = 25.18 feature_mock.async_update = AsyncMock(side_effect=initial_update) await async_setup_entity(hass, config, entity_id) @@ -85,3 +105,46 @@ async def test_update_failure(tempsensor, hass, config, caplog): await async_setup_entity(hass, config, entity_id) assert f"Updating '{feature_mock.full_name}' failed: " in caplog.text + + +async def test_airsensor_init(airsensor, hass, config): + """Test airSensor default state.""" + + _, entity_id = airsensor + entry = await async_setup_entity(hass, config, entity_id) + assert entry.unique_id == "BleBox-airSensor-1afe34db9437-0.air" + + state = hass.states.get(entity_id) + assert state.name == "airSensor-0.air" + + assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.PM1 + assert state.state == STATE_UNKNOWN + + device_registry = dr.async_get(hass) + device = device_registry.async_get(entry.device_id) + + assert device.name == "My air sensor" + assert device.identifiers == {("blebox", "abcd0123ef5678")} + assert device.manufacturer == "BleBox" + assert device.model == "airSensor" + assert device.sw_version == "1.23" + + +async def test_airsensor_update(airsensor, hass, config): + """Test air quality sensor state after update.""" + + feature_mock, entity_id = airsensor + + def initial_update(): + feature_mock.native_value = 49 + + feature_mock.async_update = AsyncMock(side_effect=initial_update) + await async_setup_entity(hass, config, entity_id) + + state = hass.states.get(entity_id) + assert ( + state.attributes[ATTR_UNIT_OF_MEASUREMENT] + == CONCENTRATION_MICROGRAMS_PER_CUBIC_METER + ) + + assert state.state == "49"