|
| 1 | +From 9bc05af1e1ef2ec93336dc0eecba16b6802b6fb1 Mon Sep 17 00:00:00 2001 |
| 2 | +Message-ID: <9bc05af1e1ef2ec93336dc0eecba16b6802b6fb1.1716466458.git.stefan@agner.ch> |
| 3 | +From: Stefan Agner <stefan@agner.ch> |
| 4 | +Date: Thu, 23 May 2024 12:48:54 +0200 |
| 5 | +Subject: [PATCH] [Python] Add raw attribute callback |
| 6 | + |
| 7 | +Add new subscription callback which uses raw AttributePath as paths |
| 8 | +of changed attributes. This allows to subscribe to custom clusters, |
| 9 | +where no Cluster/Attribute types are part of the Python library. |
| 10 | + |
| 11 | +Also allow to get the raw Python values (in tagged dict format) |
| 12 | +directly from the subscription transaction. |
| 13 | +--- |
| 14 | + .../python/chip/clusters/Attribute.py | 48 +++++++++++++++---- |
| 15 | + 1 file changed, 38 insertions(+), 10 deletions(-) |
| 16 | + |
| 17 | +diff --git a/src/controller/python/chip/clusters/Attribute.py b/src/controller/python/chip/clusters/Attribute.py |
| 18 | +index 9e46eed469..ce522bf452 100644 |
| 19 | +--- a/src/controller/python/chip/clusters/Attribute.py |
| 20 | ++++ b/src/controller/python/chip/clusters/Attribute.py |
| 21 | +@@ -466,6 +466,7 @@ class SubscriptionTransaction: |
| 22 | + def __init__(self, transaction: AsyncReadTransaction, subscriptionId, devCtrl): |
| 23 | + self._onResubscriptionAttemptedCb = DefaultResubscriptionAttemptedCallback |
| 24 | + self._onAttributeChangeCb = DefaultAttributeChangeCallback |
| 25 | ++ self._onRawAttributeChangeCb = None |
| 26 | + self._onEventChangeCb = DefaultEventChangeCallback |
| 27 | + self._onErrorCb = DefaultErrorCallback |
| 28 | + self._readTransaction = transaction |
| 29 | +@@ -491,6 +492,18 @@ class SubscriptionTransaction: |
| 30 | + else: |
| 31 | + return data[path.Path.EndpointId][path.ClusterType][path.AttributeType] |
| 32 | + |
| 33 | ++ def GetTLVAttributes(self) -> Dict[int, Dict[int, Dict[int, Any]]]: |
| 34 | ++ '''Returns the attributes value cache in raw/tag dict value tracking |
| 35 | ++ the latest state on the publisher. |
| 36 | ++ ''' |
| 37 | ++ return self._readTransaction._cache.attributeTLVCache |
| 38 | ++ |
| 39 | ++ |
| 40 | ++ def GetTLVAttribute(self, path: AttributePath) -> bytes: |
| 41 | ++ '''Returns a specific attribute given a AttributePath. |
| 42 | ++ ''' |
| 43 | ++ return self._readTransaction._cache.attributeTLVCache[path.EndpointId][path.ClusterId][path.AttributeId] |
| 44 | ++ |
| 45 | + def GetEvents(self): |
| 46 | + return self._readTransaction.GetAllEventValues() |
| 47 | + |
| 48 | +@@ -564,8 +577,14 @@ class SubscriptionTransaction: |
| 49 | + Sets the callback function for the attribute value change event, |
| 50 | + accepts a Callable accepts an attribute path and the cached data. |
| 51 | + ''' |
| 52 | +- if callback is not None: |
| 53 | +- self._onAttributeChangeCb = callback |
| 54 | ++ self._onAttributeChangeCb = callback |
| 55 | ++ |
| 56 | ++ def SetRawAttributeUpdateCallback(self, callback: Callable[[AttributePath, SubscriptionTransaction], None]): |
| 57 | ++ ''' |
| 58 | ++ Sets the callback function for raw attribute value change event, |
| 59 | ++ accepts a Callable which accepts an attribute path and the cached data. |
| 60 | ++ ''' |
| 61 | ++ self._onRawAttributeChangeCb = callback |
| 62 | + |
| 63 | + def SetEventUpdateCallback(self, callback: Callable[[EventReadResult, SubscriptionTransaction], None]): |
| 64 | + if callback is not None: |
| 65 | +@@ -583,6 +602,10 @@ class SubscriptionTransaction: |
| 66 | + def OnAttributeChangeCb(self) -> Callable[[TypedAttributePath, SubscriptionTransaction], None]: |
| 67 | + return self._onAttributeChangeCb |
| 68 | + |
| 69 | ++ @property |
| 70 | ++ def OnRawAttributeChangeCb(self) -> Callable[[TypedAttributePath, SubscriptionTransaction], None]: |
| 71 | ++ return self._onRawAttributeChangeCb |
| 72 | ++ |
| 73 | + @property |
| 74 | + def OnEventChangeCb(self) -> Callable[[EventReadResult, SubscriptionTransaction], None]: |
| 75 | + return self._onEventChangeCb |
| 76 | +@@ -785,14 +808,19 @@ class AsyncReadTransaction: |
| 77 | + |
| 78 | + if (self._subscription_handler is not None): |
| 79 | + for change in self._changedPathSet: |
| 80 | +- try: |
| 81 | +- attribute_path = TypedAttributePath(Path=change) |
| 82 | +- except (KeyError, ValueError) as err: |
| 83 | +- # path could not be resolved into a TypedAttributePath |
| 84 | +- logging.getLogger(__name__).exception(err) |
| 85 | +- continue |
| 86 | +- self._subscription_handler.OnAttributeChangeCb( |
| 87 | +- attribute_path, self._subscription_handler) |
| 88 | ++ if self._subscription_handler.OnAttributeChangeCb: |
| 89 | ++ try: |
| 90 | ++ attribute_path = TypedAttributePath(Path=change) |
| 91 | ++ except (KeyError, ValueError) as err: |
| 92 | ++ # path could not be resolved into a TypedAttributePath |
| 93 | ++ logging.getLogger(__name__).exception(err) |
| 94 | ++ continue |
| 95 | ++ self._subscription_handler.OnAttributeChangeCb( |
| 96 | ++ attribute_path, self._subscription_handler) |
| 97 | ++ |
| 98 | ++ if self._subscription_handler.OnRawAttributeChangeCb: |
| 99 | ++ self._subscription_handler.OnRawAttributeChangeCb( |
| 100 | ++ change, self._subscription_handler) |
| 101 | + |
| 102 | + # Clear it out once we've notified of all changes in this transaction. |
| 103 | + self._changedPathSet = set() |
| 104 | +-- |
| 105 | +2.45.1 |
| 106 | + |
0 commit comments