diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 9fa0f5089b8485..efadd7fd4f87c7 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -38,7 +38,6 @@ import logging import secrets import threading -import time import typing from ctypes import (CDLL, CFUNCTYPE, POINTER, Structure, byref, c_bool, c_char, c_char_p, c_int, c_int32, c_size_t, c_uint8, c_uint16, c_uint32, c_uint64, c_void_p, create_string_buffer, pointer, py_object, resize, string_at) @@ -729,8 +728,8 @@ def GetAddressAndPort(self, nodeid): return (address.value.decode(), port.value) if error == 0 else None - def DiscoverCommissionableNodes(self, filterType: discovery.FilterType = discovery.FilterType.NONE, filter: typing.Any = None, - stopOnFirst: bool = False, timeoutSecond: int = 5) -> typing.Union[None, CommissionableNode, typing.List[CommissionableNode]]: + async def DiscoverCommissionableNodes(self, filterType: discovery.FilterType = discovery.FilterType.NONE, filter: typing.Any = None, + stopOnFirst: bool = False, timeoutSecond: int = 5) -> typing.Union[None, CommissionableNode, typing.List[CommissionableNode]]: ''' Discover commissionable nodes via DNS-SD with specified filters. Supported filters are: @@ -752,27 +751,36 @@ def DiscoverCommissionableNodes(self, filterType: discovery.FilterType = discove if isinstance(filter, int): filter = str(filter) - self._ChipStack.Call( - lambda: self._dmLib.pychip_DeviceController_DiscoverCommissionableNodes( - self.devCtrl, int(filterType), str(filter).encode("utf-8"))).raise_on_error() - - if timeoutSecond != 0: - if stopOnFirst: - target = time.time() + timeoutSecond - while time.time() < target: - if self._ChipStack.Call( - lambda: self._dmLib.pychip_DeviceController_HasDiscoveredCommissionableNode(self.devCtrl)): - break - time.sleep(0.1) - else: - time.sleep(timeoutSecond) - - self._ChipStack.Call( - lambda: self._dmLib.pychip_DeviceController_StopCommissionableDiscovery(self.devCtrl)).raise_on_error() + # Discovery is also used during commissioning. Make sure this manual discovery + # and commissioning attempts do not interfere with each other. + async with self._commissioning_lock: + res = await self._ChipStack.CallAsync( + lambda: self._dmLib.pychip_DeviceController_DiscoverCommissionableNodes( + self.devCtrl, int(filterType), str(filter).encode("utf-8"))) + res.raise_on_error() - return self.GetDiscoveredDevices() + async def _wait_discovery(): + while not await self._ChipStack.CallAsync( + lambda: self._dmLib.pychip_DeviceController_HasDiscoveredCommissionableNode(self.devCtrl)): + await asyncio.sleep(0.1) + return - def GetDiscoveredDevices(self): + try: + if stopOnFirst: + await asyncio.wait_for(_wait_discovery(), timeoutSecond) + else: + await asyncio.sleep(timeoutSecond) + except TimeoutError: + # Expected timeout, do nothing + pass + finally: + res = await self._ChipStack.CallAsync( + lambda: self._dmLib.pychip_DeviceController_StopCommissionableDiscovery(self.devCtrl)) + res.raise_on_error() + + return await self.GetDiscoveredDevices() + + async def GetDiscoveredDevices(self): def GetDevices(devCtrl): devices = [] @@ -786,7 +794,7 @@ def HandleDevice(deviceJson, deviceJsonLen): self._dmLib.pychip_DeviceController_IterateDiscoveredCommissionableNodes(devCtrl.devCtrl, HandleDevice) return devices - return self._ChipStack.Call(lambda: GetDevices(self)) + return await self._ChipStack.CallAsync(lambda: GetDevices(self)) def GetIPForDiscoveredDevice(self, idx, addrStr, length): self.CheckIsActive() diff --git a/src/controller/python/chip/commissioning/pase.py b/src/controller/python/chip/commissioning/pase.py index c0cfca5ee8b93f..ee0b96c76baf73 100644 --- a/src/controller/python/chip/commissioning/pase.py +++ b/src/controller/python/chip/commissioning/pase.py @@ -48,8 +48,8 @@ async def establish_session(devCtrl: ChipDeviceCtrl.ChipDeviceControllerBase, pa if isinstance(parameter, commissioning.PaseOverBLEParameters): await devCtrl.EstablishPASESessionBLE(parameter.setup_pin, parameter.discriminator, parameter.temporary_nodeid) elif isinstance(parameter, commissioning.PaseOverIPParameters): - device = devCtrl.DiscoverCommissionableNodes(filterType=discovery.FilterType.LONG_DISCRIMINATOR, - filter=parameter.long_discriminator, stopOnFirst=True) + device = await devCtrl.DiscoverCommissionableNodes(filterType=discovery.FilterType.LONG_DISCRIMINATOR, + filter=parameter.long_discriminator, stopOnFirst=True) if not device: raise ValueError("No commissionable device found") selected_address = None diff --git a/src/controller/python/chip/yaml/runner.py b/src/controller/python/chip/yaml/runner.py index f0b681fb2b4cbe..ce1eaf84fcfbb9 100644 --- a/src/controller/python/chip/yaml/runner.py +++ b/src/controller/python/chip/yaml/runner.py @@ -712,7 +712,7 @@ def __init__(self, test_step): self.filterType, self.filter = DiscoveryCommandAction._filter_for_step(test_step) async def run_action(self, dev_ctrl: ChipDeviceController) -> _ActionResult: - devices = dev_ctrl.DiscoverCommissionableNodes( + devices = await dev_ctrl.DiscoverCommissionableNodes( filterType=self.filterType, filter=self.filter, stopOnFirst=True, timeoutSecond=5) # Devices will be a list: [CommissionableNode(), ...] diff --git a/src/controller/python/test/test_scripts/base.py b/src/controller/python/test/test_scripts/base.py index 80aaf145d964f9..ca1e37a279b417 100644 --- a/src/controller/python/test/test_scripts/base.py +++ b/src/controller/python/test/test_scripts/base.py @@ -210,10 +210,10 @@ def _WaitForOneDiscoveredDevice(self, timeoutSeconds: int = 2): return None return ctypes.string_at(addrStrStorage).decode("utf-8") - def TestDiscovery(self, discriminator: int): + async def TestDiscovery(self, discriminator: int): self.logger.info( f"Discovering commissionable nodes with discriminator {discriminator}") - res = self.devCtrl.DiscoverCommissionableNodes( + res = await self.devCtrl.DiscoverCommissionableNodes( chip.discovery.FilterType.LONG_DISCRIMINATOR, discriminator, stopOnFirst=True, timeoutSecond=3) if not res: self.logger.info( @@ -337,7 +337,7 @@ async def TestCommissioningWithSetupPayload(self, setupPayload: str, nodeid: int async def TestOnNetworkCommissioning(self, discriminator: int, setuppin: int, nodeid: int, ip_override: str = None): self.logger.info("Testing discovery") - device = self.TestDiscovery(discriminator=discriminator) + device = await self.TestDiscovery(discriminator=discriminator) if not device: self.logger.info("Failed to discover any devices.") return False diff --git a/src/controller/python/test/test_scripts/commissioning_test.py b/src/controller/python/test/test_scripts/commissioning_test.py index c53ab00f33489a..ac7954595bae91 100755 --- a/src/controller/python/test/test_scripts/commissioning_test.py +++ b/src/controller/python/test/test_scripts/commissioning_test.py @@ -125,7 +125,7 @@ async def main(): nodeid=112233, paaTrustStorePath=options.paaTrustStorePath, testCommissioner=True) logger.info("Testing discovery") - FailIfNot(test.TestDiscovery(discriminator=options.discriminator), + FailIfNot(await test.TestDiscovery(discriminator=options.discriminator), "Failed to discover any devices.") FailIfNot(test.SetNetworkCommissioningParameters(dataset=TEST_THREAD_NETWORK_DATASET_TLV), diff --git a/src/controller/python/test/test_scripts/failsafe_tests.py b/src/controller/python/test/test_scripts/failsafe_tests.py index d27111cbf76354..9e4d4bb14e7c71 100755 --- a/src/controller/python/test/test_scripts/failsafe_tests.py +++ b/src/controller/python/test/test_scripts/failsafe_tests.py @@ -88,7 +88,7 @@ async def main(): nodeid=112233, paaTrustStorePath=options.paaTrustStorePath, testCommissioner=False) logger.info("Testing discovery") - FailIfNot(test.TestDiscovery(discriminator=TEST_DISCRIMINATOR), + FailIfNot(await test.TestDiscovery(discriminator=TEST_DISCRIMINATOR), "Failed to discover any devices.") FailIfNot(test.SetNetworkCommissioningParameters(dataset=TEST_THREAD_NETWORK_DATASET_TLV), diff --git a/src/controller/python/test/test_scripts/mobile-device-test.py b/src/controller/python/test/test_scripts/mobile-device-test.py index 179dfa079a6614..27f8e98964d7b9 100755 --- a/src/controller/python/test/test_scripts/mobile-device-test.py +++ b/src/controller/python/test/test_scripts/mobile-device-test.py @@ -59,7 +59,7 @@ async def ethernet_commissioning(test: BaseTestHelper, discriminator: int, setup_pin: int, address_override: str, device_nodeid: int): logger.info("Testing discovery") - device = test.TestDiscovery(discriminator=discriminator) + device = await test.TestDiscovery(discriminator=discriminator) FailIfNot(device, "Failed to discover any devices.") address = device.addresses[0] diff --git a/src/python_testing/TC_IDM_1_2.py b/src/python_testing/TC_IDM_1_2.py index 55e2c4c65e7c6f..c91cef571d952f 100644 --- a/src/python_testing/TC_IDM_1_2.py +++ b/src/python_testing/TC_IDM_1_2.py @@ -202,7 +202,7 @@ async def test_TC_IDM_1_2(self): new_fabric_admin = new_certificate_authority.NewFabricAdmin(vendorId=0xFFF1, fabricId=self.matter_test_config.fabric_id + 1) TH2 = new_fabric_admin.NewController(nodeId=112233) - devices = TH2.DiscoverCommissionableNodes( + devices = await TH2.DiscoverCommissionableNodes( filterType=Discovery.FilterType.LONG_DISCRIMINATOR, filter=discriminator, stopOnFirst=False) # For some reason, the devices returned here aren't filtered, so filter ourselves device = next(filter(lambda d: d.commissioningMode == 2 and d.longDiscriminator == discriminator, devices)) diff --git a/src/python_testing/TC_OPCREDS_3_1.py b/src/python_testing/TC_OPCREDS_3_1.py index 32f3ec7b1f4d20..86b6d109be8e8a 100644 --- a/src/python_testing/TC_OPCREDS_3_1.py +++ b/src/python_testing/TC_OPCREDS_3_1.py @@ -34,7 +34,7 @@ async def FindAndEstablishPase(self, longDiscriminator: int, setupPinCode: int, if dev_ctrl is None: dev_ctrl = self.default_controller - devices = dev_ctrl.DiscoverCommissionableNodes( + devices = await dev_ctrl.DiscoverCommissionableNodes( filterType=Discovery.FilterType.LONG_DISCRIMINATOR, filter=longDiscriminator, stopOnFirst=False) # For some reason, the devices returned here aren't filtered, so filter ourselves device = next(filter(lambda d: d.commissioningMode ==