Skip to content

Commit 87414ee

Browse files
committed
Decouple device type from Matter device
1 parent cfb7ad6 commit 87414ee

File tree

11 files changed

+138
-115
lines changed

11 files changed

+138
-115
lines changed

custom_components/matter_experimental/adapter.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,9 @@ async def setup_node(self, node: MatterNode) -> None:
150150

151151
for device in node.devices:
152152
created = False
153-
device_type = type(device)
154153

155154
for platform, devices in DEVICE_PLATFORM.items():
156-
device_mappings = devices.get(device_type)
155+
device_mappings = devices.get(device.device_type)
157156

158157
if device_mappings is None:
159158
continue
@@ -167,7 +166,7 @@ async def setup_node(self, node: MatterNode) -> None:
167166
"Creating %s entity for %s (%s)",
168167
platform,
169168
type(device),
170-
hex(device.device_type),
169+
hex(device.device_type.device_type),
171170
)
172171
entities.append(device_mapping.entity_cls(device, device_mapping))
173172

@@ -178,7 +177,7 @@ async def setup_node(self, node: MatterNode) -> None:
178177
self.logger.warning(
179178
"Found unsupported device %s (%s)",
180179
type(device).__name__,
181-
hex(device.device_type),
180+
hex(device.device_type.device_type),
182181
)
183182

184183
async def handle_server_disconnected(self, should_reload: bool) -> None:

custom_components/matter_experimental/binary_sensor.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
from homeassistant.core import HomeAssistant, callback
1414
from homeassistant.helpers.entity_platform import AddEntitiesCallback
1515

16-
from matter_server.client.model import devices as matter_devices
16+
from matter_server.client.model.device import MatterDevice
17+
from matter_server.vendor import device_types
1718
from matter_server.vendor.chip.clusters import Objects as clusters
1819

1920
from .const import DOMAIN
@@ -37,9 +38,7 @@ async def async_setup_entry(
3738
class MatterBinarySensor(MatterEntity, BinarySensorEntity):
3839
"""Representation of a Matter binary sensor."""
3940

40-
def __init__(
41-
self, device: matter_devices.MatterDevice, mapping: DeviceMapping
42-
) -> None:
41+
def __init__(self, device: MatterDevice, mapping: DeviceMapping) -> None:
4342
"""Initialize the sensor."""
4443
super().__init__(device, mapping)
4544
self._attr_name = device.node.name or f"Matter Sensor {device.node.node_id}"
@@ -64,17 +63,17 @@ def _update_from_device(self) -> None:
6463

6564

6665
DEVICE_ENTITY: dict[
67-
matter_devices.MatterDevice, DeviceMapping | list[DeviceMapping]
66+
type[device_types.DeviceType], DeviceMapping | list[DeviceMapping]
6867
] = {
69-
matter_devices.ContactSensor: DeviceMapping(
68+
device_types.ContactSensor: DeviceMapping(
7069
entity_cls=MatterBinarySensor,
7170
subscribe_attributes=(clusters.BooleanState.Attributes.StateValue,),
7271
entity_description=BinarySensorEntityDescription(
7372
key=None,
7473
device_class=BinarySensorDeviceClass.DOOR,
7574
),
7675
),
77-
matter_devices.OccupancySensor: DeviceMapping(
76+
device_types.OccupancySensor: DeviceMapping(
7877
entity_cls=MatterOccupancySensor,
7978
subscribe_attributes=(clusters.OccupancySensing.Attributes.Occupancy,),
8079
),

custom_components/matter_experimental/device_platform.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
from .switch import DEVICE_ENTITY as SWITCH_DEVICE_ENTITY
1212

1313
if TYPE_CHECKING:
14-
from matter_server.client.model import device as matter_devices
14+
from matter_server.vendor.device_types import DeviceType
1515

1616
from .device_platform_helper import DeviceMapping
1717

1818

1919
DEVICE_PLATFORM: dict[
20-
Platform, dict[matter_devices.MatterDevice, DeviceMapping | list[DeviceMapping]]
20+
Platform, dict[type[DeviceType], DeviceMapping | list[DeviceMapping]]
2121
] = {
2222
Platform.BINARY_SENSOR: BINARY_SENSOR_DEVICE_ENTITY,
2323
Platform.LIGHT: LIGHT_DEVICE_ENTITY,

custom_components/matter_experimental/entity.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,13 @@
1414

1515
class MatterEntity(entity.Entity):
1616

17+
_attr_should_poll = False
1718
_unsubscribe: Callable[..., Coroutine[Any, Any, None]] | None = None
1819

1920
def __init__(self, device: MatterDevice, mapping: DeviceMapping) -> None:
2021
self._device = device
2122
self._device_mapping = mapping
22-
self._attr_unique_id = (
23-
f"{device.node.unique_id}-{device.endpoint_id}-{device.device_type}"
24-
)
23+
self._attr_unique_id = f"{device.node.unique_id}-{device.endpoint_id}-{device.device_type.device_type}"
2524

2625
@property
2726
def device_info(self) -> entity.DeviceInfo | None:
@@ -38,7 +37,7 @@ async def async_added_to_hass(self) -> None:
3837

3938
# Subscribe to updates.
4039
self._unsubscribe = await self._device.subscribe_updates(
41-
self._device_mapping.subscribe_attributes, self._update_from_device
40+
self._device_mapping.subscribe_attributes, self._subscription_update
4241
)
4342

4443
# Fetch latest info from the device.

custom_components/matter_experimental/light.py

+7-8
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
from homeassistant.core import HomeAssistant, callback
1010
from homeassistant.helpers.entity_platform import AddEntitiesCallback
1111

12-
from matter_server.client.model import devices as matter_devices
12+
from matter_server.client.model.device import MatterDevice
13+
from matter_server.vendor import device_types
1314
from matter_server.vendor.chip.clusters import Objects as clusters
1415

1516
from .const import DOMAIN
@@ -34,9 +35,7 @@ async def async_setup_entry(
3435
class MatterLight(MatterEntity, LightEntity):
3536
"""Representation of a Matter light."""
3637

37-
def __init__(
38-
self, device: matter_devices.MatterDevice, mapping: DeviceMapping
39-
) -> None:
38+
def __init__(self, device: MatterDevice, mapping: DeviceMapping) -> None:
4039
"""Initialize the light."""
4140
super().__init__(device, mapping)
4241
self._attr_name = device.node.name or f"Matter Light {device.node.node_id}"
@@ -99,20 +98,20 @@ def _update_from_device(self) -> None:
9998

10099

101100
DEVICE_ENTITY: dict[
102-
matter_devices.MatterDevice, DeviceMapping | list[DeviceMapping]
101+
type[device_types.DeviceType], DeviceMapping | list[DeviceMapping]
103102
] = {
104-
matter_devices.OnOffLight: DeviceMapping(
103+
device_types.OnOffLight: DeviceMapping(
105104
entity_cls=MatterLight,
106105
subscribe_attributes=(clusters.OnOff.Attributes.OnOff,),
107106
),
108-
matter_devices.DimmableLight: DeviceMapping(
107+
device_types.DimmableLight: DeviceMapping(
109108
entity_cls=MatterLight,
110109
subscribe_attributes=(
111110
clusters.OnOff.Attributes.OnOff,
112111
clusters.LevelControl.Attributes.CurrentLevel,
113112
),
114113
),
115-
matter_devices.DimmablePlugInUnit: DeviceMapping(
114+
device_types.DimmablePlugInUnit: DeviceMapping(
116115
entity_cls=MatterLight,
117116
subscribe_attributes=(
118117
clusters.OnOff.Attributes.OnOff,

custom_components/matter_experimental/sensor.py

+9-10
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
from homeassistant.core import HomeAssistant, callback
2121
from homeassistant.helpers.entity_platform import AddEntitiesCallback
2222

23-
from matter_server.client.model import devices as matter_devices
23+
from matter_server.client.model.device import MatterDevice
24+
from matter_server.vendor import device_types
2425
from matter_server.vendor.chip.clusters import Objects as clusters
2526
from matter_server.vendor.chip.clusters.Types import NullValue
2627

@@ -47,9 +48,7 @@ class MatterSensor(MatterEntity, SensorEntity):
4748

4849
_attr_state_class = SensorStateClass.MEASUREMENT
4950

50-
def __init__(
51-
self, device: matter_devices.MatterDevice, mapping: DeviceMapping
52-
) -> None:
51+
def __init__(self, device: MatterDevice, mapping: DeviceMapping) -> None:
5352
"""Initialize the sensor."""
5453
super().__init__(device, mapping)
5554
self._attr_name = device.node.name or f"Matter Sensor {device.node.node_id}"
@@ -158,29 +157,29 @@ def _update_from_device(self) -> None:
158157

159158

160159
DEVICE_ENTITY: dict[
161-
matter_devices.MatterDevice, DeviceMapping | list[DeviceMapping]
160+
type[device_types.DeviceType], DeviceMapping | list[DeviceMapping]
162161
] = {
163-
matter_devices.TemperatureSensor: DeviceMapping(
162+
device_types.TemperatureSensor: DeviceMapping(
164163
entity_cls=MatterTemperatureSensor,
165164
subscribe_attributes=(
166165
clusters.TemperatureMeasurement.Attributes.MeasuredValue,
167166
),
168167
),
169-
matter_devices.PressureSensor: DeviceMapping(
168+
device_types.PressureSensor: DeviceMapping(
170169
entity_cls=MatterPressureSensor,
171170
subscribe_attributes=(clusters.PressureMeasurement.Attributes.MeasuredValue,),
172171
),
173-
matter_devices.FlowSensor: DeviceMapping(
172+
device_types.FlowSensor: DeviceMapping(
174173
entity_cls=MatterFlowSensor,
175174
subscribe_attributes=(clusters.FlowMeasurement.Attributes.MeasuredValue,),
176175
),
177-
matter_devices.HumiditySensor: DeviceMapping(
176+
device_types.HumiditySensor: DeviceMapping(
178177
entity_cls=MatterHumiditySensor,
179178
subscribe_attributes=(
180179
clusters.RelativeHumidityMeasurement.Attributes.MeasuredValue,
181180
),
182181
),
183-
matter_devices.LightSensor: DeviceMapping(
182+
device_types.LightSensor: DeviceMapping(
184183
entity_cls=MatterLightSensor,
185184
subscribe_attributes=(
186185
clusters.IlluminanceMeasurement.Attributes.MeasuredValue,

custom_components/matter_experimental/switch.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
from homeassistant.core import HomeAssistant, callback
1414
from homeassistant.helpers.entity_platform import AddEntitiesCallback
1515

16-
from matter_server.client.model import devices as matter_devices
16+
from matter_server.client.model.device import MatterDevice
17+
from matter_server.vendor import device_types
1718
from matter_server.vendor.chip.clusters import Objects as clusters
1819

1920
from .const import DOMAIN
@@ -37,9 +38,7 @@ async def async_setup_entry(
3738
class MatterSwitch(MatterEntity, SwitchEntity):
3839
"""Representation of a Matter switch."""
3940

40-
def __init__(
41-
self, device: matter_devices.MatterDevice, mapping: DeviceMapping
42-
) -> None:
41+
def __init__(self, device: MatterDevice, mapping: DeviceMapping) -> None:
4342
"""Initialize the switch."""
4443
super().__init__(device, mapping)
4544
self._attr_name = device.node.name or f"Matter Switch {device.node.node_id}"
@@ -63,9 +62,9 @@ def _update_from_device(self) -> None:
6362

6463

6564
DEVICE_ENTITY: dict[
66-
matter_devices.MatterDevice, DeviceMapping | list[DeviceMapping]
65+
type[device_types.DeviceType], DeviceMapping | list[DeviceMapping]
6766
] = {
68-
matter_devices.OnOffPlugInUnit: DeviceMapping(
67+
device_types.OnOffPlugInUnit: DeviceMapping(
6968
entity_cls=MatterSwitch,
7069
subscribe_attributes=(clusters.OnOff.Attributes.OnOff,),
7170
entity_description=SwitchEntityDescription(

matter_server/client/model/device.py

+12-16
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,32 @@
11
from __future__ import annotations
22

3-
from typing import TYPE_CHECKING, Any, Callable, Coroutine, TypeVar
3+
from typing import TYPE_CHECKING, Callable, Coroutine, Generic, TypeVar
44

5+
from matter_server.vendor import device_types
56
from matter_server.vendor.chip.clusters import Objects as all_clusters
67

78
if TYPE_CHECKING:
89
from .node import MatterNode
910

10-
DEVICE_TYPES = {}
11-
1211
SubscriberType = Callable[[], None]
1312

1413

14+
_DEVICE_TYPE_T = TypeVar("_DEVICE_TYPE_T", bound=device_types.DeviceType)
1515
_CLUSTER_T = TypeVar("_CLUSTER_T", bound=all_clusters.Cluster)
1616

1717

18-
class MatterDevice:
18+
class MatterDevice(Generic[_DEVICE_TYPE_T]):
1919
"""Base class for Matter devices."""
2020

21-
device_type: int
22-
clusters: set[type[all_clusters.Cluster]] = set()
23-
24-
def __init_subclass__(cls, *, device_type: int, **kwargs: Any) -> None:
25-
"""Initialize a subclass, register if possible."""
26-
super().__init_subclass__(**kwargs)
27-
cls.device_type = device_type
28-
DEVICE_TYPES[device_type] = cls
29-
3021
def __init__(
31-
self, node: MatterNode, endpoint_id: int, device_revision: int
22+
self,
23+
node: MatterNode,
24+
device_type: _DEVICE_TYPE_T,
25+
endpoint_id: int,
26+
device_revision: int,
3227
) -> None:
3328
self.node = node
29+
self.device_type = device_type
3430
self.device_revision = device_revision
3531
self.endpoint_id = endpoint_id
3632
self._on_update_listener: SubscriberType | None = None
@@ -39,9 +35,9 @@ def __init__(
3935
def data(self) -> dict:
4036
return self.node.raw_data["attributes"][str(self.endpoint_id)]
4137

42-
def has_cluster(self, cluster: type[clusters.Cluster]) -> bool:
38+
def has_cluster(self, cluster: type[all_clusters.Cluster]) -> bool:
4339
"""Check if device has a specific cluster."""
44-
return cluster in self.clusters and cluster.__name__ in self.data
40+
return cluster in self.device_type.clusters and cluster.__name__ in self.data
4541

4642
def get_cluster(self, cluster: type[_CLUSTER_T]) -> _CLUSTER_T | None:
4743
"""Get the cluster object."""

matter_server/client/model/node.py

+11-8
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33

44
from typing import TYPE_CHECKING
55

6-
from .device import DEVICE_TYPES, MatterDevice
7-
from .devices import RootNode
8-
96
from matter_server.vendor.chip.clusters import Objects as all_clusters
7+
from matter_server.vendor import device_types
8+
9+
from .device import MatterDevice
10+
1011

1112
if TYPE_CHECKING:
1213
from ..matter import Matter
@@ -15,7 +16,7 @@
1516
class MatterNode:
1617
"""Matter node."""
1718

18-
root_device: RootNode
19+
root_device: MatterDevice[device_types.RootNode]
1920

2021
def __init__(self, matter: Matter, node_info: dict) -> None:
2122
self.matter = matter
@@ -26,16 +27,18 @@ def __init__(self, matter: Matter, node_info: dict) -> None:
2627
for endpoint_id, endpoint_info in node_info["attributes"].items():
2728
descriptor: all_clusters.Descriptor = endpoint_info["Descriptor"]
2829
for device_info in descriptor.deviceList:
29-
device_cls = DEVICE_TYPES.get(device_info.type)
30+
device_type = device_types.ALL_TYPES.get(device_info.type)
3031

31-
if device_cls is None:
32+
if device_type is None:
3233
matter.adapter.logger.warning(
3334
"Found unknown device type %s", device_info.type
3435
)
3536
continue
3637

37-
device = device_cls(self, int(endpoint_id), device_info.revision)
38-
if isinstance(device, RootNode):
38+
device = MatterDevice(
39+
self, device_type, int(endpoint_id), device_info.revision
40+
)
41+
if device_type is device_types.RootNode:
3942
self.root_device = device
4043
else:
4144
devices.append(device)

0 commit comments

Comments
 (0)