mirror of
https://github.com/home-assistant/core.git
synced 2025-12-24 21:06:19 +00:00
Add dynamic devices to Homee (#151934)
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from pyHomee.const import AttributeChangedBy, AttributeType
|
||||
from pyHomee.model import HomeeAttribute
|
||||
from pyHomee.model import HomeeAttribute, HomeeNode
|
||||
|
||||
from homeassistant.components.alarm_control_panel import (
|
||||
AlarmControlPanelEntity,
|
||||
@@ -17,7 +17,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import DOMAIN, HomeeConfigEntry
|
||||
from .entity import HomeeEntity
|
||||
from .helpers import get_name_for_enum
|
||||
from .helpers import get_name_for_enum, setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -60,18 +60,29 @@ def get_supported_features(
|
||||
return supported_features
|
||||
|
||||
|
||||
async def add_alarm_control_panel_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee alarm control panel entities."""
|
||||
async_add_entities(
|
||||
HomeeAlarmPanel(attribute, config_entry, ALARM_DESCRIPTIONS[attribute.type])
|
||||
for node in nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in ALARM_DESCRIPTIONS and attribute.editable
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the Homee platform for the alarm control panel component."""
|
||||
"""Add the homee platform for the alarm control panel component."""
|
||||
|
||||
async_add_entities(
|
||||
HomeeAlarmPanel(attribute, config_entry, ALARM_DESCRIPTIONS[attribute.type])
|
||||
for node in config_entry.runtime_data.nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in ALARM_DESCRIPTIONS and attribute.editable
|
||||
await setup_homee_platform(
|
||||
add_alarm_control_panel_entities, async_add_entities, config_entry
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""The Homee binary sensor platform."""
|
||||
|
||||
from pyHomee.const import AttributeType
|
||||
from pyHomee.model import HomeeAttribute
|
||||
from pyHomee.model import HomeeAttribute, HomeeNode
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
BinarySensorDeviceClass,
|
||||
@@ -14,6 +14,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import HomeeConfigEntry
|
||||
from .entity import HomeeEntity
|
||||
from .helpers import setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -152,23 +153,34 @@ BINARY_SENSOR_DESCRIPTIONS: dict[AttributeType, BinarySensorEntityDescription] =
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
async def add_binary_sensor_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_devices: AddConfigEntryEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add the Homee platform for the binary sensor component."""
|
||||
|
||||
async_add_devices(
|
||||
"""Add homee binary sensor entities."""
|
||||
async_add_entities(
|
||||
HomeeBinarySensor(
|
||||
attribute, config_entry, BINARY_SENSOR_DESCRIPTIONS[attribute.type]
|
||||
)
|
||||
for node in config_entry.runtime_data.nodes
|
||||
for node in nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in BINARY_SENSOR_DESCRIPTIONS and not attribute.editable
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the homee platform for the binary sensor component."""
|
||||
|
||||
await setup_homee_platform(
|
||||
add_binary_sensor_entities, async_add_entities, config_entry
|
||||
)
|
||||
|
||||
|
||||
class HomeeBinarySensor(HomeeEntity, BinarySensorEntity):
|
||||
"""Representation of a Homee binary sensor."""
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""The homee button platform."""
|
||||
|
||||
from pyHomee.const import AttributeType
|
||||
from pyHomee.model import HomeeAttribute
|
||||
from pyHomee.model import HomeeAttribute, HomeeNode
|
||||
|
||||
from homeassistant.components.button import (
|
||||
ButtonDeviceClass,
|
||||
@@ -14,6 +14,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import HomeeConfigEntry
|
||||
from .entity import HomeeEntity
|
||||
from .helpers import setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -39,19 +40,28 @@ BUTTON_DESCRIPTIONS: dict[AttributeType, ButtonEntityDescription] = {
|
||||
}
|
||||
|
||||
|
||||
async def add_button_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee button entities."""
|
||||
async_add_entities(
|
||||
HomeeButton(attribute, config_entry, BUTTON_DESCRIPTIONS[attribute.type])
|
||||
for node in nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in BUTTON_DESCRIPTIONS and attribute.editable
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the Homee platform for the button component."""
|
||||
"""Add the homee platform for the button component."""
|
||||
|
||||
async_add_entities(
|
||||
HomeeButton(attribute, config_entry, BUTTON_DESCRIPTIONS[attribute.type])
|
||||
for node in config_entry.runtime_data.nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in BUTTON_DESCRIPTIONS and attribute.editable
|
||||
)
|
||||
await setup_homee_platform(add_button_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
class HomeeButton(HomeeEntity, ButtonEntity):
|
||||
|
||||
@@ -21,6 +21,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from . import HomeeConfigEntry
|
||||
from .const import CLIMATE_PROFILES, DOMAIN, HOMEE_UNIT_TO_HA_UNIT, PRESET_MANUAL
|
||||
from .entity import HomeeNodeEntity
|
||||
from .helpers import setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -31,18 +32,27 @@ ROOM_THERMOSTATS = {
|
||||
}
|
||||
|
||||
|
||||
async def add_climate_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee climate entities."""
|
||||
async_add_entities(
|
||||
HomeeClimate(node, config_entry)
|
||||
for node in nodes
|
||||
if node.profile in CLIMATE_PROFILES
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_devices: AddConfigEntryEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the Homee platform for the climate component."""
|
||||
|
||||
async_add_devices(
|
||||
HomeeClimate(node, config_entry)
|
||||
for node in config_entry.runtime_data.nodes
|
||||
if node.profile in CLIMATE_PROFILES
|
||||
)
|
||||
await setup_homee_platform(add_climate_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
class HomeeClimate(HomeeNodeEntity, ClimateEntity):
|
||||
|
||||
@@ -18,6 +18,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import HomeeConfigEntry
|
||||
from .entity import HomeeNodeEntity
|
||||
from .helpers import setup_homee_platform
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -77,18 +78,25 @@ def get_device_class(node: HomeeNode) -> CoverDeviceClass | None:
|
||||
return COVER_DEVICE_PROFILES.get(node.profile)
|
||||
|
||||
|
||||
async def add_cover_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee cover entities."""
|
||||
async_add_entities(
|
||||
HomeeCover(node, config_entry) for node in nodes if is_cover_node(node)
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_devices: AddConfigEntryEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the homee platform for the cover integration."""
|
||||
|
||||
async_add_devices(
|
||||
HomeeCover(node, config_entry)
|
||||
for node in config_entry.runtime_data.nodes
|
||||
if is_cover_node(node)
|
||||
)
|
||||
await setup_homee_platform(add_cover_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
def is_cover_node(node: HomeeNode) -> bool:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""The homee event platform."""
|
||||
|
||||
from pyHomee.const import AttributeType, NodeProfile
|
||||
from pyHomee.model import HomeeAttribute
|
||||
from pyHomee.model import HomeeAttribute, HomeeNode
|
||||
|
||||
from homeassistant.components.event import (
|
||||
EventDeviceClass,
|
||||
@@ -13,6 +13,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import HomeeConfigEntry
|
||||
from .entity import HomeeEntity
|
||||
from .helpers import setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -49,6 +50,22 @@ EVENT_DESCRIPTIONS: dict[AttributeType, EventEntityDescription] = {
|
||||
}
|
||||
|
||||
|
||||
async def add_event_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee event entities."""
|
||||
async_add_entities(
|
||||
HomeeEvent(attribute, config_entry, EVENT_DESCRIPTIONS[attribute.type])
|
||||
for node in nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in EVENT_DESCRIPTIONS
|
||||
and node.profile in REMOTE_PROFILES
|
||||
and not attribute.editable
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
@@ -56,14 +73,7 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Add event entities for homee."""
|
||||
|
||||
async_add_entities(
|
||||
HomeeEvent(attribute, config_entry, EVENT_DESCRIPTIONS[attribute.type])
|
||||
for node in config_entry.runtime_data.nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in EVENT_DESCRIPTIONS
|
||||
and node.profile in REMOTE_PROFILES
|
||||
and not attribute.editable
|
||||
)
|
||||
await setup_homee_platform(add_event_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
class HomeeEvent(HomeeEntity, EventEntity):
|
||||
|
||||
@@ -19,22 +19,32 @@ from homeassistant.util.scaling import int_states_in_range
|
||||
from . import HomeeConfigEntry
|
||||
from .const import DOMAIN, PRESET_AUTO, PRESET_MANUAL, PRESET_SUMMER
|
||||
from .entity import HomeeNodeEntity
|
||||
from .helpers import setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
|
||||
async def add_fan_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee fan entities."""
|
||||
async_add_entities(
|
||||
HomeeFan(node, config_entry)
|
||||
for node in nodes
|
||||
if node.profile == NodeProfile.VENTILATION_CONTROL
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_devices: AddConfigEntryEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Homee fan platform."""
|
||||
|
||||
async_add_devices(
|
||||
HomeeFan(node, config_entry)
|
||||
for node in config_entry.runtime_data.nodes
|
||||
if node.profile == NodeProfile.VENTILATION_CONTROL
|
||||
)
|
||||
await setup_homee_platform(add_fan_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
class HomeeFan(HomeeNodeEntity, FanEntity):
|
||||
|
||||
@@ -1,11 +1,42 @@
|
||||
"""Helper functions for the homee custom component."""
|
||||
|
||||
from collections.abc import Callable, Coroutine
|
||||
from enum import IntEnum
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from pyHomee.model import HomeeNode
|
||||
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import HomeeConfigEntry
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def setup_homee_platform(
|
||||
add_platform_entities: Callable[
|
||||
[HomeeConfigEntry, AddConfigEntryEntitiesCallback, list[HomeeNode]],
|
||||
Coroutine[Any, Any, None],
|
||||
],
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
config_entry: HomeeConfigEntry,
|
||||
) -> None:
|
||||
"""Set up a homee platform."""
|
||||
await add_platform_entities(
|
||||
config_entry, async_add_entities, config_entry.runtime_data.nodes
|
||||
)
|
||||
|
||||
async def add_device(node: HomeeNode, add: bool) -> None:
|
||||
"""Dynamically add entities."""
|
||||
if add:
|
||||
await add_platform_entities(config_entry, async_add_entities, [node])
|
||||
|
||||
config_entry.async_on_unload(
|
||||
config_entry.runtime_data.add_nodes_listener(add_device)
|
||||
)
|
||||
|
||||
|
||||
def get_name_for_enum(att_class: type[IntEnum], att_id: int) -> str | None:
|
||||
"""Return the enum item name for a given integer."""
|
||||
try:
|
||||
|
||||
@@ -24,6 +24,7 @@ from homeassistant.util.color import (
|
||||
from . import HomeeConfigEntry
|
||||
from .const import LIGHT_PROFILES
|
||||
from .entity import HomeeNodeEntity
|
||||
from .helpers import setup_homee_platform
|
||||
|
||||
LIGHT_ATTRIBUTES = [
|
||||
AttributeType.COLOR,
|
||||
@@ -85,19 +86,28 @@ def decimal_to_rgb_list(color: float) -> list[int]:
|
||||
]
|
||||
|
||||
|
||||
async def add_light_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee light entities."""
|
||||
async_add_entities(
|
||||
HomeeLight(node, light, config_entry)
|
||||
for node in nodes
|
||||
for light in get_light_attribute_sets(node)
|
||||
if is_light_node(node)
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the Homee platform for the light entity."""
|
||||
"""Add the homee platform for the light entity."""
|
||||
|
||||
async_add_entities(
|
||||
HomeeLight(node, light, config_entry)
|
||||
for node in config_entry.runtime_data.nodes
|
||||
for light in get_light_attribute_sets(node)
|
||||
if is_light_node(node)
|
||||
)
|
||||
await setup_homee_platform(add_light_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
class HomeeLight(HomeeNodeEntity, LightEntity):
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from typing import Any
|
||||
|
||||
from pyHomee.const import AttributeChangedBy, AttributeType
|
||||
from pyHomee.model import HomeeNode
|
||||
|
||||
from homeassistant.components.lock import LockEntity
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -10,24 +11,33 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import HomeeConfigEntry
|
||||
from .entity import HomeeEntity
|
||||
from .helpers import get_name_for_enum
|
||||
from .helpers import get_name_for_enum, setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
|
||||
async def add_lock_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee lock entities."""
|
||||
async_add_entities(
|
||||
HomeeLock(attribute, config_entry)
|
||||
for node in nodes
|
||||
for attribute in node.attributes
|
||||
if (attribute.type == AttributeType.LOCK_STATE and attribute.editable)
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_devices: AddConfigEntryEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the Homee platform for the lock component."""
|
||||
"""Add the homee platform for the lock component."""
|
||||
|
||||
async_add_devices(
|
||||
HomeeLock(attribute, config_entry)
|
||||
for node in config_entry.runtime_data.nodes
|
||||
for attribute in node.attributes
|
||||
if (attribute.type == AttributeType.LOCK_STATE and attribute.editable)
|
||||
)
|
||||
await setup_homee_platform(add_lock_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
class HomeeLock(HomeeEntity, LockEntity):
|
||||
|
||||
@@ -4,7 +4,7 @@ from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from pyHomee.const import AttributeType
|
||||
from pyHomee.model import HomeeAttribute
|
||||
from pyHomee.model import HomeeAttribute, HomeeNode
|
||||
|
||||
from homeassistant.components.number import (
|
||||
NumberDeviceClass,
|
||||
@@ -18,6 +18,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from . import HomeeConfigEntry
|
||||
from .const import HOMEE_UNIT_TO_HA_UNIT
|
||||
from .entity import HomeeEntity
|
||||
from .helpers import setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -136,19 +137,28 @@ NUMBER_DESCRIPTIONS = {
|
||||
}
|
||||
|
||||
|
||||
async def add_number_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee number entities."""
|
||||
async_add_entities(
|
||||
HomeeNumber(attribute, config_entry, NUMBER_DESCRIPTIONS[attribute.type])
|
||||
for node in nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in NUMBER_DESCRIPTIONS and attribute.data != "fixed_value"
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the Homee platform for the number component."""
|
||||
"""Add the homee platform for the number component."""
|
||||
|
||||
async_add_entities(
|
||||
HomeeNumber(attribute, config_entry, NUMBER_DESCRIPTIONS[attribute.type])
|
||||
for node in config_entry.runtime_data.nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in NUMBER_DESCRIPTIONS and attribute.data != "fixed_value"
|
||||
)
|
||||
await setup_homee_platform(add_number_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
class HomeeNumber(HomeeEntity, NumberEntity):
|
||||
|
||||
@@ -54,7 +54,7 @@ rules:
|
||||
docs-supported-functions: todo
|
||||
docs-troubleshooting: done
|
||||
docs-use-cases: todo
|
||||
dynamic-devices: todo
|
||||
dynamic-devices: done
|
||||
entity-category: done
|
||||
entity-device-class: done
|
||||
entity-disabled-by-default: done
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""The Homee select platform."""
|
||||
|
||||
from pyHomee.const import AttributeType
|
||||
from pyHomee.model import HomeeAttribute
|
||||
from pyHomee.model import HomeeAttribute, HomeeNode
|
||||
|
||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||
from homeassistant.const import EntityCategory
|
||||
@@ -10,6 +10,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import HomeeConfigEntry
|
||||
from .entity import HomeeEntity
|
||||
from .helpers import setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -27,19 +28,28 @@ SELECT_DESCRIPTIONS: dict[AttributeType, SelectEntityDescription] = {
|
||||
}
|
||||
|
||||
|
||||
async def add_select_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee select entities."""
|
||||
async_add_entities(
|
||||
HomeeSelect(attribute, config_entry, SELECT_DESCRIPTIONS[attribute.type])
|
||||
for node in nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in SELECT_DESCRIPTIONS and attribute.editable
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the Homee platform for the select component."""
|
||||
"""Add the homee platform for the select component."""
|
||||
|
||||
async_add_entities(
|
||||
HomeeSelect(attribute, config_entry, SELECT_DESCRIPTIONS[attribute.type])
|
||||
for node in config_entry.runtime_data.nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in SELECT_DESCRIPTIONS and attribute.editable
|
||||
)
|
||||
await setup_homee_platform(add_select_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
class HomeeSelect(HomeeEntity, SelectEntity):
|
||||
|
||||
@@ -35,7 +35,7 @@ from .const import (
|
||||
WINDOW_MAP_REVERSED,
|
||||
)
|
||||
from .entity import HomeeEntity, HomeeNodeEntity
|
||||
from .helpers import get_name_for_enum
|
||||
from .helpers import get_name_for_enum, setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -304,16 +304,16 @@ def entity_used_in(hass: HomeAssistant, entity_id: str) -> list[str]:
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_devices: AddConfigEntryEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the homee platform for the sensor components."""
|
||||
ent_reg = er.async_get(hass)
|
||||
devices: list[HomeeSensor | HomeeNodeSensor] = []
|
||||
|
||||
def add_deprecated_entity(
|
||||
attribute: HomeeAttribute, description: HomeeSensorEntityDescription
|
||||
) -> None:
|
||||
) -> list[HomeeSensor]:
|
||||
"""Add deprecated entities."""
|
||||
deprecated_entities: list[HomeeSensor] = []
|
||||
entity_uid = f"{config_entry.runtime_data.settings.uid}-{attribute.node_id}-{attribute.id}"
|
||||
if entity_id := ent_reg.async_get_entity_id(SENSOR_DOMAIN, DOMAIN, entity_uid):
|
||||
entity_entry = ent_reg.async_get(entity_id)
|
||||
@@ -325,7 +325,9 @@ async def async_setup_entry(
|
||||
f"deprecated_entity_{entity_uid}",
|
||||
)
|
||||
elif entity_entry:
|
||||
devices.append(HomeeSensor(attribute, config_entry, description))
|
||||
deprecated_entities.append(
|
||||
HomeeSensor(attribute, config_entry, description)
|
||||
)
|
||||
if entity_used_in(hass, entity_id):
|
||||
async_create_issue(
|
||||
hass,
|
||||
@@ -342,27 +344,42 @@ async def async_setup_entry(
|
||||
"entity": entity_id,
|
||||
},
|
||||
)
|
||||
return deprecated_entities
|
||||
|
||||
for node in config_entry.runtime_data.nodes:
|
||||
# Node properties that are sensors.
|
||||
devices.extend(
|
||||
HomeeNodeSensor(node, config_entry, description)
|
||||
for description in NODE_SENSOR_DESCRIPTIONS
|
||||
)
|
||||
async def add_sensor_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee sensor entities."""
|
||||
entities: list[HomeeSensor | HomeeNodeSensor] = []
|
||||
|
||||
# Node attributes that are sensors.
|
||||
for attribute in node.attributes:
|
||||
if attribute.type == AttributeType.CURRENT_VALVE_POSITION:
|
||||
add_deprecated_entity(attribute, SENSOR_DESCRIPTIONS[attribute.type])
|
||||
elif attribute.type in SENSOR_DESCRIPTIONS and not attribute.editable:
|
||||
devices.append(
|
||||
HomeeSensor(
|
||||
attribute, config_entry, SENSOR_DESCRIPTIONS[attribute.type]
|
||||
for node in nodes:
|
||||
# Node properties that are sensors.
|
||||
entities.extend(
|
||||
HomeeNodeSensor(node, config_entry, description)
|
||||
for description in NODE_SENSOR_DESCRIPTIONS
|
||||
)
|
||||
|
||||
# Node attributes that are sensors.
|
||||
for attribute in node.attributes:
|
||||
if attribute.type == AttributeType.CURRENT_VALVE_POSITION:
|
||||
entities.extend(
|
||||
add_deprecated_entity(
|
||||
attribute, SENSOR_DESCRIPTIONS[attribute.type]
|
||||
)
|
||||
)
|
||||
elif attribute.type in SENSOR_DESCRIPTIONS and not attribute.editable:
|
||||
entities.append(
|
||||
HomeeSensor(
|
||||
attribute, config_entry, SENSOR_DESCRIPTIONS[attribute.type]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if devices:
|
||||
async_add_devices(devices)
|
||||
if entities:
|
||||
async_add_entities(entities)
|
||||
|
||||
await setup_homee_platform(add_sensor_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
class HomeeSensor(HomeeEntity, SensorEntity):
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from typing import Any
|
||||
|
||||
from pyHomee.const import AttributeType
|
||||
from pyHomee.model import HomeeNode
|
||||
|
||||
from homeassistant.components.siren import SirenEntity, SirenEntityFeature
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -10,23 +11,33 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import HomeeConfigEntry
|
||||
from .entity import HomeeEntity
|
||||
from .helpers import setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
|
||||
async def add_siren_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee siren entities."""
|
||||
async_add_entities(
|
||||
HomeeSiren(attribute, config_entry)
|
||||
for node in nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type == AttributeType.SIREN
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_devices: AddConfigEntryEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add siren entities for homee."""
|
||||
|
||||
async_add_devices(
|
||||
HomeeSiren(attribute, config_entry)
|
||||
for node in config_entry.runtime_data.nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type == AttributeType.SIREN
|
||||
)
|
||||
await setup_homee_platform(add_siren_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
class HomeeSiren(HomeeEntity, SirenEntity):
|
||||
|
||||
@@ -5,7 +5,7 @@ from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from pyHomee.const import AttributeType, NodeProfile
|
||||
from pyHomee.model import HomeeAttribute
|
||||
from pyHomee.model import HomeeAttribute, HomeeNode
|
||||
|
||||
from homeassistant.components.switch import (
|
||||
SwitchDeviceClass,
|
||||
@@ -19,6 +19,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from . import HomeeConfigEntry
|
||||
from .const import CLIMATE_PROFILES, LIGHT_PROFILES
|
||||
from .entity import HomeeEntity
|
||||
from .helpers import setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -65,27 +66,35 @@ SWITCH_DESCRIPTIONS: dict[AttributeType, HomeeSwitchEntityDescription] = {
|
||||
}
|
||||
|
||||
|
||||
async def add_switch_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee switch entities."""
|
||||
async_add_entities(
|
||||
HomeeSwitch(attribute, config_entry, SWITCH_DESCRIPTIONS[attribute.type])
|
||||
for node in nodes
|
||||
for attribute in node.attributes
|
||||
if (attribute.type in SWITCH_DESCRIPTIONS and attribute.editable)
|
||||
and not (
|
||||
attribute.type == AttributeType.ON_OFF and node.profile in LIGHT_PROFILES
|
||||
)
|
||||
and not (
|
||||
attribute.type == AttributeType.MANUAL_OPERATION
|
||||
and node.profile in CLIMATE_PROFILES
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_devices: AddConfigEntryEntitiesCallback,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the switch platform for the Homee component."""
|
||||
|
||||
for node in config_entry.runtime_data.nodes:
|
||||
async_add_devices(
|
||||
HomeeSwitch(attribute, config_entry, SWITCH_DESCRIPTIONS[attribute.type])
|
||||
for attribute in node.attributes
|
||||
if (attribute.type in SWITCH_DESCRIPTIONS and attribute.editable)
|
||||
and not (
|
||||
attribute.type == AttributeType.ON_OFF
|
||||
and node.profile in LIGHT_PROFILES
|
||||
)
|
||||
and not (
|
||||
attribute.type == AttributeType.MANUAL_OPERATION
|
||||
and node.profile in CLIMATE_PROFILES
|
||||
)
|
||||
)
|
||||
await setup_homee_platform(add_switch_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
class HomeeSwitch(HomeeEntity, SwitchEntity):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""The Homee valve platform."""
|
||||
|
||||
from pyHomee.const import AttributeType
|
||||
from pyHomee.model import HomeeAttribute
|
||||
from pyHomee.model import HomeeAttribute, HomeeNode
|
||||
|
||||
from homeassistant.components.valve import (
|
||||
ValveDeviceClass,
|
||||
@@ -14,6 +14,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import HomeeConfigEntry
|
||||
from .entity import HomeeEntity
|
||||
from .helpers import setup_homee_platform
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -25,19 +26,28 @@ VALVE_DESCRIPTIONS = {
|
||||
}
|
||||
|
||||
|
||||
async def add_valve_entities(
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
nodes: list[HomeeNode],
|
||||
) -> None:
|
||||
"""Add homee valve entities."""
|
||||
async_add_entities(
|
||||
HomeeValve(attribute, config_entry, VALVE_DESCRIPTIONS[attribute.type])
|
||||
for node in nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in VALVE_DESCRIPTIONS
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: HomeeConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Add the Homee platform for the valve component."""
|
||||
"""Add the homee platform for the valve component."""
|
||||
|
||||
async_add_entities(
|
||||
HomeeValve(attribute, config_entry, VALVE_DESCRIPTIONS[attribute.type])
|
||||
for node in config_entry.runtime_data.nodes
|
||||
for attribute in node.attributes
|
||||
if attribute.type in VALVE_DESCRIPTIONS
|
||||
)
|
||||
await setup_homee_platform(add_valve_entities, async_add_entities, config_entry)
|
||||
|
||||
|
||||
class HomeeValve(HomeeEntity, ValveEntity):
|
||||
|
||||
176
tests/components/homee/fixtures/add_device.json
Normal file
176
tests/components/homee/fixtures/add_device.json
Normal file
@@ -0,0 +1,176 @@
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Added Device",
|
||||
"profile": 4010,
|
||||
"image": "default",
|
||||
"favorite": 0,
|
||||
"order": 20,
|
||||
"protocol": 1,
|
||||
"routing": 0,
|
||||
"state": 1,
|
||||
"state_changed": 1709379826,
|
||||
"added": 1676199446,
|
||||
"history": 1,
|
||||
"cube_type": 1,
|
||||
"note": "",
|
||||
"services": 5,
|
||||
"phonetic_name": "",
|
||||
"owner": 2,
|
||||
"security": 0,
|
||||
"attributes": [
|
||||
{
|
||||
"id": 21,
|
||||
"node_id": 3,
|
||||
"instance": 1,
|
||||
"minimum": 0,
|
||||
"maximum": 200000,
|
||||
"current_value": 555.591,
|
||||
"target_value": 555.591,
|
||||
"last_value": 555.586,
|
||||
"unit": "kWh",
|
||||
"step_value": 1.0,
|
||||
"editable": 0,
|
||||
"type": 4,
|
||||
"state": 1,
|
||||
"last_changed": 1694175270,
|
||||
"changed_by": 1,
|
||||
"changed_by_id": 0,
|
||||
"based_on": 1,
|
||||
"data": "",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"id": 22,
|
||||
"node_id": 3,
|
||||
"instance": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"current_value": 0.0,
|
||||
"target_value": 0.0,
|
||||
"last_value": 0.0,
|
||||
"unit": "",
|
||||
"step_value": 1.0,
|
||||
"editable": 0,
|
||||
"type": 17,
|
||||
"state": 1,
|
||||
"last_changed": 1691668428,
|
||||
"changed_by": 1,
|
||||
"changed_by_id": 0,
|
||||
"based_on": 1,
|
||||
"data": "",
|
||||
"name": "",
|
||||
"options": {
|
||||
"automations": ["reset"],
|
||||
"history": {
|
||||
"day": 182,
|
||||
"week": 26,
|
||||
"month": 6,
|
||||
"stepped": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 27,
|
||||
"node_id": 3,
|
||||
"instance": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"current_value": 100.0,
|
||||
"target_value": 100.0,
|
||||
"last_value": 100.0,
|
||||
"unit": "%",
|
||||
"step_value": 0.5,
|
||||
"editable": 1,
|
||||
"type": 349,
|
||||
"state": 1,
|
||||
"last_changed": 1624446307,
|
||||
"changed_by": 1,
|
||||
"changed_by_id": 0,
|
||||
"based_on": 1,
|
||||
"data": "",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"id": 28,
|
||||
"node_id": 3,
|
||||
"instance": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"current_value": 0.0,
|
||||
"target_value": 0.0,
|
||||
"last_value": 0.0,
|
||||
"unit": "",
|
||||
"step_value": 1.0,
|
||||
"editable": 1,
|
||||
"type": 346,
|
||||
"state": 1,
|
||||
"last_changed": 1624806728,
|
||||
"changed_by": 1,
|
||||
"changed_by_id": 0,
|
||||
"based_on": 1,
|
||||
"data": "",
|
||||
"name": ""
|
||||
},
|
||||
{
|
||||
"id": 29,
|
||||
"node_id": 3,
|
||||
"instance": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"current_value": 0.0,
|
||||
"target_value": 0.0,
|
||||
"last_value": 0.0,
|
||||
"unit": "n/a",
|
||||
"step_value": 1.0,
|
||||
"editable": 1,
|
||||
"type": 13,
|
||||
"state": 1,
|
||||
"last_changed": 1736003985,
|
||||
"changed_by": 1,
|
||||
"changed_by_id": 0,
|
||||
"based_on": 1,
|
||||
"data": "",
|
||||
"name": "",
|
||||
"options": {
|
||||
"automations": ["toggle"],
|
||||
"history": {
|
||||
"day": 35,
|
||||
"week": 5,
|
||||
"month": 1,
|
||||
"stepped": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 30,
|
||||
"node_id": 3,
|
||||
"instance": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"current_value": 1.0,
|
||||
"target_value": 0.0,
|
||||
"last_value": 0.0,
|
||||
"unit": "n/a",
|
||||
"step_value": 1.0,
|
||||
"editable": 1,
|
||||
"type": 1,
|
||||
"state": 1,
|
||||
"last_changed": 1736743294,
|
||||
"changed_by": 1,
|
||||
"changed_by_id": 0,
|
||||
"based_on": 1,
|
||||
"data": "",
|
||||
"name": "",
|
||||
"options": {
|
||||
"can_observe": [300],
|
||||
"automations": ["toggle"],
|
||||
"history": {
|
||||
"day": 35,
|
||||
"week": 5,
|
||||
"month": 1,
|
||||
"stepped": true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,3 +27,26 @@ async def test_sensor_snapshot(
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
async def test_add_device(
|
||||
hass: HomeAssistant,
|
||||
mock_homee: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test adding a device."""
|
||||
mock_homee.nodes = [build_mock_node("binary_sensors.json")]
|
||||
mock_homee.get_node_by_id.return_value = mock_homee.nodes[0]
|
||||
with patch("homeassistant.components.homee.PLATFORMS", [Platform.BINARY_SENSOR]):
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
# Add a new device
|
||||
added_node = build_mock_node("add_device.json")
|
||||
mock_homee.nodes.append(added_node)
|
||||
mock_homee.get_node_by_id.return_value = mock_homee.nodes[1]
|
||||
await mock_homee.add_nodes_listener.call_args_list[0][0][0](added_node, True)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
Reference in New Issue
Block a user