Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Python] Convert DiscoverCommissionableNodes to asyncio #34033

Merged
merged 2 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 31 additions & 23 deletions src/controller/python/chip/ChipDeviceCtrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:

Expand All @@ -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 = []

Expand All @@ -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()
Expand Down
4 changes: 2 additions & 2 deletions src/controller/python/chip/commissioning/pase.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/controller/python/chip/yaml/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(), ...]
Expand Down
6 changes: 3 additions & 3 deletions src/controller/python/test/test_scripts/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion src/controller/python/test/test_scripts/failsafe_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion src/python_testing/TC_IDM_1_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,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))
Expand Down
2 changes: 1 addition & 1 deletion src/python_testing/TC_OPCREDS_3_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 ==
Expand Down
Loading