Skip to content

Commit 1639268

Browse files
agnerspull[bot]
authored andcommitted
Add Error Callback for subscriptions (#19693)
This is useful when subscriptions are not renewed automatically to get the actual error from the stack. Without this change, if auto-renew is disabled, the following exception is thrown: ERROR Exception in callback AsyncReadTransaction._handleError(50) handle: <Handle AsyncReadTransaction._handleError(50)> Traceback (most recent call last): File "/usr/lib/python3.9/asyncio/events.py", line 80, in _run self._context.run(self._callback, *self._args) File "/home/sag/projects/project-chip/connectedhomeip/out/python_env/lib/python3.9/site-packages/chip/clusters/Attribute.py", line 661, in _handleError self._future.set_exception( asyncio.exceptions.InvalidStateError: invalid state
1 parent fd0ec26 commit 1639268

File tree

1 file changed

+20
-2
lines changed

1 file changed

+20
-2
lines changed

src/controller/python/chip/clusters/Attribute.py

+20-2
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ class SubscriptionTransaction:
468468
def __init__(self, transaction: 'AsyncReadTransaction', subscriptionId, devCtrl):
469469
self._onAttributeChangeCb = DefaultAttributeChangeCallback
470470
self._onEventChangeCb = DefaultEventChangeCallback
471+
self._onErrorCb = DefaultErrorCallback
471472
self._readTransaction = transaction
472473
self._subscriptionId = subscriptionId
473474
self._devCtrl = devCtrl
@@ -502,6 +503,13 @@ def SetEventUpdateCallback(self, callback: Callable[[EventReadResult, Subscripti
502503
if callback is not None:
503504
self._onEventChangeCb = callback
504505

506+
def SetErrorCallback(self, callback: Callable[[int, SubscriptionTransaction], None]):
507+
'''
508+
Sets the callback function in case a subscription error occured, accepts a Callable accepts an error code and the cached data.
509+
'''
510+
if callback is not None:
511+
self._onErrorCb = callback
512+
505513
@property
506514
def OnAttributeChangeCb(self) -> Callable[[TypedAttributePath, SubscriptionTransaction], None]:
507515
return self._onAttributeChangeCb
@@ -510,6 +518,10 @@ def OnAttributeChangeCb(self) -> Callable[[TypedAttributePath, SubscriptionTrans
510518
def OnEventChangeCb(self) -> Callable[[EventReadResult, SubscriptionTransaction], None]:
511519
return self._onEventChangeCb
512520

521+
@property
522+
def OnErrorCb(self) -> Callable[[int, SubscriptionTransaction], None]:
523+
return self._onErrorCb
524+
513525
def Shutdown(self):
514526
if (self._isDone):
515527
print("Subscription was already terminated previously!")
@@ -545,6 +557,10 @@ def DefaultEventChangeCallback(data: EventReadResult, transaction: SubscriptionT
545557
pprint(data, expand_all=True)
546558

547559

560+
def DefaultErrorCallback(chipError: int, transaction: SubscriptionTransaction):
561+
print("Error during Subscription: Chip Stack Error %d".format(chipError))
562+
563+
548564
def _BuildEventIndex():
549565
''' Build internal event index for locating the corresponding cluster object by path in the future.
550566
We do this because this operation will take a long time when there are lots of events, it takes about 300ms for a single query.
@@ -659,8 +675,10 @@ def handleEventData(self, header: EventHeader, path: EventPath, data: bytes, sta
659675
self._handleEventData(header, path, data, status)
660676

661677
def _handleError(self, chipError: int):
662-
self._future.set_exception(
663-
chip.exceptions.ChipStackError(chipError))
678+
if not self._future.done():
679+
self._future.set_exception(
680+
chip.exceptions.ChipStackError(chipError))
681+
self._subscription_handler.OnErrorCb(chipError, self._subscription_handler)
664682

665683
def handleError(self, chipError: int):
666684
self._event_loop.call_soon_threadsafe(

0 commit comments

Comments
 (0)