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

Restyle [Python] Process attribute cache updates in Python thread #35572

Closed
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
47 changes: 37 additions & 10 deletions src/controller/python/chip/clusters/Attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ def __init__(self, transaction: AsyncReadTransaction, subscriptionId, devCtrl):
self._onResubscriptionAttemptedCb: Callable[[SubscriptionTransaction,
int, int], None] = DefaultResubscriptionAttemptedCallback
self._onAttributeChangeCb: Callable[[TypedAttributePath, SubscriptionTransaction], None] = DefaultAttributeChangeCallback
self._onRawAttributeChangeCb: Optional[Callable[[AttributePath, SubscriptionTransaction]]] = None
self._onEventChangeCb: Callable[[EventReadResult, SubscriptionTransaction], None] = DefaultEventChangeCallback
self._onErrorCb: Callable[[int, SubscriptionTransaction], None] = DefaultErrorCallback
self._readTransaction = transaction
Expand All @@ -454,6 +455,17 @@ def GetAttribute(self, path: TypedAttributePath) -> Any:
else:
return data[path.Path.EndpointId][path.ClusterType][path.AttributeType]

def GetTLVAttributes(self) -> Dict[int, Dict[int, Dict[int, Any]]]:
'''Returns the attributes value cache in raw/tag dict value tracking
the latest state on the publisher.
'''
return self._readTransaction._cache.attributeTLVCache

def GetTLVAttribute(self, path: AttributePath) -> bytes:
'''Returns a specific attribute given a AttributePath.
'''
return self._readTransaction._cache.attributeTLVCache[path.EndpointId][path.ClusterId][path.AttributeId]

def GetEvents(self):
return self._readTransaction.GetAllEventValues()

Expand Down Expand Up @@ -534,8 +546,14 @@ def SetAttributeUpdateCallback(self, callback: Callable[[TypedAttributePath, Sub
Sets the callback function for the attribute value change event,
accepts a Callable accepts an attribute path and the cached data.
'''
if callback is not None:
self._onAttributeChangeCb = callback
self._onAttributeChangeCb = callback

def SetRawAttributeUpdateCallback(self, callback: Callable[[AttributePath, SubscriptionTransaction], None]):
'''
Sets the callback function for raw attribute value change event,
accepts a Callable which accepts an attribute path and the cached data.
'''
self._onRawAttributeChangeCb = callback

def SetEventUpdateCallback(self, callback: Callable[[EventReadResult, SubscriptionTransaction], None]):
if callback is not None:
Expand All @@ -553,6 +571,10 @@ def SetErrorCallback(self, callback: Callable[[int, SubscriptionTransaction], No
def OnAttributeChangeCb(self) -> Callable[[TypedAttributePath, SubscriptionTransaction], None]:
return self._onAttributeChangeCb

@property
def OnRawAttributeChangeCb(self) -> Callable[[TypedAttributePath, SubscriptionTransaction], None]:
return self._onRawAttributeChangeCb

@property
def OnEventChangeCb(self) -> Callable[[EventReadResult, SubscriptionTransaction], None]:
return self._onEventChangeCb
Expand Down Expand Up @@ -767,14 +789,19 @@ def _handleReportBegin(self):
def _handleReportEnd(self):
if (self._subscription_handler is not None):
for change in self._changedPathSet:
try:
attribute_path = TypedAttributePath(Path=change)
except (KeyError, ValueError) as err:
# path could not be resolved into a TypedAttributePath
LOGGER.exception(err)
continue
self._subscription_handler.OnAttributeChangeCb(
attribute_path, self._subscription_handler)
if self._subscription_handler.OnAttributeChangeCb:
try:
attribute_path = TypedAttributePath(Path=change)
except (KeyError, ValueError) as err:
# path could not be resolved into a TypedAttributePath
LOGGER.exception(err)
continue
self._subscription_handler.OnAttributeChangeCb(
attribute_path, self._subscription_handler)

if self._subscription_handler.OnRawAttributeChangeCb:
self._subscription_handler.OnRawAttributeChangeCb(
change, self._subscription_handler)

# Clear it out once we've notified of all changes in this transaction.
self._changedPathSet = set()
Expand Down
3 changes: 2 additions & 1 deletion src/controller/python/test/test_scripts/cluster_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,12 @@ def subUpdate(path: TypedAttributePath, transaction: SubscriptionTransaction):
sub.SetAttributeUpdateCallback(subUpdate)

try:
data = sub.GetAttributes()
req = Clusters.OnOff.Commands.On()
await devCtrl.SendCommand(nodeid=NODE_ID, endpoint=1, payload=req)

await asyncio.wait_for(event.wait(), timeout=11)

data = sub.GetAttributes()
if (data[1][Clusters.OnOff][Clusters.OnOff.Attributes.OnOff] != 1):
raise ValueError("Current On/Off state should be 1")

Expand All @@ -232,6 +232,7 @@ def subUpdate(path: TypedAttributePath, transaction: SubscriptionTransaction):

await asyncio.wait_for(event.wait(), timeout=11)

data = sub.GetAttributes()
if (data[1][Clusters.OnOff][Clusters.OnOff.Attributes.OnOff] != 0):
raise ValueError("Current On/Off state should be 0")

Expand Down