diff --git a/homeassistant/components/blebox/__init__.py b/homeassistant/components/blebox/__init__.py index 35a334f36f3..4314412a13d 100644 --- a/homeassistant/components/blebox/__init__.py +++ b/homeassistant/components/blebox/__init__.py @@ -1,5 +1,6 @@ """The BleBox devices integration.""" import logging +from typing import Generic, TypeVar from blebox_uniapi.box import Box from blebox_uniapi.error import Error @@ -8,7 +9,7 @@ from blebox_uniapi.session import ApiHost from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_PORT, Platform -from homeassistant.core import HomeAssistant, callback +from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.entity import DeviceInfo, Entity @@ -28,6 +29,8 @@ PLATFORMS = [ PARALLEL_UPDATES = 0 +_FeatureT = TypeVar("_FeatureT", bound=Feature) + async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up BleBox devices from a config entry.""" @@ -64,26 +67,10 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: return unload_ok -@callback -def create_blebox_entities( - hass, config_entry, async_add_entities, 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]: - entities.append(entity_klass(feature)) - - async_add_entities(entities, True) - - -class BleBoxEntity(Entity): +class BleBoxEntity(Entity, Generic[_FeatureT]): """Implements a common class for entities representing a BleBox feature.""" - def __init__(self, feature: Feature) -> None: + def __init__(self, feature: _FeatureT) -> None: """Initialize a BleBox entity.""" self._feature = feature self._attr_name = feature.full_name diff --git a/homeassistant/components/blebox/button.py b/homeassistant/components/blebox/button.py index e9ceaac2dc7..93a5a4e0c5a 100644 --- a/homeassistant/components/blebox/button.py +++ b/homeassistant/components/blebox/button.py @@ -1,12 +1,16 @@ """BleBox button entities implementation.""" from __future__ import annotations +from blebox_uniapi.box import Box +import blebox_uniapi.button + from homeassistant.components.button import ButtonEntity from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import BleBoxEntity, create_blebox_entities +from . import BleBoxEntity +from .const import DOMAIN, PRODUCT async def async_setup_entry( @@ -15,20 +19,23 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up a BleBox button entry.""" - create_blebox_entities( - hass, config_entry, async_add_entities, BleBoxButtonEntity, "buttons" - ) + product: Box = hass.data[DOMAIN][config_entry.entry_id][PRODUCT] + + entities = [ + BleBoxButtonEntity(feature) for feature in product.features.get("buttons", []) + ] + async_add_entities(entities, True) -class BleBoxButtonEntity(BleBoxEntity, ButtonEntity): +class BleBoxButtonEntity(BleBoxEntity[blebox_uniapi.button.Button], ButtonEntity): """Representation of BleBox buttons.""" - def __init__(self, feature): + def __init__(self, feature: blebox_uniapi.button.Button) -> None: """Initialize a BleBox button feature.""" super().__init__(feature) self._attr_icon = self.get_icon() - def get_icon(self): + def get_icon(self) -> str | None: """Return icon for endpoint.""" if "up" in self._feature.query_string: return "mdi:arrow-up-circle" @@ -40,7 +47,7 @@ class BleBoxButtonEntity(BleBoxEntity, ButtonEntity): return "mdi:arrow-up-circle" if "close" in self._feature.query_string: return "mdi:arrow-down-circle" - return "" + return None async def async_press(self) -> None: """Handle the button press.""" diff --git a/homeassistant/components/blebox/climate.py b/homeassistant/components/blebox/climate.py index 65920b170c5..9b632c9aceb 100644 --- a/homeassistant/components/blebox/climate.py +++ b/homeassistant/components/blebox/climate.py @@ -2,6 +2,9 @@ from datetime import timedelta from typing import Any +from blebox_uniapi.box import Box +import blebox_uniapi.climate + from homeassistant.components.climate import ( ClimateEntity, ClimateEntityFeature, @@ -13,7 +16,8 @@ from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import BleBoxEntity, create_blebox_entities +from . import BleBoxEntity +from .const import DOMAIN, PRODUCT SCAN_INTERVAL = timedelta(seconds=5) @@ -24,13 +28,15 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up a BleBox climate entity.""" + product: Box = hass.data[DOMAIN][config_entry.entry_id][PRODUCT] - create_blebox_entities( - hass, config_entry, async_add_entities, BleBoxClimateEntity, "climates" - ) + entities = [ + BleBoxClimateEntity(feature) for feature in product.features.get("climates", []) + ] + async_add_entities(entities, True) -class BleBoxClimateEntity(BleBoxEntity, ClimateEntity): +class BleBoxClimateEntity(BleBoxEntity[blebox_uniapi.climate.Climate], ClimateEntity): """Representation of a BleBox climate feature (saunaBox).""" _attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE diff --git a/homeassistant/components/blebox/cover.py b/homeassistant/components/blebox/cover.py index 882356f1a77..80e2fbd30e7 100644 --- a/homeassistant/components/blebox/cover.py +++ b/homeassistant/components/blebox/cover.py @@ -3,6 +3,9 @@ from __future__ import annotations from typing import Any +from blebox_uniapi.box import Box +import blebox_uniapi.cover + from homeassistant.components.cover import ( ATTR_POSITION, CoverDeviceClass, @@ -14,7 +17,8 @@ from homeassistant.const import STATE_CLOSED, STATE_CLOSING, STATE_OPEN, STATE_O from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import BleBoxEntity, create_blebox_entities +from . import BleBoxEntity +from .const import DOMAIN, PRODUCT BLEBOX_TO_COVER_DEVICE_CLASSES = { "gate": CoverDeviceClass.GATE, @@ -44,16 +48,17 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up a BleBox entry.""" - - create_blebox_entities( - hass, config_entry, async_add_entities, BleBoxCoverEntity, "covers" - ) + product: Box = hass.data[DOMAIN][config_entry.entry_id][PRODUCT] + entities = [ + BleBoxCoverEntity(feature) for feature in product.features.get("covers", []) + ] + async_add_entities(entities, True) -class BleBoxCoverEntity(BleBoxEntity, CoverEntity): +class BleBoxCoverEntity(BleBoxEntity[blebox_uniapi.cover.Cover], CoverEntity): """Representation of a BleBox cover feature.""" - def __init__(self, feature): + def __init__(self, feature: blebox_uniapi.cover.Cover) -> None: """Initialize a BleBox cover feature.""" super().__init__(feature) self._attr_device_class = BLEBOX_TO_COVER_DEVICE_CLASSES[feature.device_class] diff --git a/homeassistant/components/blebox/light.py b/homeassistant/components/blebox/light.py index c1245d52fec..b138aae15b7 100644 --- a/homeassistant/components/blebox/light.py +++ b/homeassistant/components/blebox/light.py @@ -5,6 +5,7 @@ from datetime import timedelta import logging from typing import Any +from blebox_uniapi.box import Box import blebox_uniapi.light from blebox_uniapi.light import BleboxColorMode @@ -23,7 +24,8 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import BleBoxEntity, create_blebox_entities +from . import BleBoxEntity +from .const import DOMAIN, PRODUCT _LOGGER = logging.getLogger(__name__) @@ -36,10 +38,11 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up a BleBox entry.""" - - create_blebox_entities( - hass, config_entry, async_add_entities, BleBoxLightEntity, "lights" - ) + product: Box = hass.data[DOMAIN][config_entry.entry_id][PRODUCT] + entities = [ + BleBoxLightEntity(feature) for feature in product.features.get("lights", []) + ] + async_add_entities(entities, True) COLOR_MODE_MAP = { @@ -53,11 +56,9 @@ COLOR_MODE_MAP = { } -class BleBoxLightEntity(BleBoxEntity, LightEntity): +class BleBoxLightEntity(BleBoxEntity[blebox_uniapi.light.Light], LightEntity): """Representation of BleBox lights.""" - _feature: blebox_uniapi.light.Light - def __init__(self, feature: blebox_uniapi.light.Light) -> None: """Initialize a BleBox light.""" super().__init__(feature) diff --git a/homeassistant/components/blebox/sensor.py b/homeassistant/components/blebox/sensor.py index f3c0c393fd9..60d94507f4b 100644 --- a/homeassistant/components/blebox/sensor.py +++ b/homeassistant/components/blebox/sensor.py @@ -1,6 +1,9 @@ """BleBox sensor entities.""" from dataclasses import dataclass +from blebox_uniapi.box import Box +import blebox_uniapi.sensor + from homeassistant.components.sensor import ( SensorDeviceClass, SensorEntity, @@ -11,7 +14,8 @@ from homeassistant.const import CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, TEMP_C from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import BleBoxEntity, create_blebox_entities +from . import BleBoxEntity +from .const import DOMAIN, PRODUCT @dataclass @@ -49,16 +53,17 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up a BleBox entry.""" - - create_blebox_entities( - hass, config_entry, async_add_entities, BleBoxSensorEntity, "sensors" - ) + product: Box = hass.data[DOMAIN][config_entry.entry_id][PRODUCT] + entities = [ + BleBoxSensorEntity(feature) for feature in product.features.get("sensors", []) + ] + async_add_entities(entities, True) -class BleBoxSensorEntity(BleBoxEntity, SensorEntity): +class BleBoxSensorEntity(BleBoxEntity[blebox_uniapi.sensor.BaseSensor], SensorEntity): """Representation of a BleBox sensor feature.""" - def __init__(self, feature): + def __init__(self, feature: blebox_uniapi.sensor.BaseSensor) -> None: """Initialize a BleBox sensor feature.""" super().__init__(feature) diff --git a/homeassistant/components/blebox/switch.py b/homeassistant/components/blebox/switch.py index 5ae37d6b34d..d7145ebb620 100644 --- a/homeassistant/components/blebox/switch.py +++ b/homeassistant/components/blebox/switch.py @@ -2,12 +2,16 @@ from datetime import timedelta from typing import Any +from blebox_uniapi.box import Box +import blebox_uniapi.switch + from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import BleBoxEntity, create_blebox_entities +from . import BleBoxEntity +from .const import DOMAIN, PRODUCT SCAN_INTERVAL = timedelta(seconds=5) @@ -18,15 +22,17 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up a BleBox switch entity.""" - create_blebox_entities( - hass, config_entry, async_add_entities, BleBoxSwitchEntity, "switches" - ) + product: Box = hass.data[DOMAIN][config_entry.entry_id][PRODUCT] + entities = [ + BleBoxSwitchEntity(feature) for feature in product.features.get("switches", []) + ] + async_add_entities(entities, True) -class BleBoxSwitchEntity(BleBoxEntity, SwitchEntity): +class BleBoxSwitchEntity(BleBoxEntity[blebox_uniapi.switch.Switch], SwitchEntity): """Representation of a BleBox switch feature.""" - def __init__(self, feature): + def __init__(self, feature: blebox_uniapi.switch.Switch) -> None: """Initialize a BleBox switch feature.""" super().__init__(feature) self._attr_device_class = SwitchDeviceClass.SWITCH diff --git a/tests/components/blebox/test_init.py b/tests/components/blebox/test_init.py index c0add2696b5..9320c3c271c 100644 --- a/tests/components/blebox/test_init.py +++ b/tests/components/blebox/test_init.py @@ -7,7 +7,7 @@ import blebox_uniapi from homeassistant.components.blebox.const import DOMAIN from homeassistant.config_entries import ConfigEntryState -from .conftest import mock_config, patch_product_identify +from .conftest import mock_config, patch_product_identify, setup_product_mock async def test_setup_failure(hass, caplog): @@ -44,7 +44,7 @@ async def test_setup_failure_on_connection(hass, caplog): async def test_unload_config_entry(hass): """Test that unloading works properly.""" - patch_product_identify(None) + setup_product_mock("switches", []) entry = mock_config() entry.add_to_hass(hass)