1
0
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:
Markus Adrario
2025-09-12 00:19:37 +02:00
committed by GitHub
parent 82b9fead39
commit 59cd24f54b
20 changed files with 1994 additions and 137 deletions

View File

@@ -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
)

View File

@@ -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."""

View File

@@ -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):

View File

@@ -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):

View File

@@ -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:

View File

@@ -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):

View File

@@ -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):

View File

@@ -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:

View File

@@ -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):

View File

@@ -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):

View File

@@ -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):

View File

@@ -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

View File

@@ -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):

View File

@@ -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):

View File

@@ -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):

View File

@@ -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):

View File

@@ -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):

View 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

View File

@@ -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)