Skip to content

Commit

Permalink
[Python] Implement asyncio variant of CallAsync
Browse files Browse the repository at this point in the history
Call Matter SDK in a asyncio friendly way. During posting of the task
onto the CHIP mainloop, it makes sure that the asyncio loop is not
blocked.
  • Loading branch information
agners committed May 7, 2024
1 parent 604af30 commit 1124706
Showing 1 changed file with 44 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/controller/python/chip/ChipStack.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from __future__ import absolute_import, print_function

import asyncio
import builtins
import logging
import os
Expand Down Expand Up @@ -164,6 +165,31 @@ def Wait(self, timeoutMs: int = None):
return self._res


class AsyncSimpleCallableHandle:
"""Class which handles Matter SDK Calls asyncio friendly"""

def __init__(self, callback, loop, future):
self._callback = callback
self._loop = loop
self._future = future
self._result = None
self._exception = None

def _done(self):
if self._exception:
self._future.set_exception(self._exception)
else:
self._future.set_result(self._result)

def __call__(self):
try:
self._result = self._callback()
except Exception as ex:
self._exception = ex
self._loop.call_soon_threadsafe(self._done)
pythonapi.Py_DecRef(py_object(self))


_CompleteFunct = CFUNCTYPE(None, c_void_p, c_void_p)
_ErrorFunct = CFUNCTYPE(None, c_void_p, c_void_p,
c_ulong, POINTER(DeviceStatusStruct))
Expand Down Expand Up @@ -367,6 +393,24 @@ def Call(self, callFunct, timeoutMs: int = None):
return self.callbackRes
return res

async def CallAsync(self, callFunct, timeoutMs: int = None):
'''Run a Python function on CHIP stack, and wait for the response.
This function will post a task on CHIP mainloop and waits for the call response in a asyncio friendly manner.
'''
loop = asyncio.get_event_loop()
future = loop.create_future()
callObj = AsyncSimpleCallableHandle(callFunct, loop, future)
pythonapi.Py_IncRef(py_object(callObj))

res = self._ChipStackLib.pychip_DeviceController_PostTaskOnChipThread(
self.cbHandleChipThreadRun, py_object(callObj))

if not res.is_success:
pythonapi.Py_DecRef(py_object(callObj))
raise res.to_exception()

return await asyncio.wait_for(future, timeoutMs / 1000 if timeoutMs else None)

def CallAsyncWithCallback(self, callFunct):
'''Run a Python function on CHIP stack, and wait for the application specific response.
This function is a wrapper of PostTaskOnChipThread, which includes some handling of application specific logics.
Expand Down

0 comments on commit 1124706

Please sign in to comment.