Skip to content

Commit

Permalink
Add python IM event client code (#12194)
Browse files Browse the repository at this point in the history
  • Loading branch information
yunhanw-google authored and pull[bot] committed Dec 17, 2021
1 parent a6af0ec commit d908d14
Show file tree
Hide file tree
Showing 13 changed files with 485 additions and 47 deletions.
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)
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

0 comments on commit d908d14

Please sign in to comment.