Add Blebox air quality support (#35372)

* support BleBox air-quality

* fixed switch tests via cherry-pick from #35552

* fix test after cherry-picking

* fix flake8 issues
This commit is contained in:
gadgetmobile 2020-05-16 17:51:37 +02:00 committed by GitHub
parent 73616520c0
commit 6e0359efa6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 142 additions and 20 deletions

View File

@ -17,7 +17,7 @@ from .const import DEFAULT_SETUP_TIMEOUT, DOMAIN, PRODUCT
_LOGGER = logging.getLogger(__name__)
PLATFORMS = ["cover", "sensor", "switch"]
PLATFORMS = ["cover", "sensor", "switch", "air_quality"]
PARALLEL_UPDATES = 0
@ -74,9 +74,11 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
@callback
def create_blebox_entities(product, async_add, entity_klass, entity_type):
def create_blebox_entities(hass, config_entry, async_add, entity_klass, entity_type):
"""Create entities from a BleBox product's features."""
product = hass.data[DOMAIN][config_entry.entry_id][PRODUCT]
entities = []
if entity_type in product.features:
for feature in product.features[entity_type]:

View File

@ -0,0 +1,36 @@
"""BleBox air quality entity."""
from homeassistant.components.air_quality import AirQualityEntity
from . import BleBoxEntity, create_blebox_entities
async def async_setup_entry(hass, config_entry, async_add):
"""Set up a BleBox air quality entity."""
create_blebox_entities(
hass, config_entry, async_add, BleBoxAirQualityEntity, "air_qualities"
)
class BleBoxAirQualityEntity(BleBoxEntity, AirQualityEntity):
"""Representation of a BleBox air quality feature."""
@property
def icon(self):
"""Return the icon."""
return "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

View File

@ -13,20 +13,13 @@ from homeassistant.components.cover import (
)
from . import BleBoxEntity, create_blebox_entities
from .const import (
BLEBOX_TO_HASS_COVER_STATES,
BLEBOX_TO_HASS_DEVICE_CLASSES,
DOMAIN,
PRODUCT,
)
from .const import BLEBOX_TO_HASS_COVER_STATES, BLEBOX_TO_HASS_DEVICE_CLASSES
async def async_setup_entry(hass, config_entry, async_add):
"""Set up a BleBox entry."""
product = hass.data[DOMAIN][config_entry.entry_id][PRODUCT]
create_blebox_entities(product, async_add, BleBoxCoverEntity, "covers")
return True
create_blebox_entities(hass, config_entry, async_add, BleBoxCoverEntity, "covers")
class BleBoxCoverEntity(BleBoxEntity, CoverEntity):

View File

@ -3,15 +3,13 @@
from homeassistant.helpers.entity import Entity
from . import BleBoxEntity, create_blebox_entities
from .const import BLEBOX_TO_HASS_DEVICE_CLASSES, BLEBOX_TO_UNIT_MAP, DOMAIN, PRODUCT
from .const import BLEBOX_TO_HASS_DEVICE_CLASSES, BLEBOX_TO_UNIT_MAP
async def async_setup_entry(hass, config_entry, async_add):
"""Set up a BleBox entry."""
product = hass.data[DOMAIN][config_entry.entry_id][PRODUCT]
create_blebox_entities(product, async_add, BleBoxSensorEntity, "sensors")
return True
create_blebox_entities(hass, config_entry, async_add, BleBoxSensorEntity, "sensors")
class BleBoxSensorEntity(BleBoxEntity, Entity):

View File

@ -2,15 +2,14 @@
from homeassistant.components.switch import SwitchDevice
from . import BleBoxEntity, create_blebox_entities
from .const import BLEBOX_TO_HASS_DEVICE_CLASSES, DOMAIN, PRODUCT
from .const import BLEBOX_TO_HASS_DEVICE_CLASSES
async def async_setup_entry(hass, config_entry, async_add):
"""Set up a BleBox switch entity."""
product = hass.data[DOMAIN][config_entry.entry_id][PRODUCT]
create_blebox_entities(product, async_add, BleBoxSwitchEntity, "switches")
return True
create_blebox_entities(
hass, config_entry, async_add, BleBoxSwitchEntity, "switches"
)
class BleBoxSwitchEntity(BleBoxEntity, SwitchDevice):

View File

@ -0,0 +1,94 @@
"""Blebox air_quality tests."""
import logging
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 .conftest import async_setup_entity, mock_feature
from tests.async_mock import AsyncMock, PropertyMock
@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 = await hass.helpers.device_registry.async_get_registry()
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