core/homeassistant/components/matter/models.py

114 lines
3.9 KiB
Python

"""Models used for the Matter integration."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import asdict, dataclass
from typing import TYPE_CHECKING, Any
from chip.clusters import Objects as clusters
from chip.clusters.Objects import ClusterAttributeDescriptor
from matter_server.client.models.device_types import DeviceType
from matter_server.client.models.node import MatterEndpoint
from homeassistant.const import Platform
from homeassistant.helpers.entity import EntityDescription
if TYPE_CHECKING:
from _typeshed import DataclassInstance
class DataclassMustHaveAtLeastOne:
"""A dataclass that must have at least one input parameter that is not None."""
def __post_init__(self: DataclassInstance) -> None:
"""Post dataclass initialization."""
if all(val is None for val in asdict(self).values()):
raise ValueError("At least one input parameter must not be None")
SensorValueTypes = type[
clusters.uint | int | clusters.Nullable | clusters.float32 | float
]
@dataclass
class MatterEntityInfo:
"""Info discovered from (primary) Matter Attribute to create entity."""
# MatterEndpoint to which the value(s) belongs
endpoint: MatterEndpoint
# the home assistant platform for which an entity should be created
platform: Platform
# All attributes that need to be watched by entity (incl. primary)
attributes_to_watch: list[type[ClusterAttributeDescriptor]]
# the entity description to use
entity_description: EntityDescription
# entity class to use to instantiate the entity
entity_class: type
# [optional] function to call to convert the value from the primary attribute
measurement_to_ha: Callable[[SensorValueTypes], SensorValueTypes] | None = None
@property
def primary_attribute(self) -> type[ClusterAttributeDescriptor]:
"""Return Primary Attribute belonging to the entity."""
return self.attributes_to_watch[0]
@dataclass
class MatterDiscoverySchema:
"""Matter discovery schema.
The Matter endpoint and it's (primary) Attribute for an entity must match these conditions.
"""
# specify the hass platform for which this scheme applies (e.g. light, sensor)
platform: Platform
# platform-specific entity description
entity_description: EntityDescription
# entity class to use to instantiate the entity
entity_class: type
# DISCOVERY OPTIONS
# [required] attributes that ALL need to be present
# on the node for this scheme to pass (minimal one == primary)
required_attributes: tuple[type[ClusterAttributeDescriptor], ...]
# [optional] the value's endpoint must contain this devicetype(s)
device_type: tuple[type[DeviceType] | DeviceType, ...] | None = None
# [optional] the value's endpoint must NOT contain this devicetype(s)
not_device_type: tuple[type[DeviceType] | DeviceType, ...] | None = None
# [optional] the endpoint's vendor_id must match ANY of these values
vendor_id: tuple[int, ...] | None = None
# [optional] the endpoint's product_name must match ANY of these values
product_name: tuple[str, ...] | None = None
# [optional] the attribute's endpoint_id must match ANY of these values
endpoint_id: tuple[int, ...] | None = None
# [optional] additional attributes that MAY NOT be present
# on the node for this scheme to pass
absent_attributes: tuple[type[ClusterAttributeDescriptor], ...] | None = None
# [optional] additional attributes that may be present
# these attributes are copied over to attributes_to_watch and
# are not discovered by other entities
optional_attributes: tuple[type[ClusterAttributeDescriptor], ...] | None = None
# [optional] bool to specify if this primary value may be discovered
# by multiple platforms
allow_multi: bool = False
# [optional] function to call to convert the value from the primary attribute
measurement_to_ha: Callable[[Any], Any] | None = None