Add blebox tvLiftBox support (#74395)

* Added tvLiftBox support.

* Changes after @epenet code review.

* After @epenet code review, dictionaries moved to relevant modules.

* Import path changed to full path.

* Removed redundant code in BLEBOX_TO_<platform>_DEVICE_CLASSES for switch and button platforms.

* Post isort on covers.

* Added tests, required version bump. As property was added inside dependency.
This commit is contained in:
Michał Huryn 2022-07-11 12:24:37 +02:00 committed by GitHub
parent c80066072c
commit ca93aacc57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 141 additions and 28 deletions

View File

@ -17,12 +17,13 @@ from .const import DEFAULT_SETUP_TIMEOUT, DOMAIN, PRODUCT
_LOGGER = logging.getLogger(__name__)
PLATFORMS = [
Platform.AIR_QUALITY,
Platform.BUTTON,
Platform.CLIMATE,
Platform.COVER,
Platform.LIGHT,
Platform.SENSOR,
Platform.SWITCH,
Platform.AIR_QUALITY,
Platform.LIGHT,
Platform.CLIMATE,
]
PARALLEL_UPDATES = 0

View File

@ -0,0 +1,48 @@
"""BleBox button entities implementation."""
from __future__ import annotations
from homeassistant.components.button import ButtonDeviceClass, 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
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up a BleBox button entry."""
create_blebox_entities(
hass, config_entry, async_add_entities, BleBoxButtonEntity, "buttons"
)
class BleBoxButtonEntity(BleBoxEntity, ButtonEntity):
"""Representation of BleBox buttons."""
def __init__(self, feature):
"""Initialize a BleBox button feature."""
super().__init__(feature)
self._attr_device_class = ButtonDeviceClass.UPDATE
self._attr_icon = self.get_icon()
def get_icon(self):
"""Return icon for endpoint."""
if "up" in self._feature.query_string:
return "mdi:arrow-up-circle"
if "down" in self._feature.query_string:
return "mdi:arrow-down-circle"
if "fav" in self._feature.query_string:
return "mdi:heart-circle"
if "open" in self._feature.query_string:
return "mdi:arrow-up-circle"
if "close" in self._feature.query_string:
return "mdi:arrow-down-circle"
return ""
async def async_press(self) -> None:
"""Handle the button press."""
await self._feature.set()

View File

@ -1,9 +1,5 @@
"""Constants for the BleBox devices integration."""
from homeassistant.components.cover import CoverDeviceClass
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.components.switch import SwitchDeviceClass
from homeassistant.const import TEMP_CELSIUS
DOMAIN = "blebox"
PRODUCT = "product"
@ -16,16 +12,6 @@ CANNOT_CONNECT = "cannot_connect"
UNSUPPORTED_VERSION = "unsupported_version"
UNKNOWN = "unknown"
BLEBOX_TO_HASS_DEVICE_CLASSES = {
"shutter": CoverDeviceClass.SHUTTER,
"gatebox": CoverDeviceClass.DOOR,
"gate": CoverDeviceClass.GATE,
"relay": SwitchDeviceClass.SWITCH,
"temperature": SensorDeviceClass.TEMPERATURE,
}
BLEBOX_TO_UNIT_MAP = {"celsius": TEMP_CELSIUS}
DEFAULT_HOST = "192.168.0.2"
DEFAULT_PORT = 80

View File

@ -5,6 +5,7 @@ from typing import Any
from homeassistant.components.cover import (
ATTR_POSITION,
CoverDeviceClass,
CoverEntity,
CoverEntityFeature,
)
@ -14,7 +15,13 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import BleBoxEntity, create_blebox_entities
from .const import BLEBOX_TO_HASS_DEVICE_CLASSES
BLEBOX_TO_COVER_DEVICE_CLASSES = {
"gate": CoverDeviceClass.GATE,
"gatebox": CoverDeviceClass.DOOR,
"shutter": CoverDeviceClass.SHUTTER,
}
BLEBOX_TO_HASS_COVER_STATES = {
None: None,
@ -49,7 +56,7 @@ class BleBoxCoverEntity(BleBoxEntity, CoverEntity):
def __init__(self, feature):
"""Initialize a BleBox cover feature."""
super().__init__(feature)
self._attr_device_class = BLEBOX_TO_HASS_DEVICE_CLASSES[feature.device_class]
self._attr_device_class = BLEBOX_TO_COVER_DEVICE_CLASSES[feature.device_class]
position = CoverEntityFeature.SET_POSITION if feature.is_slider else 0
stop = CoverEntityFeature.STOP if feature.has_stop else 0
self._attr_supported_features = (

View File

@ -3,7 +3,7 @@
"name": "BleBox devices",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/blebox",
"requirements": ["blebox_uniapi==2.0.1"],
"requirements": ["blebox_uniapi==2.0.2"],
"codeowners": ["@bbx-a", "@riokuu"],
"iot_class": "local_polling",
"loggers": ["blebox_uniapi"]

View File

@ -1,11 +1,15 @@
"""BleBox sensor entities."""
from homeassistant.components.sensor import SensorEntity
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import TEMP_CELSIUS
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import BleBoxEntity, create_blebox_entities
from .const import BLEBOX_TO_HASS_DEVICE_CLASSES, BLEBOX_TO_UNIT_MAP
BLEBOX_TO_UNIT_MAP = {"celsius": TEMP_CELSIUS}
BLEBOX_TO_SENSOR_DEVICE_CLASS = {"temperature": SensorDeviceClass.TEMPERATURE}
async def async_setup_entry(
@ -27,7 +31,7 @@ class BleBoxSensorEntity(BleBoxEntity, SensorEntity):
"""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_HASS_DEVICE_CLASSES[feature.device_class]
self._attr_device_class = BLEBOX_TO_SENSOR_DEVICE_CLASS[feature.device_class]
@property
def native_value(self):

View File

@ -1,13 +1,12 @@
"""BleBox switch implementation."""
from datetime import timedelta
from homeassistant.components.switch import SwitchEntity
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 .const import BLEBOX_TO_HASS_DEVICE_CLASSES
SCAN_INTERVAL = timedelta(seconds=5)
@ -29,7 +28,7 @@ class BleBoxSwitchEntity(BleBoxEntity, SwitchEntity):
def __init__(self, feature):
"""Initialize a BleBox switch feature."""
super().__init__(feature)
self._attr_device_class = BLEBOX_TO_HASS_DEVICE_CLASSES[feature.device_class]
self._attr_device_class = SwitchDeviceClass.SWITCH
@property
def is_on(self):

View File

@ -405,7 +405,7 @@ bizkaibus==0.1.1
bleak==0.14.3
# homeassistant.components.blebox
blebox_uniapi==2.0.1
blebox_uniapi==2.0.2
# homeassistant.components.blink
blinkpy==0.19.0

View File

@ -320,7 +320,7 @@ bimmer_connected==0.9.6
bleak==0.14.3
# homeassistant.components.blebox
blebox_uniapi==2.0.1
blebox_uniapi==2.0.2
# homeassistant.components.blink
blinkpy==0.19.0

View File

@ -0,0 +1,68 @@
"""Blebox button entities tests."""
import logging
from unittest.mock import PropertyMock
import blebox_uniapi
import pytest
from homeassistant.components.button import ButtonDeviceClass
from homeassistant.const import ATTR_ICON
from .conftest import async_setup_entity, mock_feature
query_icon_matching = [
("up", "mdi:arrow-up-circle"),
("down", "mdi:arrow-down-circle"),
("fav", "mdi:heart-circle"),
("open", "mdi:arrow-up-circle"),
("close", "mdi:arrow-down-circle"),
]
@pytest.fixture(name="tvliftbox")
def tv_lift_box_fixture(caplog):
"""Return simple button entity mock."""
caplog.set_level(logging.ERROR)
feature = mock_feature(
"buttons",
blebox_uniapi.button.Button,
unique_id="BleBox-tvLiftBox-4a3fdaad90aa-open_or_stop",
full_name="tvLiftBox-open_or_stop",
control_type=blebox_uniapi.button.ControlType.OPEN,
)
product = feature.product
type(product).name = PropertyMock(return_value="My tvLiftBox")
type(product).model = PropertyMock(return_value="tvLiftBox")
type(product)._query_string = PropertyMock(return_value="open_or_stop")
return (feature, "button.tvliftbox_open_or_stop")
async def test_tvliftbox_init(tvliftbox, hass, config, caplog):
"""Test tvLiftBox initialisation."""
caplog.set_level(logging.ERROR)
_, entity_id = tvliftbox
entry = await async_setup_entity(hass, config, entity_id)
state = hass.states.get(entity_id)
assert entry.unique_id == "BleBox-tvLiftBox-4a3fdaad90aa-open_or_stop"
assert state.attributes["device_class"] == ButtonDeviceClass.UPDATE
assert state.name == "tvLiftBox-open_or_stop"
@pytest.mark.parametrize("input", query_icon_matching)
async def test_get_icon(input, tvliftbox, hass, config, caplog):
"""Test if proper icon is returned."""
caplog.set_level(logging.ERROR)
feature_mock, entity_id = tvliftbox
feature_mock.query_string = input[0]
_ = await async_setup_entity(hass, config, entity_id)
state = hass.states.get(entity_id)
assert state.attributes[ATTR_ICON] == input[1]