Skip to content

Commit a0dd0fb

Browse files
Some small bugfixes and stability improvements (#324)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
1 parent 2649b5b commit a0dd0fb

File tree

7 files changed

+47
-14
lines changed

7 files changed

+47
-14
lines changed

.pre-commit-config.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ repos:
99
- --quiet
1010
files: ^(matter_server|scripts)/.+\.py$
1111
- repo: https://github.com/codespell-project/codespell
12-
rev: v2.2.2
12+
rev: v2.2.4
1313
hooks:
1414
- id: codespell
1515
args: []
1616
exclude_types: [csv, json]
1717
exclude: ^tests/fixtures/
18+
additional_dependencies:
19+
- tomli
1820
- repo: https://github.com/PyCQA/flake8
1921
rev: 6.0.0
2022
hooks:

matter_server/client/models/device_types.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def __init_subclass__(cls, *, device_type: int, **kwargs: typing.Any) -> None:
2727

2828
def __hash__(self) -> int:
2929
"""Return unique hash for this object."""
30-
return hash(self.device_type)
30+
return self.device_type
3131

3232

3333
class OrphanClusters(DeviceType, device_type=0xF001):

matter_server/client/models/node.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def __init__(
6565
self.node = node
6666
self.endpoint_id = endpoint_id
6767
self.clusters: dict[int, Clusters.Cluster] = {}
68-
self.device_types: set[DeviceType] = set()
68+
self.device_types: set[type[DeviceType]] = set()
6969
self.update(attributes_data)
7070

7171
@property

matter_server/server/device_controller.py

+35-9
Original file line numberDiff line numberDiff line change
@@ -285,13 +285,13 @@ async def interview_node(self, node_id: int) -> None:
285285

286286
LOGGER.debug("Interviewing node: %s", node_id)
287287
try:
288-
await self._call_sdk(self.chip_controller.ResolveNode, nodeid=node_id)
288+
await self._resolve_node(node_id=node_id)
289289
read_response: Attribute.AsyncReadTransaction.ReadResponse = (
290290
await self.chip_controller.Read(
291291
nodeid=node_id, attributes="*", events="*", fabricFiltered=False
292292
)
293293
)
294-
except ChipStackError as err:
294+
except (ChipStackError, NodeNotResolving) as err:
295295
raise NodeInterviewFailed(f"Failed to interview node {node_id}") from err
296296

297297
is_new_node = node_id not in self._nodes
@@ -406,12 +406,9 @@ async def subscribe_node(self, node_id: int) -> None:
406406
node_logger.debug("Setting up subscriptions...")
407407

408408
node = cast(MatterNodeData, self._nodes[node_id])
409-
410-
try:
411-
await self._call_sdk(self.chip_controller.ResolveNode, nodeid=node_id)
412-
except ChipStackError as err:
413-
node.available = False
414-
raise NodeNotResolving(f"Failed to resolve node {node_id}") from err
409+
node.available = False
410+
await self._resolve_node(node_id=node_id)
411+
node.available = True
415412

416413
# we follow the pattern of apple and google here and
417414
# just do a wildcard subscription for all clusters and properties
@@ -421,7 +418,7 @@ async def subscribe_node(self, node_id: int) -> None:
421418
sub: Attribute.SubscriptionTransaction = await self.chip_controller.Read(
422419
nodeid=node_id,
423420
attributes="*",
424-
events=[("*", 0)],
421+
events=[("*", 1)],
425422
reportInterval=(0, 120),
426423
fabricFiltered=False,
427424
)
@@ -632,3 +629,32 @@ def _parse_attributes_from_read_result(
632629
)
633630
result[attribute_path] = attr_value
634631
return result
632+
633+
async def _resolve_node(
634+
self, node_id: int, retries: int = 3, allow_pase: bool = False
635+
) -> None:
636+
"""Resolve a Node on the network."""
637+
if self.chip_controller is None:
638+
raise RuntimeError("Device Controller not initialized.")
639+
try:
640+
if allow_pase:
641+
# last attempt allows PASE connection (last resort)
642+
LOGGER.debug(
643+
"Attempting to resolve node %s (with PASE connection)", node_id
644+
)
645+
await self._call_sdk(
646+
self.chip_controller.GetConnectedDeviceSync,
647+
nodeid=node_id,
648+
allowPASE=True,
649+
)
650+
return
651+
LOGGER.debug("Resolving node %s", node_id)
652+
await self._call_sdk(self.chip_controller.ResolveNode, nodeid=node_id)
653+
except (ChipStackError, TimeoutError) as err:
654+
if not retries:
655+
# when we're out of retries, raise NodeNotResolving
656+
raise NodeNotResolving(f"Unable to resolve Node {node_id}") from err
657+
await self._resolve_node(
658+
node_id=node_id, retries=retries - 1, allow_pase=retries - 1 == 0
659+
)
660+
await asyncio.sleep(2)

pyproject.toml

+5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ test = [
4949
[project.scripts]
5050
matter-server = "matter_server.server.__main__:main"
5151

52+
[tool.codespell]
53+
ignore-words-list = "pase,"
54+
5255
[tool.mypy]
5356
python_version = "3.10"
5457
check_untyped_defs = true
@@ -134,3 +137,5 @@ forced_separate = [
134137
"tests",
135138
]
136139
combine_as_imports = true
140+
141+

scripts/beautify_diagnostics.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def process_node(node):
7575
continue
7676

7777
for device_type in device_types:
78-
device_type_id = device_type["type"]
78+
device_type_id = device_type["deviceType"]
7979
if device_type_id in ALL_TYPES:
8080
device_type_name = ALL_TYPES[device_type_id].__name__
8181
else:

scripts/generate_devices.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
CHIP_ROOT = REPO_ROOT / "../../project-chip/connectedhomeip"
1010
DEVICE_XML = CHIP_ROOT / "src/app/zap-templates/zcl/data-model/chip/matter-devices.xml"
1111

12-
OUTPUT_PYTHON = REPO_ROOT / "matter_server/common/models/device_types.py"
12+
OUTPUT_PYTHON = REPO_ROOT / "matter_server/client/models/device_types.py"
1313

1414

1515
def gen_cls_name(name: str):

0 commit comments

Comments
 (0)