Change subscription logic for Matter devices (#95387)
This commit is contained in:
parent
a885ceefa2
commit
ed2daf1f65
31 changed files with 110 additions and 30 deletions
|
@ -52,13 +52,62 @@ class MatterAdapter:
|
|||
|
||||
async def setup_nodes(self) -> None:
|
||||
"""Set up all existing nodes and subscribe to new nodes."""
|
||||
for node in await self.matter_client.get_nodes():
|
||||
for node in self.matter_client.get_nodes():
|
||||
self._setup_node(node)
|
||||
|
||||
def node_added_callback(event: EventType, node: MatterNode) -> None:
|
||||
"""Handle node added event."""
|
||||
self._setup_node(node)
|
||||
|
||||
def endpoint_added_callback(event: EventType, data: dict[str, int]) -> None:
|
||||
"""Handle endpoint added event."""
|
||||
node = self.matter_client.get_node(data["node_id"])
|
||||
self._setup_endpoint(node.endpoints[data["endpoint_id"]])
|
||||
|
||||
def endpoint_removed_callback(event: EventType, data: dict[str, int]) -> None:
|
||||
"""Handle endpoint removed event."""
|
||||
server_info = cast(ServerInfoMessage, self.matter_client.server_info)
|
||||
try:
|
||||
node = self.matter_client.get_node(data["node_id"])
|
||||
except KeyError:
|
||||
return # race condition
|
||||
device_registry = dr.async_get(self.hass)
|
||||
endpoint = node.endpoints.get(data["endpoint_id"])
|
||||
if not endpoint:
|
||||
return # race condition
|
||||
node_device_id = get_device_id(
|
||||
server_info,
|
||||
node.endpoints[data["endpoint_id"]],
|
||||
)
|
||||
identifier = (DOMAIN, f"{ID_TYPE_DEVICE_ID}_{node_device_id}")
|
||||
if device := device_registry.async_get_device({identifier}):
|
||||
device_registry.async_remove_device(device.id)
|
||||
|
||||
def node_removed_callback(event: EventType, node_id: int) -> None:
|
||||
"""Handle node removed event."""
|
||||
try:
|
||||
node = self.matter_client.get_node(node_id)
|
||||
except KeyError:
|
||||
return # race condition
|
||||
for endpoint_id in node.endpoints:
|
||||
endpoint_removed_callback(
|
||||
EventType.ENDPOINT_REMOVED,
|
||||
{"node_id": node_id, "endpoint_id": endpoint_id},
|
||||
)
|
||||
|
||||
self.config_entry.async_on_unload(
|
||||
self.matter_client.subscribe(
|
||||
endpoint_added_callback, EventType.ENDPOINT_ADDED
|
||||
)
|
||||
)
|
||||
self.config_entry.async_on_unload(
|
||||
self.matter_client.subscribe(
|
||||
endpoint_removed_callback, EventType.ENDPOINT_REMOVED
|
||||
)
|
||||
)
|
||||
self.config_entry.async_on_unload(
|
||||
self.matter_client.subscribe(node_removed_callback, EventType.NODE_REMOVED)
|
||||
)
|
||||
self.config_entry.async_on_unload(
|
||||
self.matter_client.subscribe(node_added_callback, EventType.NODE_ADDED)
|
||||
)
|
||||
|
|
|
@ -75,9 +75,11 @@ class MatterEntity(Entity):
|
|||
await super().async_added_to_hass()
|
||||
|
||||
# Subscribe to attribute updates.
|
||||
sub_paths: list[str] = []
|
||||
for attr_cls in self._entity_info.attributes_to_watch:
|
||||
attr_path = self.get_matter_attribute_path(attr_cls)
|
||||
self._attributes_map[attr_cls] = attr_path
|
||||
sub_paths.append(attr_path)
|
||||
self._unsubscribes.append(
|
||||
self.matter_client.subscribe(
|
||||
callback=self._on_matter_event,
|
||||
|
@ -86,6 +88,9 @@ class MatterEntity(Entity):
|
|||
attr_path_filter=attr_path,
|
||||
)
|
||||
)
|
||||
await self.matter_client.subscribe_attribute(
|
||||
self._endpoint.node.node_id, sub_paths
|
||||
)
|
||||
# subscribe to node (availability changes)
|
||||
self._unsubscribes.append(
|
||||
self.matter_client.subscribe(
|
||||
|
|
|
@ -95,7 +95,7 @@ async def get_node_from_device_entry(
|
|||
node = next(
|
||||
(
|
||||
node
|
||||
for node in await matter_client.get_nodes()
|
||||
for node in matter_client.get_nodes()
|
||||
for endpoint in node.endpoints.values()
|
||||
if get_device_id(server_info, endpoint) == device_id
|
||||
),
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
"dependencies": ["websocket_api"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/matter",
|
||||
"iot_class": "local_push",
|
||||
"requirements": ["python-matter-server==3.5.1"]
|
||||
"requirements": ["python-matter-server==3.6.0"]
|
||||
}
|
||||
|
|
|
@ -2103,7 +2103,7 @@ python-kasa==0.5.1
|
|||
# python-lirc==1.2.3
|
||||
|
||||
# homeassistant.components.matter
|
||||
python-matter-server==3.5.1
|
||||
python-matter-server==3.6.0
|
||||
|
||||
# homeassistant.components.xiaomi_miio
|
||||
python-miio==0.5.12
|
||||
|
|
|
@ -1541,7 +1541,7 @@ python-juicenet==1.1.0
|
|||
python-kasa==0.5.1
|
||||
|
||||
# homeassistant.components.matter
|
||||
python-matter-server==3.5.1
|
||||
python-matter-server==3.6.0
|
||||
|
||||
# homeassistant.components.xiaomi_miio
|
||||
python-miio==0.5.12
|
||||
|
|
|
@ -669,7 +669,9 @@
|
|||
"1/1030/65529": [],
|
||||
"1/1030/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"is_bridge": false,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
],
|
||||
"events": []
|
||||
|
|
|
@ -482,7 +482,9 @@
|
|||
"1/1030/65529": [],
|
||||
"1/1030/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"is_bridge": false,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
],
|
||||
"events": []
|
||||
|
|
|
@ -313,5 +313,6 @@
|
|||
"1/4/65529": [0, 5, 2, 4, 3, 1],
|
||||
"1/4/65531": [0, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -85,5 +85,6 @@
|
|||
"1/69/65529": [],
|
||||
"1/69/65531": [0, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -467,5 +467,7 @@
|
|||
"1/1030/65529": [],
|
||||
"1/1030/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"is_bridge": false,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -407,5 +407,6 @@
|
|||
"1/1030/65529": [],
|
||||
"1/1030/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -505,5 +505,6 @@
|
|||
0, 1, 2, 3, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 33, 35, 36,
|
||||
37, 38, 41, 43, 48, 49, 51, 65528, 65529, 65530, 65531, 65532, 65533
|
||||
]
|
||||
}
|
||||
},
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -313,5 +313,6 @@
|
|||
"1/4/65529": [0, 5, 2, 4, 3, 1],
|
||||
"1/4/65531": [0, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -78,5 +78,6 @@
|
|||
"1/1028/65529": [],
|
||||
"1/1028/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -77,5 +77,6 @@
|
|||
"1/1029/65529": [],
|
||||
"1/1029/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -85,5 +85,6 @@
|
|||
"1/1024/65529": [],
|
||||
"1/1024/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -93,5 +93,6 @@
|
|||
"1/1030/65529": [],
|
||||
"1/1030/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -136,5 +136,6 @@
|
|||
"1/29/65529": [],
|
||||
"1/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -407,5 +407,6 @@
|
|||
"1/1030/65529": [],
|
||||
"1/1030/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -407,5 +407,6 @@
|
|||
"1/1030/65529": [],
|
||||
"1/1030/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -407,5 +407,6 @@
|
|||
"1/1030/65529": [],
|
||||
"1/1030/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -77,5 +77,6 @@
|
|||
"1/1027/65529": [],
|
||||
"1/1027/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -83,5 +83,6 @@
|
|||
"1/1026/65529": [],
|
||||
"1/1026/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"available": true
|
||||
"available": true,
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -264,5 +264,6 @@
|
|||
65528, 65529, 65531, 65532, 65533, 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12,
|
||||
13, 14, 15, 16, 17, 18, 19, 23, 26, 6
|
||||
]
|
||||
}
|
||||
},
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -245,5 +245,6 @@
|
|||
"1/258/65528": [],
|
||||
"1/258/65529": [0, 1, 2, 5],
|
||||
"1/258/65531": [65528, 65529, 65531, 65532, 65533, 0, 1, 5, 7, 10, 13, 23]
|
||||
}
|
||||
},
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -349,5 +349,6 @@
|
|||
0, 1, 3, 5, 7, 8, 10, 11, 13, 14, 16, 17, 23, 65528, 65529, 65531, 65532,
|
||||
65533
|
||||
]
|
||||
}
|
||||
},
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -250,5 +250,6 @@
|
|||
"1/258/65531": [
|
||||
65528, 65529, 65531, 65532, 65533, 0, 7, 9, 10, 12, 13, 15, 23, 6
|
||||
]
|
||||
}
|
||||
},
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -245,5 +245,6 @@
|
|||
"1/258/65528": [],
|
||||
"1/258/65529": [0, 1, 2, 8],
|
||||
"1/258/65531": [65528, 65529, 65531, 65532, 65533, 0, 7, 10, 13, 23, 6]
|
||||
}
|
||||
},
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ async def test_node_added_subscription(
|
|||
integration: MagicMock,
|
||||
) -> None:
|
||||
"""Test subscription to new devices work."""
|
||||
assert matter_client.subscribe.call_count == 1
|
||||
assert matter_client.subscribe.call_count == 4
|
||||
assert matter_client.subscribe.call_args[0][1] == EventType.NODE_ADDED
|
||||
|
||||
node_added_callback = matter_client.subscribe.call_args[0][0]
|
||||
|
|
|
@ -168,7 +168,7 @@ async def test_listen_failure_config_entry_not_loaded(
|
|||
matter_client.connect.side_effect = MatterError("Boom")
|
||||
raise error
|
||||
|
||||
async def get_nodes() -> list[MagicMock]:
|
||||
def get_nodes() -> list[MagicMock]:
|
||||
"""Mock the client get_nodes method."""
|
||||
listen_block.set()
|
||||
return []
|
||||
|
|
Loading…
Add table
Reference in a new issue