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

Add python IM event client code #12194

Merged
Merged
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
5 changes: 1 addition & 4 deletions src/app/MessageDef/EventDataIB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,10 +455,7 @@ CHIP_ERROR EventDataIB::Parser::ProcessEventTimestamp(EventHeader & aEventHeader
hasEpochTimestamp = true;
}

if ((hasSystemTimestamp && !hasEpochTimestamp && !hasDeltaSystemTimestamp && !hasDeltaEpochTimestamp) ||
(!hasSystemTimestamp && hasEpochTimestamp && !hasDeltaSystemTimestamp && !hasDeltaEpochTimestamp) ||
(!hasSystemTimestamp && !hasEpochTimestamp && hasDeltaSystemTimestamp && !hasDeltaEpochTimestamp) ||
(!hasSystemTimestamp && !hasEpochTimestamp && !hasDeltaSystemTimestamp && hasDeltaEpochTimestamp))
if (hasSystemTimestamp + hasEpochTimestamp + hasDeltaSystemTimestamp + hasDeltaEpochTimestamp == 1)
{
return CHIP_NO_ERROR;
}
Expand Down
5 changes: 2 additions & 3 deletions src/app/ReadClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,10 @@ class ReadClient : public Messaging::ExchangeDelegate
* The ReadClient object MUST continue to exist after this call is completed.
*
* This callback will be called when receiving event data received in the Read and Subscribe interactions
*
* only one of the apData and apStatus will be non-null.
* @param[in] apReadClient: The read client object that initiated the read or subscribe transaction.
* @param[in] aEventHeader: The event header in report response.
* @param[in] apData: A TLVReader positioned right on the payload of the event. This will be set to null if the apStatus is
* not null.
* @param[in] apData: A TLVReader positioned right on the payload of the event.
* @param[in] apStatus: Event-specific status, containing an InteractionModel::Status code as well as an optional
* cluster-specific status code.
*/
Expand Down
6 changes: 3 additions & 3 deletions src/app/reporting/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,14 +227,14 @@ CHIP_ERROR Engine::BuildSingleReportDataEventReports(ReportDataMessage::Builder

VerifyOrExit(clusterInfoList != nullptr, );
VerifyOrExit(apReadHandler != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
// If the eventManager is not valid or has not been initialized,
// skip the rest of processing
VerifyOrExit(eventManager.IsValid(), ChipLogError(DataManagement, "EventManagement has not yet initialized"));

EventReports = aReportDataBuilder.CreateEventReports();
SuccessOrExit(err = EventReports.GetError());

memcpy(initialEvents, eventNumberList, sizeof(initialEvents));
// If the eventManager is not valid or has not been initialized,
// skip the rest of processing
VerifyOrExit(eventManager.IsValid(), err = CHIP_ERROR_INCORRECT_STATE);

for (size_t index = 0; index < kNumPriorityLevel; index++)
{
Expand Down
7 changes: 3 additions & 4 deletions src/controller/ReadInteraction.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,11 @@ CHIP_ERROR ReadAttribute(Messaging::ExchangeManager * aExchangeMgr, const Sessio
*/
template <typename DecodableEventTypeInfo>
CHIP_ERROR ReadEvent(Messaging::ExchangeManager * apExchangeMgr, const SessionHandle sessionHandle, EndpointId endpointId,
ClusterId clusterId, EventId eventId,
typename TypedReadEventCallback<DecodableEventTypeInfo>::OnSuccessCallbackType onSuccessCb,
typename TypedReadEventCallback<DecodableEventTypeInfo>::OnErrorCallbackType onErrorCb)
{
ClusterId clusterId = DecodableEventTypeInfo::GetClusterId();
EventId eventId = DecodableEventTypeInfo::GetEventId();
app::EventPathParams eventPath(endpointId, clusterId, eventId);
app::ReadPrepareParams readParams(sessionHandle);
app::ReadClient * readClient = nullptr;
Expand Down Expand Up @@ -150,9 +151,7 @@ CHIP_ERROR ReadEvent(Messaging::ExchangeManager * aExchangeMgr, const SessionHan
typename TypedReadEventCallback<typename EventTypeInfo::DecodableType>::OnSuccessCallbackType onSuccessCb,
typename TypedReadEventCallback<typename EventTypeInfo::DecodableType>::OnErrorCallbackType onErrorCb)
{
return ReadAttribute<typename EventTypeInfo::DecodableType>(aExchangeMgr, sessionHandle, endpointId,
EventTypeInfo::GetClusterId(), EventTypeInfo::GetEventId(),
onSuccessCb, onErrorCb);
return ReadEvent<typename EventTypeInfo::DecodableType>(aExchangeMgr, sessionHandle, endpointId, onSuccessCb, onErrorCb);
}
} // namespace Controller
} // namespace chip
6 changes: 2 additions & 4 deletions src/controller/TypedReadCallback.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,10 @@ class TypedReadEventCallback final : public app::ReadClient::Callback
{
CHIP_ERROR err = CHIP_NO_ERROR;
DecodableEventTypeInfo value;
VerifyOrExit(aEventHeader.mPath.mClusterId == DecodableEventTypeInfo::GetClusterId() &&
aEventHeader.mPath.mEventId == DecodableEventTypeInfo::GetEventId(),
CHIP_ERROR_SCHEMA_MISMATCH);

VerifyOrExit(apData != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);

err = app::DataModel::Decode(*apData, value);
err = apReadClient->DecodeEvent(aEventHeader, value, *apData);
SuccessOrExit(err);

mOnSuccess(aEventHeader, value);
Expand Down
78 changes: 77 additions & 1 deletion src/controller/python/chip/ChipDeviceCtrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,81 @@ async def ReadAttribute(self, nodeid: int, attributes: typing.List[typing.Union[
raise self._ChipStack.ErrorToException(res)
return await future

async def ReadEvent(self, nodeid: int, events: typing.List[typing.Union[
None, # Empty tuple, all wildcard
typing.Tuple[int], # Endpoint
# Wildcard endpoint, Cluster id present
typing.Tuple[typing.Type[ClusterObjects.Cluster]],
# Wildcard endpoint, Cluster + Event present
typing.Tuple[typing.Type[ClusterObjects.ClusterEventDescriptor]],
# Wildcard event id
typing.Tuple[int, typing.Type[ClusterObjects.Cluster]],
# Concrete path
typing.Tuple[int, typing.Type[ClusterObjects.ClusterEventDescriptor]]
]], reportInterval: typing.Tuple[int, int] = None):
'''
Read a list of events from a target node
nodeId: Target's Node ID
events: A list of tuples of varying types depending on the type of read being requested:
(endpoint, Clusters.ClusterA.EventA): Endpoint = specific, Cluster = specific, Event = specific
(endpoint, Clusters.ClusterA): Endpoint = specific, Cluster = specific, Event = *
(Clusters.ClusterA.EventA): Endpoint = *, Cluster = specific, Event = specific
endpoint: Endpoint = specific, Cluster = *, Event = *
Clusters.ClusterA: Endpoint = *, Cluster = specific, Event = *
'*' or (): Endpoint = *, Cluster = *, Event = *
The cluster and events specified above are to be selected from the generated cluster objects.
e.g.
ReadEvent(1, [ 1 ] ) -- case 4 above.
ReadEvent(1, [ Clusters.Basic ] ) -- case 5 above.
ReadEvent(1, [ (1, Clusters.Basic.Events.Location ] ) -- case 1 above.
reportInterval: A tuple of two int-s for (MinIntervalFloor, MaxIntervalCeiling). Used by establishing subscriptions.
When not provided, a read request will be sent.
'''

eventLoop = asyncio.get_running_loop()
future = eventLoop.create_future()

device = self.GetConnectedDeviceSync(nodeid)
eves = []
for v in events:
endpoint = None
cluster = None
event = None
if v in [('*'), ()]:
# Wildcard
pass
elif type(v) is not tuple:
print(type(v))
if type(v) is int:
endpoint = v
elif issubclass(v, ClusterObjects.Cluster):
cluster = v
elif issubclass(v, ClusterObjects.ClusterEventDescriptor):
event = v
else:
raise ValueError("Unsupported Event Path")
else:
# endpoint + (cluster) event / endpoint + cluster
endpoint = v[0]
if issubclass(v[1], ClusterObjects.Cluster):
cluster = v[1]
elif issubclass(v[1], ClusterAttribute.ClusterEventDescriptor):
event = v[1]
else:
raise ValueError("Unsupported Attribute Path")
eves.append(ClusterAttribute.EventPath(
EndpointId=endpoint, Cluster=cluster, Event=event))
res = self._ChipStack.Call(
lambda: ClusterAttribute.ReadEvents(future, eventLoop, device, self, eves, ClusterAttribute.SubscriptionParameters(reportInterval[0], reportInterval[1]) if reportInterval else None))
if res != 0:
raise self._ChipStack.ErrorToException(res)
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved
outcome = await future
return await future

def ZCLSend(self, cluster, command, nodeid, endpoint, groupid, args, blocking=False):
req = None
try:
Expand All @@ -507,7 +582,8 @@ def ZCLReadAttribute(self, cluster, attribute, nodeid, endpoint, groupid, blocki
except:
raise UnknownAttribute(cluster, attribute)

result = asyncio.run(self.ReadAttribute(nodeid, [(endpoint, req)]))
result = asyncio.run(self.ReadAttribute(
nodeid, [(endpoint, req)]))['Attributes']
path = ClusterAttribute.AttributePath(
EndpointId=endpoint, Attribute=req)
return im.AttributeReadResult(path=im.AttributePath(nodeId=nodeid, endpointId=path.EndpointId, clusterId=path.ClusterId, attributeId=path.AttributeId), status=0, value=result[path].Data.value)
Expand Down
Loading