Skip to content

Commit a51ad2b

Browse files
committed
[Python] Convert DiscoverCommissionableNodes to asyncio
Make the discovery of commissionable nodes Python asyncio APIs as well. This avoids blocking the event loop when using the API. The implementation is also safe to be used with the Python asyncio wait_for() function: The discovery process will be cancelled if the timeout is reached.
1 parent e407d40 commit a51ad2b

File tree

1 file changed

+30
-22
lines changed

1 file changed

+30
-22
lines changed

src/controller/python/chip/ChipDeviceCtrl.py

+30-22
Original file line numberDiff line numberDiff line change
@@ -729,8 +729,8 @@ def GetAddressAndPort(self, nodeid):
729729

730730
return (address.value.decode(), port.value) if error == 0 else None
731731

732-
def DiscoverCommissionableNodes(self, filterType: discovery.FilterType = discovery.FilterType.NONE, filter: typing.Any = None,
733-
stopOnFirst: bool = False, timeoutSecond: int = 5) -> typing.Union[None, CommissionableNode, typing.List[CommissionableNode]]:
732+
async def DiscoverCommissionableNodes(self, filterType: discovery.FilterType = discovery.FilterType.NONE, filter: typing.Any = None,
733+
stopOnFirst: bool = False, timeoutSecond: int = 5) -> typing.Union[None, CommissionableNode, typing.List[CommissionableNode]]:
734734
''' Discover commissionable nodes via DNS-SD with specified filters.
735735
Supported filters are:
736736
@@ -752,27 +752,35 @@ def DiscoverCommissionableNodes(self, filterType: discovery.FilterType = discove
752752
if isinstance(filter, int):
753753
filter = str(filter)
754754

755-
self._ChipStack.Call(
756-
lambda: self._dmLib.pychip_DeviceController_DiscoverCommissionableNodes(
757-
self.devCtrl, int(filterType), str(filter).encode("utf-8"))).raise_on_error()
758-
759-
if timeoutSecond != 0:
760-
if stopOnFirst:
761-
target = time.time() + timeoutSecond
762-
while time.time() < target:
763-
if self._ChipStack.Call(
764-
lambda: self._dmLib.pychip_DeviceController_HasDiscoveredCommissionableNode(self.devCtrl)):
765-
break
766-
time.sleep(0.1)
767-
else:
768-
time.sleep(timeoutSecond)
769-
770-
self._ChipStack.Call(
771-
lambda: self._dmLib.pychip_DeviceController_StopCommissionableDiscovery(self.devCtrl)).raise_on_error()
755+
# Discovery is also used during commissioning. Make sure this manual discovery
756+
# and commissioning attempts do not interfere with each other.
757+
async with self._commissioning_lock:
758+
res = await self._ChipStack.CallAsync(
759+
lambda: self._dmLib.pychip_DeviceController_DiscoverCommissionableNodes(
760+
self.devCtrl, int(filterType), str(filter).encode("utf-8")))
761+
res.raise_on_error()
772762

773-
return self.GetDiscoveredDevices()
763+
async def _wait_discovery():
764+
while not await self._ChipStack.CallAsync(
765+
lambda: self._dmLib.pychip_DeviceController_HasDiscoveredCommissionableNode(self.devCtrl)):
766+
await asyncio.sleep(0.1)
767+
return
774768

775-
def GetDiscoveredDevices(self):
769+
try:
770+
if stopOnFirst:
771+
await asyncio.wait_for(_wait_discovery(), timeoutSecond)
772+
else:
773+
await asyncio.sleep(timeoutSecond)
774+
except TimeoutError:
775+
# Expected timeout, do nothing
776+
pass
777+
finally:
778+
res = await self._ChipStack.CallAsync(
779+
lambda: self._dmLib.pychip_DeviceController_StopCommissionableDiscovery(self.devCtrl))
780+
res.raise_on_error()
781+
782+
return await self.GetDiscoveredDevices()
783+
async def GetDiscoveredDevices(self):
776784
def GetDevices(devCtrl):
777785
devices = []
778786

@@ -786,7 +794,7 @@ def HandleDevice(deviceJson, deviceJsonLen):
786794
self._dmLib.pychip_DeviceController_IterateDiscoveredCommissionableNodes(devCtrl.devCtrl, HandleDevice)
787795
return devices
788796

789-
return self._ChipStack.Call(lambda: GetDevices(self))
797+
return await self._ChipStack.CallAsync(lambda: GetDevices(self))
790798

791799
def GetIPForDiscoveredDevice(self, idx, addrStr, length):
792800
self.CheckIsActive()

0 commit comments

Comments
 (0)