Skip to content

Commit 5991608

Browse files
bzbarsky-applepull[bot]
authored andcommitted
Include event header information in results from multi-path read/subscribe. (#26173)
Fixes #26075
1 parent d7d5761 commit 5991608

File tree

7 files changed

+223
-113
lines changed

7 files changed

+223
-113
lines changed

src/darwin/Framework/CHIP/MTRBaseDevice.h

+19
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,20 @@ NS_ASSUME_NONNULL_BEGIN
4141
* MTRDataKey: Data-value NSDictionary object.
4242
* Included when there is data and when there is no error.
4343
* The data-value is described below.
44+
* MTREventNumberKey : NSNumber-wrapped uint64_t value. Monotonically increasing, and consecutive event reports
45+
* should have consecutive numbers unless device reboots, or if events are lost.
46+
* Only present when both MTREventPathKey and MTRDataKey are present.
47+
* MTREventPriorityKey : NSNumber-wrapped MTREventPriority value.
48+
* Only present when both MTREventPathKey and MTRDataKey are present.
49+
* MTREventTimeTypeKey : NSNumber-wrapped MTREventTimeType value.
50+
* Only present when both MTREventPathKey and MTRDataKey are present.
51+
* MTREventSystemUpTimeKey : NSNumber-wrapped NSTimeInterval value.
52+
* Only present when MTREventTimeTypeKey is MTREventTimeTypeSystemUpTime.
53+
* MTREventTimestampDateKey : NSDate object.
54+
* Only present when MTREventTimeTypeKey is MTREventTimeTypeTimestampDate.
55+
*
56+
* Only one of MTREventTimestampDateKey and MTREventSystemUpTimeKey will be present, depending on the value for
57+
* MTREventTimeTypeKey.
4458
*
4559
* A data-value is an NSDictionary object with the following key values:
4660
*
@@ -117,6 +131,11 @@ extern NSString * const MTRDoubleValueType;
117131
extern NSString * const MTRNullValueType;
118132
extern NSString * const MTRStructureValueType;
119133
extern NSString * const MTRArrayValueType;
134+
extern NSString * const MTREventNumberKey API_AVAILABLE(ios(16.5), macos(13.4), watchos(9.5), tvos(16.5));
135+
extern NSString * const MTREventPriorityKey API_AVAILABLE(ios(16.5), macos(13.4), watchos(9.5), tvos(16.5));
136+
extern NSString * const MTREventTimeTypeKey API_AVAILABLE(ios(16.5), macos(13.4), watchos(9.5), tvos(16.5));
137+
extern NSString * const MTREventSystemUpTimeKey API_AVAILABLE(ios(16.5), macos(13.4), watchos(9.5), tvos(16.5));
138+
extern NSString * const MTREventTimestampDateKey API_AVAILABLE(ios(16.5), macos(13.4), watchos(9.5), tvos(16.5));
120139

121140
@class MTRClusterStateCacheContainer;
122141
@class MTRAttributeCacheContainer;

src/darwin/Framework/CHIP/MTRBaseDevice.mm

+98-22
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@
7474
NSString * const MTRNullValueType = @"Null";
7575
NSString * const MTRStructureValueType = @"Structure";
7676
NSString * const MTRArrayValueType = @"Array";
77+
NSString * const MTREventNumberKey = @"eventNumber";
78+
NSString * const MTREventPriorityKey = @"eventPriority";
79+
NSString * const MTREventTimeTypeKey = @"eventTimeType";
80+
NSString * const MTREventSystemUpTimeKey = @"eventSystemUpTime";
81+
NSString * const MTREventTimestampDateKey = @"eventTimestampDate";
7782

7883
class MTRDataValueDictionaryCallbackBridge;
7984

@@ -752,7 +757,7 @@ CHIP_ERROR Encode(chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) const
752757
public:
753758
using OnSuccessAttributeCallbackType
754759
= std::function<void(const ConcreteAttributePath & aPath, const DecodableValueType & aData)>;
755-
using OnSuccessEventCallbackType = std::function<void(const ConcreteEventPath & aPath, const DecodableValueType & aData)>;
760+
using OnSuccessEventCallbackType = std::function<void(const EventHeader & aEventHeader, const DecodableValueType & aData)>;
756761
using OnErrorCallbackType = std::function<void(
757762
const app::ConcreteAttributePath * attributePath, const app::ConcreteEventPath * eventPath, CHIP_ERROR aError)>;
758763
using OnDoneCallbackType = std::function<void(BufferedReadClientCallback * callback)>;
@@ -844,7 +849,7 @@ void OnEventData(const EventHeader & aEventHeader, TLV::TLVReader * apData, cons
844849

845850
SuccessOrExit(err = app::DataModel::Decode(*apData, value));
846851

847-
mOnEventSuccess(aEventHeader.mPath, value);
852+
mOnEventSuccess(aEventHeader, value);
848853

849854
exit:
850855
if (err != CHIP_NO_ERROR) {
@@ -944,31 +949,28 @@ - (void)readAttributePaths:(NSArray<MTRAttributeRequestPath *> * _Nullable)attri
944949

945950
auto resultArray = [[NSMutableArray alloc] init];
946951
auto onAttributeSuccessCb
947-
= [resultArray](const ConcreteAttributePath & attributePath, const MTRDataValueDictionaryDecodableType & aData) {
952+
= [resultArray](const ConcreteAttributePath & aAttributePath, const MTRDataValueDictionaryDecodableType & aData) {
948953
[resultArray addObject:@ {
949-
MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:attributePath],
954+
MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:aAttributePath],
950955
MTRDataKey : aData.GetDecodedObject()
951956
}];
952957
};
953958

954959
auto onEventSuccessCb
955-
= [resultArray](const ConcreteEventPath & eventPath, const MTRDataValueDictionaryDecodableType & aData) {
956-
[resultArray addObject:@ {
957-
MTREventPathKey : [[MTREventPath alloc] initWithPath:eventPath],
958-
MTRDataKey : aData.GetDecodedObject()
959-
}];
960+
= [resultArray](const EventHeader & aEventHeader, const MTRDataValueDictionaryDecodableType & aData) {
961+
[resultArray addObject:[MTRBaseDevice eventReportForHeader:aEventHeader andData:aData.GetDecodedObject()]];
960962
};
961963

962-
auto onFailureCb = [resultArray, interactionStatus](const app::ConcreteAttributePath * attributePath,
963-
const app::ConcreteEventPath * eventPath, CHIP_ERROR aError) {
964-
if (attributePath != nullptr) {
964+
auto onFailureCb = [resultArray, interactionStatus](const app::ConcreteAttributePath * aAttributePath,
965+
const app::ConcreteEventPath * aEventPath, CHIP_ERROR aError) {
966+
if (aAttributePath != nullptr) {
965967
[resultArray addObject:@ {
966-
MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:*attributePath],
968+
MTRAttributePathKey : [[MTRAttributePath alloc] initWithPath:*aAttributePath],
967969
MTRErrorKey : [MTRError errorForCHIPErrorCode:aError]
968970
}];
969-
} else if (eventPath != nullptr) {
971+
} else if (aEventPath != nullptr) {
970972
[resultArray addObject:@ {
971-
MTREventPathKey : [[MTREventPath alloc] initWithPath:*eventPath],
973+
MTREventPathKey : [[MTREventPath alloc] initWithPath:*aEventPath],
972974
MTRErrorKey : [MTRError errorForCHIPErrorCode:aError]
973975
}];
974976
} else {
@@ -1343,14 +1345,11 @@ - (void)subscribeToAttributePaths:(NSArray<MTRAttributeRequestPath *> * _Nullabl
13431345
});
13441346
};
13451347

1346-
auto onEventReportCb = [queue, reportHandler](const ConcreteEventPath & eventPath,
1347-
const MTRDataValueDictionaryDecodableType & data) {
1348-
id valueObject = data.GetDecodedObject();
1349-
ConcreteEventPath pathCopy(eventPath);
1348+
auto onEventReportCb = [queue, reportHandler](
1349+
const EventHeader & eventHeader, const MTRDataValueDictionaryDecodableType & data) {
1350+
NSDictionary * report = [MTRBaseDevice eventReportForHeader:eventHeader andData:data.GetDecodedObject()];
13501351
dispatch_async(queue, ^{
1351-
reportHandler(
1352-
@[ @ { MTREventPathKey : [[MTREventPath alloc] initWithPath:pathCopy], MTRDataKey : valueObject } ],
1353-
nil);
1352+
reportHandler(@[ report ], nil);
13541353
});
13551354
};
13561355

@@ -1540,6 +1539,43 @@ static CHIP_ERROR OpenCommissioningWindow(Controller::DeviceController * control
15401539
delete self;
15411540
}
15421541

1542+
#pragma mark - Utility for time conversion
1543+
NSTimeInterval MTRTimeIntervalForEventTimestampValue(uint64_t timeValue)
1544+
{
1545+
// Note: The event timestamp value as written in the spec is in microseconds, but the released 1.0 SDK implemented it in
1546+
// milliseconds. The following issue was filed to address the inconsistency:
1547+
// https://github.com/CHIP-Specifications/connectedhomeip-spec/issues/6236
1548+
// For consistency with the released behavior, calculations here will be done in milliseconds.
1549+
1550+
// First convert the event timestamp value (in milliseconds) to NSTimeInterval - to minimize potential loss of precision
1551+
// of uint64 => NSTimeInterval (double), convert whole seconds and remainder separately and then combine
1552+
uint64_t eventTimestampValueSeconds = timeValue / chip::kMillisecondsPerSecond;
1553+
uint64_t eventTimestampValueRemainderMilliseconds = timeValue % chip::kMillisecondsPerSecond;
1554+
NSTimeInterval eventTimestampValueRemainder
1555+
= NSTimeInterval(eventTimestampValueRemainderMilliseconds) / chip::kMillisecondsPerSecond;
1556+
NSTimeInterval eventTimestampValue = eventTimestampValueSeconds + eventTimestampValueRemainder;
1557+
1558+
return eventTimestampValue;
1559+
}
1560+
1561+
#pragma mark - Utility for event priority conversion
1562+
BOOL MTRPriorityLevelIsValid(chip::app::PriorityLevel priorityLevel)
1563+
{
1564+
return (priorityLevel >= chip::app::PriorityLevel::Debug) && (priorityLevel <= chip::app::PriorityLevel::Critical);
1565+
}
1566+
1567+
MTREventPriority MTREventPriorityForValidPriorityLevel(chip::app::PriorityLevel priorityLevel)
1568+
{
1569+
switch (priorityLevel) {
1570+
case chip::app::PriorityLevel::Debug:
1571+
return MTREventPriorityDebug;
1572+
case chip::app::PriorityLevel::Info:
1573+
return MTREventPriorityInfo;
1574+
default:
1575+
return MTREventPriorityCritical;
1576+
}
1577+
}
1578+
15431579
} // anonymous namespace
15441580

15451581
- (void)_openCommissioningWindowWithSetupPasscode:(nullable NSNumber *)setupPasscode
@@ -1738,6 +1774,46 @@ - (void)subscribeToEventsWithEndpointID:(NSNumber * _Nullable)endpointID
17381774
subscriptionEstablished:subscriptionEstablished
17391775
resubscriptionScheduled:nil];
17401776
}
1777+
1778+
+ (NSDictionary *)eventReportForHeader:(const chip::app::EventHeader &)header andData:(id _Nullable)data
1779+
{
1780+
MTREventPath * eventPath = [[MTREventPath alloc] initWithPath:header.mPath];
1781+
if (data == nil) {
1782+
MTR_LOG_ERROR("%@ could not decode event data", eventPath);
1783+
return @{ MTREventPathKey : eventPath, MTRErrorKey : [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_ARGUMENT] };
1784+
}
1785+
1786+
// Construct the right type, and key/value depending on the type
1787+
NSNumber * eventTimeType;
1788+
NSString * timestampKey;
1789+
id timestampValue;
1790+
if (header.mTimestamp.mType == Timestamp::Type::kSystem) {
1791+
eventTimeType = @(MTREventTimeTypeSystemUpTime);
1792+
timestampKey = MTREventSystemUpTimeKey;
1793+
timestampValue = @(MTRTimeIntervalForEventTimestampValue(header.mTimestamp.mValue));
1794+
} else if (header.mTimestamp.mType == Timestamp::Type::kEpoch) {
1795+
eventTimeType = @(MTREventTimeTypeTimestampDate);
1796+
timestampKey = MTREventTimestampDateKey;
1797+
timestampValue = [NSDate dateWithTimeIntervalSince1970:MTRTimeIntervalForEventTimestampValue(header.mTimestamp.mValue)];
1798+
} else {
1799+
MTR_LOG_ERROR("%@ Unsupported event timestamp type %u - ignoring", eventPath, (unsigned int) header.mTimestamp.mType);
1800+
return @{ MTREventPathKey : eventPath, MTRErrorKey : [MTRError errorForCHIPErrorCode:CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE] };
1801+
}
1802+
1803+
if (!MTRPriorityLevelIsValid(header.mPriorityLevel)) {
1804+
MTR_LOG_ERROR("%@ Unsupported event priority %u - ignoring", eventPath, (unsigned int) header.mPriorityLevel);
1805+
return @{ MTREventPathKey : eventPath, MTRErrorKey : [MTRError errorForCHIPErrorCode:CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE] };
1806+
}
1807+
1808+
return @{
1809+
MTREventPathKey : eventPath,
1810+
MTRDataKey : data,
1811+
MTREventNumberKey : @(header.mEventNumber),
1812+
MTREventPriorityKey : @(MTREventPriorityForValidPriorityLevel(header.mPriorityLevel)),
1813+
MTREventTimeTypeKey : eventTimeType,
1814+
timestampKey : timestampValue
1815+
};
1816+
}
17411817
@end
17421818

17431819
@implementation MTRBaseDevice (Deprecated)

src/darwin/Framework/CHIP/MTRBaseDevice_Internal.h

+8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <app/ConcreteCommandPath.h>
2424
#include <app/ConcreteEventPath.h>
2525
#include <app/DeviceProxy.h>
26+
#include <app/EventHeader.h>
2627
#include <app/EventLoggingTypes.h>
2728
#include <app/EventPathParams.h>
2829

@@ -75,6 +76,13 @@ static inline MTRTransportType MTRMakeTransportType(chip::Transport::Type type)
7576
*/
7677
- (instancetype)initWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller;
7778

79+
/**
80+
* Create a report, suitable in including in the sort of data structure that
81+
* gets passed to MTRDeviceResponseHandler, from a given event header and
82+
* already-decoded event data. The data is allowed to be nil in error cases
83+
* (e.g. when TLV decoding failed).
84+
*/
85+
+ (NSDictionary *)eventReportForHeader:(const chip::app::EventHeader &)header andData:(id _Nullable)data;
7886
@end
7987

8088
@interface MTRClusterPath ()

src/darwin/Framework/CHIP/MTRDevice.h

-6
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,6 @@ typedef NS_ENUM(NSUInteger, MTRDeviceState) {
202202

203203
@end
204204

205-
extern NSString * const MTREventNumberKey API_AVAILABLE(ios(16.5), macos(13.4), watchos(9.5), tvos(16.5));
206-
extern NSString * const MTREventPriorityKey API_AVAILABLE(ios(16.5), macos(13.4), watchos(9.5), tvos(16.5));
207-
extern NSString * const MTREventTimeTypeKey API_AVAILABLE(ios(16.5), macos(13.4), watchos(9.5), tvos(16.5));
208-
extern NSString * const MTREventSystemUpTimeKey API_AVAILABLE(ios(16.5), macos(13.4), watchos(9.5), tvos(16.5));
209-
extern NSString * const MTREventTimestampDateKey API_AVAILABLE(ios(16.5), macos(13.4), watchos(9.5), tvos(16.5));
210-
211205
@protocol MTRDeviceDelegate <NSObject>
212206
@required
213207
/**

src/darwin/Framework/CHIP/MTRDevice.mm

+7-77
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,6 @@
3838
#include <app/InteractionModelEngine.h>
3939
#include <platform/PlatformManager.h>
4040

41-
NSString * const MTREventNumberKey = @"eventNumber";
42-
NSString * const MTREventPriorityKey = @"eventPriority";
43-
NSString * const MTREventTimeTypeKey = @"eventTimeType";
44-
NSString * const MTREventSystemUpTimeKey = @"eventSystemUpTime";
45-
NSString * const MTREventTimestampDateKey = @"eventTimestampDate";
46-
4741
typedef void (^MTRDeviceAttributeReportHandler)(NSArray * _Nonnull);
4842

4943
// Consider moving utility classes to their own file
@@ -89,41 +83,6 @@ - (id)strongObject
8983
return aNumber;
9084
}
9185

92-
NSTimeInterval MTRTimeIntervalForEventTimestampValue(uint64_t timeValue)
93-
{
94-
// Note: The event timestamp value as written in the spec is in microseconds, but the released 1.0 SDK implemented it in
95-
// milliseconds. The following issue was filed to address the inconsistency:
96-
// https://github.com/CHIP-Specifications/connectedhomeip-spec/issues/6236
97-
// For consistency with the released behavior, calculations here will be done in milliseconds.
98-
99-
// First convert the event timestamp value (in milliseconds) to NSTimeInterval - to minimize potential loss of precision
100-
// of uint64 => NSTimeInterval (double), convert whole seconds and remainder separately and then combine
101-
uint64_t eventTimestampValueSeconds = timeValue / chip::kMillisecondsPerSecond;
102-
uint64_t eventTimestampValueRemainderMilliseconds = timeValue % chip::kMillisecondsPerSecond;
103-
NSTimeInterval eventTimestampValueRemainder
104-
= NSTimeInterval(eventTimestampValueRemainderMilliseconds) / chip::kMillisecondsPerSecond;
105-
NSTimeInterval eventTimestampValue = eventTimestampValueSeconds + eventTimestampValueRemainder;
106-
107-
return eventTimestampValue;
108-
}
109-
110-
BOOL MTRPriorityLevelIsValid(chip::app::PriorityLevel priorityLevel)
111-
{
112-
return (priorityLevel >= chip::app::PriorityLevel::Debug) && (priorityLevel <= chip::app::PriorityLevel::Critical);
113-
}
114-
115-
MTREventPriority MTREventPriorityForValidPriorityLevel(chip::app::PriorityLevel priorityLevel)
116-
{
117-
switch (priorityLevel) {
118-
case chip::app::PriorityLevel::Debug:
119-
return MTREventPriorityDebug;
120-
case chip::app::PriorityLevel::Info:
121-
return MTREventPriorityInfo;
122-
default:
123-
return MTREventPriorityCritical;
124-
}
125-
}
126-
12786
#pragma mark - SubscriptionCallback class declaration
12887
using namespace chip;
12988
using namespace chip::app;
@@ -1214,43 +1173,14 @@ - (void)invokeCommandWithEndpointID:(NSNumber *)endpointID
12141173
MTRErrorKey : [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_ARGUMENT]
12151174
}];
12161175
} else {
1217-
id value = MTRDecodeDataValueDictionaryFromCHIPTLV(apData);
1218-
if (value) {
1219-
// Construct the right type, and key/value depending on the type
1220-
NSNumber * eventTimeType;
1221-
NSString * timestampKey;
1222-
id timestampValue;
1223-
if (aEventHeader.mTimestamp.mType == Timestamp::Type::kSystem) {
1224-
eventTimeType = @(MTREventTimeTypeSystemUpTime);
1225-
timestampKey = MTREventSystemUpTimeKey;
1226-
timestampValue = @(MTRTimeIntervalForEventTimestampValue(aEventHeader.mTimestamp.mValue));
1227-
} else if (aEventHeader.mTimestamp.mType == Timestamp::Type::kEpoch) {
1228-
eventTimeType = @(MTREventTimeTypeTimestampDate);
1229-
timestampKey = MTREventTimestampDateKey;
1230-
timestampValue =
1231-
[NSDate dateWithTimeIntervalSince1970:MTRTimeIntervalForEventTimestampValue(aEventHeader.mTimestamp.mValue)];
1232-
} else {
1233-
MTR_LOG_INFO(
1234-
"%@ Unsupported event timestamp type %u - ignoring", eventPath, (unsigned int) aEventHeader.mTimestamp.mType);
1235-
ReportError(CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
1236-
return;
1237-
}
1238-
1239-
if (!MTRPriorityLevelIsValid(aEventHeader.mPriorityLevel)) {
1240-
MTR_LOG_INFO("%@ Unsupported event priority %u - ignoring", eventPath, (unsigned int) aEventHeader.mPriorityLevel);
1241-
ReportError(CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
1242-
return;
1243-
}
1244-
1245-
[mEventReports addObject:@{
1246-
MTREventPathKey : eventPath,
1247-
MTRDataKey : value,
1248-
MTREventNumberKey : @(aEventHeader.mEventNumber),
1249-
MTREventPriorityKey : @(MTREventPriorityForValidPriorityLevel(aEventHeader.mPriorityLevel)),
1250-
MTREventTimeTypeKey : eventTimeType,
1251-
timestampKey : timestampValue
1252-
}];
1176+
id value;
1177+
if (apData == nullptr) {
1178+
value = nil;
1179+
} else {
1180+
value = MTRDecodeDataValueDictionaryFromCHIPTLV(apData);
12531181
}
1182+
1183+
[mEventReports addObject:[MTRBaseDevice eventReportForHeader:aEventHeader andData:value]];
12541184
}
12551185
}
12561186

src/darwin/Framework/CHIP/MTRDevice_Internal.h

-7
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,4 @@ typedef void (^MTRDevicePerformAsyncBlock)(MTRBaseDevice * baseDevice);
5656
// Returns min or max, if it is below or above, respectively.
5757
NSNumber * MTRClampedNumber(NSNumber * aNumber, NSNumber * min, NSNumber * max);
5858

59-
#pragma mark - Utility for time conversion
60-
NSTimeInterval MTRTimeIntervalForEventTimestampValue(uint64_t timeValue);
61-
62-
#pragma mark - Utility for event priority conversion
63-
BOOL MTRPriorityLevelIsValid(chip::app::PriorityLevel priorityLevel);
64-
MTREventPriority MTREventPriorityForValidPriorityLevel(chip::app::PriorityLevel);
65-
6659
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)