-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a Matter.framework API for invoking multiple commands.
The API allows grouping the commands, so that later groups don't get invoked if anything in an earlier group fails.
- Loading branch information
1 parent
e490944
commit a0c93ca
Showing
10 changed files
with
678 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/** | ||
* Copyright (c) 2025 Project CHIP Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#import <Foundation/Foundation.h> | ||
#import <Matter/MTRBaseDevice.h> // For MTRCommandPath | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
/** | ||
* An object representing a single command to be invoked and the expected | ||
* result of invoking it. | ||
*/ | ||
// TODO: Maybe MTRCommandToInvoke? What's a good name here? | ||
MTR_AVAILABLE(ios(18.4), macos(15.4), watchos(11.4), tvos(18.4)) | ||
@interface MTRCommandWithExpectedResult : NSObject <NSCopying, NSSecureCoding> | ||
|
||
/** | ||
* The path of the command being invoked. | ||
*/ | ||
@property (nonatomic, retain) MTRCommandPath * path; | ||
|
||
/** | ||
* The command fields to pass for the command invoke. nil if this command does | ||
* not have any fields. If not nil, this should be a data-value dictionary of | ||
* MTRStructureValueType. | ||
*/ | ||
@property (nonatomic, retain, nullable) NSDictionary<NSString *, id> * commandFields; | ||
|
||
/** | ||
* The expected result of invoking the command. | ||
* | ||
* If this is nil, that indicates that the invoke is considered successful if it | ||
* does not result in an error status response. | ||
* | ||
* If this is is not nil, then invoke is considered successful if | ||
* it results in a data response and for each entry in the provided | ||
* expectedResult the field whose field ID matches the key of the entry has a | ||
* value that equals the value of the entry. Values of entries are data-value | ||
* dictionaries. | ||
*/ | ||
@property (nonatomic, copy, nullable) NSDictionary<NSNumber *, NSDictionary<NSString *, id> *> * expectedResult; | ||
|
||
- (instancetype)initWithPath:(MTRCommandPath *)path | ||
commandFields:(nullable NSDictionary<NSString *, id> *)commandFields | ||
expectedResult:(nullable NSDictionary<NSNumber *, NSDictionary<NSString *, id> *> *)expectedResult; | ||
|
||
@end | ||
|
||
NS_ASSUME_NONNULL_END |
119 changes: 119 additions & 0 deletions
119
src/darwin/Framework/CHIP/MTRCommandWithExpectedResult.mm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/** | ||
* Copyright (c) 2025 Project CHIP Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#import "MTRDeviceDataValidation.h" | ||
#import "MTRLogging_Internal.h" | ||
#import <Matter/Matter.h> | ||
|
||
@implementation MTRCommandWithExpectedResult | ||
- (instancetype)initWithPath:(MTRCommandPath *)path | ||
commandFields:(nullable NSDictionary<NSString *, id> *)commandFields | ||
expectedResult:(nullable NSDictionary<NSNumber *, NSDictionary<NSString *, id> *> *)expectedResult | ||
{ | ||
if (self = [super init]) { | ||
self.path = path; | ||
self.commandFields = commandFields; | ||
self.expectedResult = expectedResult; | ||
} | ||
|
||
return self; | ||
} | ||
|
||
- (id)copyWithZone:(NSZone *)zone | ||
{ | ||
return [[MTRCommandWithExpectedResult alloc] initWithPath:self.path commandFields:self.commandFields expectedResult:self.expectedResult]; | ||
} | ||
|
||
- (NSString *)description | ||
{ | ||
return [NSString stringWithFormat:@"<%@: %p, path: %@, fields: %@, expectedResult: %@", NSStringFromClass(self.class), self, self.path, self.commandFields, self.expectedResult]; | ||
} | ||
|
||
#pragma mark - MTRCommandWithExpectedResult NSSecureCoding implementation | ||
|
||
static NSString * const sPathKey = @"pathKey"; | ||
static NSString * const sFieldsKey = @"fieldsKey"; | ||
static NSString * const sExpectedResultKey = @"expectedResultKey"; | ||
|
||
+ (BOOL)supportsSecureCoding | ||
{ | ||
return YES; | ||
} | ||
|
||
- (nullable instancetype)initWithCoder:(NSCoder *)decoder | ||
{ | ||
self = [super init]; | ||
if (self == nil) { | ||
return nil; | ||
} | ||
|
||
_path = [decoder decodeObjectOfClass:MTRCommandPath.class forKey:sPathKey]; | ||
if (!_path || ![_path isKindOfClass:MTRCommandPath.class]) { | ||
MTR_LOG_ERROR("MTRCommandWithExpectedResult decoded %@ for endpoint, not MTRCommandPath.", _path); | ||
return nil; | ||
} | ||
|
||
_commandFields = [decoder decodeObjectOfClass:NSDictionary.class forKey:sFieldsKey]; | ||
if (_commandFields) { | ||
if (![_commandFields isKindOfClass:NSDictionary.class]) { | ||
MTR_LOG_ERROR("MTRCommandWithExpectedResult decoded %@ for commandFields, not NSDictionary.", _commandFields); | ||
return nil; | ||
} | ||
|
||
if (!MTRDataValueDictionaryIsWellFormed(_commandFields) || ![MTRStructureValueType isEqual:_commandFields[MTRTypeKey]]) { | ||
MTR_LOG_ERROR("MTRCommandWithExpectedResult decoded %@ for commandFields, not a structure-typed data-value dictionary.", _commandFields); | ||
return nil; | ||
} | ||
} | ||
|
||
_expectedResult = [decoder decodeObjectOfClass:NSDictionary.class forKey:sExpectedResultKey]; | ||
if (_expectedResult) { | ||
if (![_expectedResult isKindOfClass:NSDictionary.class]) { | ||
MTR_LOG_ERROR("MTRCommandWithExpectedResult decoded %@ for expectedResult, not NSDictionary.", _expectedResult); | ||
return nil; | ||
} | ||
|
||
for (id key in _expectedResult) { | ||
if (![key isKindOfClass:NSNumber.class]) { | ||
MTR_LOG_ERROR("MTRCommandWithExpectedResult decoded key %@ in expectedResult", key); | ||
return nil; | ||
} | ||
|
||
if (![_expectedResult[key] isKindOfClass:NSDictionary.class] || !MTRDataValueDictionaryIsWellFormed(_expectedResult[key])) { | ||
MTR_LOG_ERROR("MTRCommandWithExpectedResult decoded value %@ for key %@ in expectedResult", _expectedResult[key], key); | ||
return nil; | ||
} | ||
} | ||
} | ||
|
||
return self; | ||
} | ||
|
||
- (void)encodeWithCoder:(NSCoder *)coder | ||
{ | ||
// In theory path is not nullable, but we don't really enforce that in init. | ||
if (self.path) { | ||
[coder encodeObject:self.path forKey:sPathKey]; | ||
} | ||
if (self.commandFields) { | ||
[coder encodeObject:self.commandFields forKey:sFieldsKey]; | ||
} | ||
if (self.expectedResult) { | ||
[coder encodeObject:self.expectedResult forKey:sExpectedResultKey]; | ||
} | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.