1 """Matter entity base class."""
3 from __future__
import annotations
5 from collections.abc
import Callable
6 from dataclasses
import dataclass
8 from typing
import TYPE_CHECKING, Any, cast
10 from chip.clusters
import Objects
as clusters
11 from chip.clusters.Objects
import ClusterAttributeDescriptor, NullValue
12 from matter_server.common.helpers.util
import create_attribute_path
13 from matter_server.common.models
import EventType, ServerInfoMessage
14 from propcache
import cached_property
22 from .const
import DOMAIN, FEATUREMAP_ATTRIBUTE_ID, ID_TYPE_DEVICE_ID
23 from .helpers
import get_device_id
26 from matter_server.client
import MatterClient
27 from matter_server.client.models.node
import MatterEndpoint
29 from .discovery
import MatterEntityInfo
31 LOGGER = logging.getLogger(__name__)
34 @dataclass(frozen=True)
36 """Describe the Matter entity."""
39 measurement_to_ha: Callable[[Any], Any] |
None =
None
40 ha_to_native_value: Callable[[Any], Any] |
None =
None
44 """Entity class for Matter devices."""
46 _attr_has_entity_name =
True
47 _attr_should_poll =
False
48 _name_postfix: str |
None =
None
49 _platform_translation_key: str |
None =
None
53 matter_client: MatterClient,
54 endpoint: MatterEndpoint,
55 entity_info: MatterEntityInfo,
57 """Initialize the entity."""
62 self._unsubscribes: list[Callable] = []
64 self._attributes_map: dict[type, str] = {}
66 server_info = cast(ServerInfoMessage, self.
matter_clientmatter_client.server_info)
71 f
"{endpoint.endpoint_id}-"
72 f
"{entity_info.entity_description.key}-"
73 f
"{entity_info.primary_attribute.cluster_id}-"
74 f
"{entity_info.primary_attribute.attribute_id}"
77 identifiers={(DOMAIN, f
"{ID_TYPE_DEVICE_ID}_{node_device_id}")}
81 if not self.
_endpoint_endpoint.node.is_bridge_device
and any(
83 for ep
in self.
_endpoint_endpoint.node.endpoints.values()
85 and ep.has_attribute(
None, entity_info.primary_attribute)
88 if self._platform_translation_key
and not self.
translation_keytranslation_key:
95 clusters.FixedLabel.Attributes.LabelList,
96 clusters.UserLabel.Attributes.LabelList,
101 if label.label
not in [
"Label",
"Button"]:
104 label_value: str = label.value
106 if label_value.isnumeric():
116 """Handle being added to Home Assistant."""
120 sub_paths: list[str] = []
121 for attr_cls
in self.
_entity_info_entity_info.attributes_to_watch:
123 if attr_path
in sub_paths:
126 self._attributes_map[attr_cls] = attr_path
127 sub_paths.append(attr_path)
128 self._unsubscribes.append(
131 event_filter=EventType.ATTRIBUTE_UPDATED,
132 node_filter=self.
_endpoint_endpoint.node.node_id,
133 attr_path_filter=attr_path,
137 self._unsubscribes.append(
140 event_filter=EventType.NODE_UPDATED,
141 node_filter=self.
_endpoint_endpoint.node.node_id,
145 self._unsubscribes.append(
148 event_filter=EventType.ATTRIBUTE_UPDATED,
149 node_filter=self.
_endpoint_endpoint.node.node_id,
150 attr_path_filter=create_attribute_path(
151 endpoint=self.
_endpoint_endpoint.endpoint_id,
152 cluster_id=self.
_entity_info_entity_info.primary_attribute.cluster_id,
153 attribute_id=FEATUREMAP_ATTRIBUTE_ID,
159 def name(self) -> str | UndefinedType | None:
160 """Return the name of the entity."""
161 if hasattr(self,
"_attr_name"):
166 name = f
"{name} ({self._name_postfix})"
171 """Call on update from the device."""
178 self, event: EventType, data: tuple[int, str, int] |
None
180 """Handle FeatureMap attribute updates."""
186 self.
_entity_info_entity_info.discovery_schema.featuremap_contains
is not None
188 new_value & self.
_entity_info_entity_info.discovery_schema.featuremap_contains
192 ent_reg = er.async_get(self.
hasshass)
193 ent_reg.async_remove(self.
entity_identity_id)
201 """Update data from Matter device."""
205 self, attribute: type[ClusterAttributeDescriptor], null_as_none: bool =
True
207 """Get current value for given attribute."""
208 value = self.
_endpoint_endpoint.get_attribute_value(
None, attribute)
209 if null_as_none
and value == NullValue:
215 self, attribute: type[ClusterAttributeDescriptor]
217 """Return AttributePath by providing the endpoint and Attribute class."""
218 return create_attribute_path(
219 self.
_endpoint_endpoint.endpoint_id, attribute.cluster_id, attribute.attribute_id
None async_added_to_hass(self)
None __init__(self, MatterClient matter_client, MatterEndpoint endpoint, MatterEntityInfo entity_info)
str|UndefinedType|None name(self)
str get_matter_attribute_path(self, type[ClusterAttributeDescriptor] attribute)
None _on_matter_event(self, EventType event, Any data=None)
None _on_featuremap_update(self, EventType event, tuple[int, str, int]|None data)
Any get_matter_attribute_value(self, type[ClusterAttributeDescriptor] attribute, bool null_as_none=True)
None _update_from_device(self)
None async_write_ha_state(self)
str|None translation_key(self)
str get_device_id(ServerInfoMessage server_info, MatterEndpoint endpoint)