Skip to content

Commit a63cfab

Browse files
authored
Add warning if node setup takes too long (#623)
1 parent 9950f8b commit a63cfab

File tree

1 file changed

+48
-5
lines changed

1 file changed

+48
-5
lines changed

matter_server/server/device_controller.py

+48-5
Original file line numberDiff line numberDiff line change
@@ -1068,8 +1068,50 @@ async def _setup_node(self, node_id: int) -> None:
10681068
return
10691069
self._nodes_in_setup.add(node_id)
10701070
node_logger = LOGGER.getChild(f"node_{node_id}")
1071-
try:
1072-
async with self._node_setup_throttle:
1071+
node_data = self._nodes[node_id]
1072+
log_timers: dict[int, asyncio.TimerHandle] = {}
1073+
1074+
def log_node_long_setup(time_start: float) -> None:
1075+
"""Temporary measure to track a locked-up SDK issue in some (special) circumstances."""
1076+
time_mins = int((time.time() - time_start) / 60)
1077+
if TYPE_CHECKING:
1078+
assert self.server.loop
1079+
assert self.chip_controller
1080+
# get productlabel or modelname from raw attributes
1081+
node_model = node_data.attributes.get(
1082+
"0/40/14", node_data.attributes.get("0/40/3", "")
1083+
)
1084+
node_name = f"Node {node_id} ({node_model})"
1085+
# get current IP the sdk is using to communicate with the device
1086+
if sdk_ip_info := self.chip_controller.GetAddressAndPort(node_id):
1087+
ip_address = sdk_ip_info[0]
1088+
else:
1089+
ip_address = "unknown"
1090+
1091+
node_logger.error(
1092+
f"\n\nATTENTION: {node_name} did not complete setup in {time_mins} minutes.\n" # noqa: G004
1093+
"This is an indication of a (connectivity) issue with this device. \n"
1094+
f"IP-address in use for this device: {ip_address}\n"
1095+
"Try powercycling this device and/or relocate it closer to a Border Router or \n"
1096+
"WiFi Access Point. If this issue persists, please create an issue report on \n"
1097+
"the Matter channel of the Home Assistant Discord server or on Github:\n"
1098+
"https://github.com/home-assistant/core/issues/new?assignees=&labels="
1099+
"integration%3A%20matter&projects=&template=bug_report.yml\n",
1100+
)
1101+
# reschedule itself
1102+
log_timers[node_id] = self.server.loop.call_later(
1103+
15 * 60, log_node_long_setup, time_start
1104+
)
1105+
1106+
async with self._node_setup_throttle:
1107+
time_start = time.time()
1108+
# we want to track nodes that take too long so we log it when we detect that
1109+
if TYPE_CHECKING:
1110+
assert self.server.loop
1111+
log_timers[node_id] = self.server.loop.call_later(
1112+
15 * 60, log_node_long_setup, time_start
1113+
)
1114+
try:
10731115
node_logger.info("Setting-up node...")
10741116

10751117
# try to resolve the node using the sdk first before do anything else
@@ -1087,7 +1129,7 @@ async def _setup_node(self, node_id: int) -> None:
10871129
return
10881130

10891131
# (re)interview node (only) if needed
1090-
node_data = self._nodes[node_id]
1132+
10911133
if (
10921134
# re-interview if we dont have any node attributes (empty node)
10931135
not node_data.attributes
@@ -1121,8 +1163,9 @@ async def _setup_node(self, node_id: int) -> None:
11211163
)
11221164
# NOTE: the node will be picked up by mdns discovery automatically
11231165
# when it becomes available again.
1124-
finally:
1125-
self._nodes_in_setup.discard(node_id)
1166+
finally:
1167+
log_timers[node_id].cancel()
1168+
self._nodes_in_setup.discard(node_id)
11261169

11271170
async def _resolve_node(
11281171
self, node_id: int, retries: int = 2, attempt: int = 1

0 commit comments

Comments
 (0)