diff --git a/src/darwin/Framework/CHIP/CHIPAttributeCacheContainer.h b/src/darwin/Framework/CHIP/CHIPAttributeCacheContainer.h index 28d6476f3bb379..2c72c24cf65f2b 100644 --- a/src/darwin/Framework/CHIP/CHIPAttributeCacheContainer.h +++ b/src/darwin/Framework/CHIP/CHIPAttributeCacheContainer.h @@ -21,6 +21,8 @@ NS_ASSUME_NONNULL_BEGIN +@class CHIPSubscribeParams; + @interface CHIPAttributeCacheContainer : NSObject /** @@ -28,11 +30,13 @@ NS_ASSUME_NONNULL_BEGIN * * @param deviceController device controller to retrieve connected device from * @param deviceId device identifier of the device to cache attributes of + * @param params subscription parameters * @param clientQueue client queue to dispatch the completion handler through * @param completion completion handler */ - (void)subscribeWithDeviceController:(CHIPDeviceController *)deviceController deviceId:(uint64_t)deviceId + params:(CHIPSubscribeParams * _Nullable)params clientQueue:(dispatch_queue_t)clientQueue completion:(void (^)(NSError * _Nullable error))completion; @@ -47,9 +51,9 @@ NS_ASSUME_NONNULL_BEGIN * "values" received by the block will have the same format of object as the one received by completion block * of CHIPDevice readAttributeWithEndpointId:clusterId:attributeId:clientQueue:completion method. */ -- (void)readAttributeWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId +- (void)readAttributeWithEndpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId clientQueue:(dispatch_queue_t)clientQueue completion:(void (^)(NSArray *> * _Nullable values, NSError * _Nullable error))completion; diff --git a/src/darwin/Framework/CHIP/CHIPAttributeCacheContainer.mm b/src/darwin/Framework/CHIP/CHIPAttributeCacheContainer.mm index 32d9c97be8b776..59c7ec701ff051 100644 --- a/src/darwin/Framework/CHIP/CHIPAttributeCacheContainer.mm +++ b/src/darwin/Framework/CHIP/CHIPAttributeCacheContainer.mm @@ -18,6 +18,7 @@ #import #import "CHIPAttributeCacheContainer_Internal.h" +#import "CHIPCluster.h" #import "CHIPDeviceControllerOverXPC+AttributeCache.h" #import "CHIPDevice_Internal.h" #import "CHIPError.h" @@ -80,6 +81,7 @@ - (void)dealloc - (void)subscribeWithDeviceController:(CHIPDeviceController *)deviceController deviceId:(uint64_t)deviceId + params:(CHIPSubscribeParams * _Nullable)params clientQueue:clientQueue completion:(void (^)(NSError * _Nullable error))completion { @@ -93,7 +95,7 @@ - (void)subscribeWithDeviceController:(CHIPDeviceController *)deviceController self.deviceId = deviceId; CHIPDeviceControllerOverXPC * xpcDeviceController = (CHIPDeviceControllerOverXPC *) deviceController; self.xpcDeviceController = xpcDeviceController; - [xpcDeviceController subscribeAttributeCacheWithNodeId:deviceId completion:completionHandler]; + [xpcDeviceController subscribeAttributeCacheWithNodeId:deviceId params:params completion:completionHandler]; return; } [deviceController @@ -129,10 +131,13 @@ - (void)subscribeWithDeviceController:(CHIPDeviceController *)deviceController } self.deviceId = deviceId; app::ReadPrepareParams readParams([device internalDevice]->GetSecureSession().Value()); - static app::AttributePathParams attributePath(kInvalidEndpointId, kInvalidClusterId, kInvalidAttributeId); + static app::AttributePathParams attributePath; readParams.mpAttributePathParamsList = &attributePath; readParams.mAttributePathParamsListSize = 1; readParams.mMaxIntervalCeilingSeconds = 43200; + readParams.mIsFabricFiltered = (params == nil || params.fabricFiltered == nil || [params.fabricFiltered boolValue]); + readParams.mKeepSubscriptions + = (params != nil && params.keepPreviousSubscriptions != nil && [params.keepPreviousSubscriptions boolValue]); __auto_type err = readClient->SendAutoResubscribeRequest(std::move(readParams)); if (err != CHIP_NO_ERROR) { CHIP_LOG_ERROR("Error: attribute cache subscription failed for device %llu: %s", deviceId, ErrorStr(err)); @@ -171,9 +176,9 @@ static CHIP_ERROR AppendAttibuteValueToArray( return err; } -- (void)readAttributeWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId +- (void)readAttributeWithEndpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId clientQueue:(dispatch_queue_t)clientQueue completion:(void (^)(NSArray *> * _Nullable values, NSError * _Nullable error))completion @@ -200,7 +205,7 @@ - (void)readAttributeWithEndpointId:(NSUInteger)endpointId return; } dispatch_async(DeviceLayer::PlatformMgrImpl().GetWorkQueue(), ^{ - if (endpointId == chip::kInvalidEndpointId && clusterId == chip::kInvalidClusterId) { + if (endpointId == nil && clusterId == nil) { CHIP_LOG_ERROR("Error: currently read from attribute cache does not support wildcards for both endpoint and cluster"); completionHandler(nil, [NSError errorWithDomain:CHIPErrorDomain code:CHIPErrorCodeInvalidArgument userInfo:nil]); return; @@ -214,38 +219,39 @@ - (void)readAttributeWithEndpointId:(NSUInteger)endpointId NSMutableArray * result = [[NSMutableArray alloc] init]; CHIP_ERROR err = CHIP_NO_ERROR; - if (endpointId == chip::kInvalidEndpointId) { + if (endpointId == nil) { err = self.cppAttributeCache->ForEachAttribute( - static_cast(clusterId), [&](const app::ConcreteAttributePath & path) { - if (static_cast(attributeId) == chip::kInvalidAttributeId - || static_cast(attributeId) == path.mAttributeId) { + static_cast([clusterId unsignedLongValue]), [&](const app::ConcreteAttributePath & path) { + if (attributeId == nil + || static_cast([attributeId unsignedLongValue]) == path.mAttributeId) { (void) AppendAttibuteValueToArray(path, self.cppAttributeCache, result); } return CHIP_NO_ERROR; }); - } else if (clusterId == chip::kInvalidClusterId) { - err = self.cppAttributeCache->ForEachCluster(static_cast(endpointId), [&](chip::ClusterId clusterId) { - (void) self.cppAttributeCache->ForEachAttribute( - static_cast(endpointId), clusterId, [&](const app::ConcreteAttributePath & path) { - if (static_cast(attributeId) == chip::kInvalidAttributeId - || static_cast(attributeId) == path.mAttributeId) { - (void) AppendAttibuteValueToArray(path, self.cppAttributeCache, result); - } - return CHIP_NO_ERROR; - }); - return CHIP_NO_ERROR; - }); - } else if (attributeId == chip::kInvalidAttributeId) { - err = self.cppAttributeCache->ForEachAttribute(static_cast(endpointId), - static_cast(clusterId), [&](const app::ConcreteAttributePath & path) { + } else if (clusterId == nil) { + err = self.cppAttributeCache->ForEachCluster( + static_cast([endpointId unsignedShortValue]), [&](chip::ClusterId enumeratedClusterId) { + (void) self.cppAttributeCache->ForEachAttribute(static_cast([endpointId unsignedShortValue]), + enumeratedClusterId, [&](const app::ConcreteAttributePath & path) { + if (attributeId == nil + || static_cast([attributeId unsignedLongValue]) == path.mAttributeId) { + (void) AppendAttibuteValueToArray(path, self.cppAttributeCache, result); + } + return CHIP_NO_ERROR; + }); + return CHIP_NO_ERROR; + }); + } else if (attributeId == nil) { + err = self.cppAttributeCache->ForEachAttribute(static_cast([endpointId unsignedShortValue]), + static_cast([clusterId unsignedLongValue]), [&](const app::ConcreteAttributePath & path) { (void) AppendAttibuteValueToArray(path, self.cppAttributeCache, result); return CHIP_NO_ERROR; }); } else { app::ConcreteAttributePath path; - path.mEndpointId = static_cast(endpointId); - path.mClusterId = static_cast(clusterId); - path.mAttributeId = static_cast(attributeId); + path.mEndpointId = static_cast([endpointId unsignedShortValue]); + path.mClusterId = static_cast([clusterId unsignedLongValue]); + path.mAttributeId = static_cast([attributeId unsignedLongValue]); err = AppendAttibuteValueToArray(path, self.cppAttributeCache, result); } if (err == CHIP_NO_ERROR) { diff --git a/src/darwin/Framework/CHIP/CHIPDevice.h b/src/darwin/Framework/CHIP/CHIPDevice.h index 74ba8bbf67bded..eac211d1593ba8 100644 --- a/src/darwin/Framework/CHIP/CHIPDevice.h +++ b/src/darwin/Framework/CHIP/CHIPDevice.h @@ -20,8 +20,6 @@ #import -@class CHIPSubscribeParams; - NS_ASSUME_NONNULL_BEGIN /** @@ -91,6 +89,9 @@ extern NSString * const kCHIPNullValueType; extern NSString * const kCHIPStructureValueType; extern NSString * const kCHIPArrayValueType; +@class CHIPReadParams; +@class CHIPSubscribeParams; + @interface CHIPDevice : NSObject - (instancetype)init NS_UNAVAILABLE; @@ -126,9 +127,10 @@ extern NSString * const kCHIPArrayValueType; /** * Read attribute in a designated attribute path */ -- (void)readAttributeWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId +- (void)readAttributeWithEndpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId + params:(CHIPReadParams * _Nullable)params clientQueue:(dispatch_queue_t)clientQueue completion:(CHIPDeviceResponseHandler)completion; @@ -137,11 +139,19 @@ extern NSString * const kCHIPArrayValueType; * * @param value A data-value NSDictionary object as described in * CHIPDeviceResponseHandler. + * + * @param timeoutMs timeout in milliseconds for timed write, or nil. + * + * @param completion response handler will receive either values or error. + * + * Received values are an NSArray object with response-value element as described in + * readAttributeWithEndpointId:clusterId:attributeId:clientQueue:completion:. */ -- (void)writeAttributeWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId +- (void)writeAttributeWithEndpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + attributeId:(NSNumber *)attributeId value:(id)value + timedWriteTimeout:(NSNumber * _Nullable)timeoutMs clientQueue:(dispatch_queue_t)clientQueue completion:(CHIPDeviceResponseHandler)completion; @@ -152,22 +162,28 @@ extern NSString * const kCHIPArrayValueType; * as described in the CHIPDeviceResponseHandler. * The attribute must be a Structure, i.e., * the NSDictionary kCHIPTypeKey key must have the value kCHIPStructureValueType. + * + * @param timeoutMs timeout in milliseconds for timed invoke, or nil. + * + * @param completion response handler will receive either values or error. */ -- (void)invokeCommandWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - commandId:(NSUInteger)commandId +- (void)invokeCommandWithEndpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + commandId:(NSNumber *)commandId commandFields:(id)commandFields + timedInvokeTimeout:(NSNumber * _Nullable)timeoutMs clientQueue:(dispatch_queue_t)clientQueue completion:(CHIPDeviceResponseHandler)completion; /** * Subscribe an attribute in a designated attribute path */ -- (void)subscribeAttributeWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId - minInterval:(NSUInteger)minInterval - maxInterval:(NSUInteger)maxInterval +- (void)subscribeAttributeWithEndpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId + minInterval:(NSNumber *)minInterval + maxInterval:(NSNumber *)maxInterval + params:(CHIPSubscribeParams * _Nullable)params clientQueue:(dispatch_queue_t)clientQueue reportHandler:(CHIPDeviceResponseHandler)reportHandler subscriptionEstablished:(nullable void (^)(void))subscriptionEstablishedHandler; diff --git a/src/darwin/Framework/CHIP/CHIPDevice.mm b/src/darwin/Framework/CHIP/CHIPDevice.mm index 614a0f3235e20f..9528022aadea4f 100644 --- a/src/darwin/Framework/CHIP/CHIPDevice.mm +++ b/src/darwin/Framework/CHIP/CHIPDevice.mm @@ -17,6 +17,7 @@ #import "CHIPAttributeTLVValueDecoder_Internal.h" #import "CHIPCallbackBridgeBase_internal.h" +#import "CHIPCluster.h" #import "CHIPDevice_Internal.h" #import "CHIPError_Internal.h" #import "CHIPLogging.h" @@ -717,9 +718,10 @@ void OnDeallocatePaths(chip::app::ReadPrepareParams && aReadPrepareParams) overr Platform::UniquePtr mReadClient; }; -- (void)readAttributeWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId +- (void)readAttributeWithEndpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + attributeId:(NSNumber *)attributeId + params:(CHIPReadParams * _Nullable)params clientQueue:(dispatch_queue_t)clientQueue completion:(CHIPDeviceResponseHandler)completion { @@ -755,17 +757,23 @@ new NSObjectDataValueCallbackBridge( } }; - auto chipEndpointId = static_cast(endpointId); - auto chipClusterId = static_cast(clusterId); - auto chipAttributeId = static_cast(attributeId); - - app::AttributePathParams attributePath(chipEndpointId, chipClusterId, chipAttributeId); + app::AttributePathParams attributePath; + if (endpointId) { + attributePath.mEndpointId = static_cast([endpointId unsignedShortValue]); + } + if (clusterId) { + attributePath.mClusterId = static_cast([clusterId unsignedLongValue]); + } + if (attributeId) { + attributePath.mAttributeId = static_cast([attributeId unsignedLongValue]); + } app::InteractionModelEngine * engine = app::InteractionModelEngine::GetInstance(); CHIP_ERROR err = CHIP_NO_ERROR; chip::app::ReadPrepareParams readParams([self internalDevice]->GetSecureSession().Value()); readParams.mpAttributePathParamsList = &attributePath; readParams.mAttributePathParamsListSize = 1; + readParams.mIsFabricFiltered = params == nil || params.fabricFiltered == nil || [params.fabricFiltered boolValue]; auto onDone = [resultArray, resultSuccess, resultFailure, context, successCb, failureCb]( BufferedReadAttributeCallback * callback) { @@ -790,7 +798,7 @@ new NSObjectDataValueCallbackBridge( }; auto callback = chip::Platform::MakeUnique>( - chipClusterId, chipAttributeId, onSuccessCb, onFailureCb, onDone, nullptr); + attributePath.mClusterId, attributePath.mAttributeId, onSuccessCb, onFailureCb, onDone, nullptr); VerifyOrReturnError(callback != nullptr, CHIP_ERROR_NO_MEMORY); auto readClient = chip::Platform::MakeUnique(engine, [self internalDevice]->GetExchangeManager(), @@ -814,10 +822,11 @@ new NSObjectDataValueCallbackBridge( }); } -- (void)writeAttributeWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId +- (void)writeAttributeWithEndpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + attributeId:(NSNumber *)attributeId value:(id)value + timedWriteTimeout:(NSNumber * _Nullable)timeoutMs clientQueue:(dispatch_queue_t)clientQueue completion:(CHIPDeviceResponseHandler)completion { @@ -873,9 +882,10 @@ new NSObjectDataValueCallbackBridge( }; return chip::Controller::WriteAttribute([self internalDevice]->GetSecureSession().Value(), - static_cast(endpointId), static_cast(clusterId), - static_cast(attributeId), NSObjectData(value), onSuccessCb, onFailureCb, NullOptional, onDoneCb, - NullOptional); + static_cast([endpointId unsignedShortValue]), + static_cast([clusterId unsignedLongValue]), + static_cast([attributeId unsignedLongValue]), NSObjectData(value), onSuccessCb, onFailureCb, + (timeoutMs == nil) ? NullOptional : Optional([timeoutMs unsignedShortValue]), onDoneCb, NullOptional); }); } @@ -944,10 +954,11 @@ void OnResponse(app::CommandSender * apCommandSender, const app::ConcreteCommand } } -- (void)invokeCommandWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - commandId:(NSUInteger)commandId +- (void)invokeCommandWithEndpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + commandId:(NSNumber *)commandId commandFields:(id)commandFields + timedInvokeTimeout:(NSNumber * _Nullable)timeoutMs clientQueue:(dispatch_queue_t)clientQueue completion:(CHIPDeviceResponseHandler)completion { @@ -982,8 +993,9 @@ new NSObjectDataValueCallbackBridge( } }; - app::CommandPathParams commandPath = { (chip::EndpointId) endpointId, 0, (chip::ClusterId) clusterId, - (chip::CommandId) commandId, (app::CommandPathFlags::kEndpointIdValid) }; + app::CommandPathParams commandPath = { static_cast([endpointId unsignedShortValue]), 0, + static_cast([clusterId unsignedLongValue]), + static_cast([commandId unsignedLongValue]), (app::CommandPathFlags::kEndpointIdValid) }; auto decoder = chip::Platform::MakeUnique( commandPath.mClusterId, commandPath.mCommandId, onSuccessCb, onFailureCb); @@ -1017,7 +1029,8 @@ new NSObjectDataValueCallbackBridge( = chip::Platform::MakeUnique(decoder.get(), [self internalDevice]->GetExchangeManager(), false); VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_NO_MEMORY); - ReturnErrorOnFailure(commandSender->AddRequestData(commandPath, NSObjectData(commandFields), chip::NullOptional)); + ReturnErrorOnFailure(commandSender->AddRequestData(commandPath, NSObjectData(commandFields), + (timeoutMs == nil) ? NullOptional : Optional([timeoutMs unsignedShortValue]))); ReturnErrorOnFailure(commandSender->SendCommandRequest([self internalDevice]->GetSecureSession().Value())); decoder.release(); @@ -1026,11 +1039,12 @@ new NSObjectDataValueCallbackBridge( }); } -- (void)subscribeAttributeWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId - minInterval:(NSUInteger)minInterval - maxInterval:(NSUInteger)maxInterval +- (void)subscribeAttributeWithEndpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId + minInterval:(NSNumber *)minInterval + maxInterval:(NSNumber *)maxInterval + params:(CHIPSubscribeParams * _Nullable)params clientQueue:(dispatch_queue_t)clientQueue reportHandler:(CHIPDeviceResponseHandler)reportHandler subscriptionEstablished:(SubscriptionEstablishedHandler)subscriptionEstablishedHandler @@ -1074,13 +1088,18 @@ - (void)subscribeAttributeWithEndpointId:(NSUInteger)endpointId } }; - auto chipEndpointId = static_cast(endpointId); - auto chipClusterId = static_cast(clusterId); - auto chipAttributeId = static_cast(attributeId); - CHIPReadClientContainer * container = [[CHIPReadClientContainer alloc] init]; container.deviceId = self.cppDevice->GetDeviceId(); - container.pathParams = Platform::New(chipEndpointId, chipClusterId, chipAttributeId); + container.pathParams = Platform::New(); + if (endpointId) { + container.pathParams->mEndpointId = static_cast([endpointId unsignedShortValue]); + } + if (clusterId) { + container.pathParams->mClusterId = static_cast([clusterId unsignedLongValue]); + } + if (attributeId) { + container.pathParams->mAttributeId = static_cast([attributeId unsignedLongValue]); + } app::InteractionModelEngine * engine = app::InteractionModelEngine::GetInstance(); CHIP_ERROR err = CHIP_NO_ERROR; @@ -1088,6 +1107,11 @@ - (void)subscribeAttributeWithEndpointId:(NSUInteger)endpointId chip::app::ReadPrepareParams readParams([self internalDevice]->GetSecureSession().Value()); readParams.mpAttributePathParamsList = container.pathParams; readParams.mAttributePathParamsListSize = 1; + readParams.mMinIntervalFloorSeconds = static_cast([minInterval unsignedShortValue]); + readParams.mMaxIntervalCeilingSeconds = static_cast([maxInterval unsignedShortValue]); + readParams.mIsFabricFiltered = (params == nil || params.fabricFiltered == nil || [params.fabricFiltered boolValue]); + readParams.mKeepSubscriptions + = (params != nil && params.keepPreviousSubscriptions != nil && [params.keepPreviousSubscriptions boolValue]); auto onDone = [container](BufferedReadAttributeCallback * callback) { chip::Platform::Delete(callback); @@ -1095,7 +1119,7 @@ - (void)subscribeAttributeWithEndpointId:(NSUInteger)endpointId }; auto callback = chip::Platform::MakeUnique>( - chipClusterId, chipAttributeId, onReportCb, onFailureCb, onDone, onEstablishedCb); + container.pathParams->mClusterId, container.pathParams->mAttributeId, onReportCb, onFailureCb, onDone, onEstablishedCb); auto readClient = Platform::New(engine, [self internalDevice]->GetExchangeManager(), callback -> GetBufferedCallback(), chip::app::ReadClient::InteractionType::Subscribe); diff --git a/src/darwin/Framework/CHIP/CHIPDeviceController+XPC.h b/src/darwin/Framework/CHIP/CHIPDeviceController+XPC.h index 58b2ff738da1e7..8bb366ba99235f 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceController+XPC.h +++ b/src/darwin/Framework/CHIP/CHIPDeviceController+XPC.h @@ -17,6 +17,7 @@ #import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -47,6 +48,26 @@ NS_ASSUME_NONNULL_BEGIN + (NSArray *> * _Nullable)decodeXPCResponseValues: (NSArray *> * _Nullable)values; +/** + * Returns a serialized read parameter object to send over XPC + */ ++ (NSDictionary * _Nullable)encodeXPCReadParams:(CHIPReadParams *)params; + +/** + * Returns a deserialized read parameter object from an object received over XPC + */ ++ (CHIPReadParams * _Nullable)decodeXPCReadParams:(NSDictionary * _Nullable)params; + +/** + * Returns a serialized subscribe parameter object to send over XPC + */ ++ (NSDictionary * _Nullable)encodeXPCSubscribeParams:(CHIPSubscribeParams *)params; + +/** + * Returns a deserialized subscribe parameter object from an object received over XPC + */ ++ (CHIPSubscribeParams * _Nullable)decodeXPCSubscribeParams:(NSDictionary * _Nullable)params; + @end /** * Protocol that remote object must support over XPC @@ -69,9 +90,10 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)readAttributeWithController:(id _Nullable)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId + endpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId + params:(NSDictionary * _Nullable)params completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion; /** @@ -79,10 +101,11 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)writeAttributeWithController:(id _Nullable)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId + endpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + attributeId:(NSNumber *)attributeId value:(id)value + timedWriteTimeout:(NSNumber * _Nullable)timeoutMs completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion; /** @@ -90,10 +113,11 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)invokeCommandWithController:(id _Nullable)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - commandId:(NSUInteger)commandId + endpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + commandId:(NSNumber *)commandId fields:(id)fields + timedInvokeTimeout:(NSNumber * _Nullable)timeoutMs completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion; /** @@ -101,18 +125,25 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)subscribeAttributeWithController:(id _Nullable)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId - minInterval:(NSUInteger)minInterval - maxInterval:(NSUInteger)maxInterval + endpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId + minInterval:(NSNumber *)minInterval + maxInterval:(NSNumber *)maxInterval + params:(NSDictionary * _Nullable)params establishedHandler:(void (^)(void))establishedHandler; +/** + * Requests to stop reporting + */ +- (void)stopReportsWithController:(id _Nullable)controller nodeId:(uint64_t)nodeId completion:(void (^)(void))completion; + /** * Requests a specific node attribute subscription into a cache */ - (void)subscribeAttributeCacheWithController:(id _Nullable)controller nodeId:(uint64_t)nodeId + params:(NSDictionary * _Nullable)params completion:(void (^)(NSError * _Nullable error))completion; /** @@ -120,9 +151,9 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)readAttributeCacheWithController:(id _Nullable)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId + endpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion; @end diff --git a/src/darwin/Framework/CHIP/CHIPDeviceController+XPC.m b/src/darwin/Framework/CHIP/CHIPDeviceController+XPC.m index 4c07d98846ded8..57e9135eebb08f 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceController+XPC.m +++ b/src/darwin/Framework/CHIP/CHIPDeviceController+XPC.m @@ -17,12 +17,17 @@ #import "CHIPDeviceController+XPC.h" +#import "CHIPCluster.h" #import "CHIPDevice.h" #import "CHIPDeviceControllerOverXPC.h" NS_ASSUME_NONNULL_BEGIN -static NSArray * _Nullable serializeAttributePath(CHIPAttributePath * _Nullable path) +static NSString * const kFabricFilteredKey = @"fabricFiltered"; +static NSString * const kKeepPreviousSubscriptionsKey = @"keepPreviousSubscriptions"; +static NSString * const kAutoResubscribeKey = @"autoResubscribe"; + +static NSArray * _Nullable encodeAttributePath(CHIPAttributePath * _Nullable path) { if (!path) { return nil; @@ -30,7 +35,7 @@ return @[ path.endpoint, path.cluster, path.attribute ]; } -static NSArray * _Nullable serializeCommandPath(CHIPCommandPath * _Nullable path) +static NSArray * _Nullable encodeCommandPath(CHIPCommandPath * _Nullable path) { if (!path) { return nil; @@ -38,7 +43,7 @@ return @[ path.endpoint, path.cluster, path.command ]; } -static CHIPAttributePath * _Nullable deserializeAttributePath(NSArray * _Nullable pathArray) +static CHIPAttributePath * _Nullable decodeAttributePath(NSArray * _Nullable pathArray) { if (pathArray == nil || [pathArray count] != 3) { return nil; @@ -46,7 +51,7 @@ return [CHIPAttributePath attributePathWithEndpointId:pathArray[0] clusterId:pathArray[1] attributeId:pathArray[2]]; } -static CHIPCommandPath * _Nullable deserializeCommandPath(NSArray * _Nullable pathArray) +static CHIPCommandPath * _Nullable decodeCommandPath(NSArray * _Nullable pathArray) { if (pathArray == nil || [pathArray count] != 3) { return nil; @@ -54,6 +59,11 @@ return [CHIPCommandPath commandPathWithEndpointId:pathArray[0] clusterId:pathArray[1] commandId:pathArray[2]]; } +static void decodeReadParams(NSDictionary * inParams, CHIPReadParams * outParams) +{ + outParams.fabricFiltered = inParams[kFabricFilteredKey]; +} + @implementation CHIPDeviceController (XPC) + (CHIPDeviceController *)sharedControllerWithId:(id _Nullable)controllerId @@ -77,10 +87,10 @@ + (CHIPDeviceController *)sharedControllerWithId:(id _Nullable)contro NSMutableDictionary * resultValue = [NSMutableDictionary dictionaryWithCapacity:[value count]]; [resultValue addEntriesFromDictionary:value]; if (value[kCHIPAttributePathKey]) { - resultValue[kCHIPAttributePathKey] = serializeAttributePath(value[kCHIPAttributePathKey]); + resultValue[kCHIPAttributePathKey] = encodeAttributePath(value[kCHIPAttributePathKey]); } if (value[kCHIPCommandPathKey]) { - resultValue[kCHIPCommandPathKey] = serializeCommandPath(value[kCHIPCommandPathKey]); + resultValue[kCHIPCommandPathKey] = encodeCommandPath(value[kCHIPCommandPathKey]); } [result addObject:resultValue]; } @@ -101,16 +111,66 @@ + (CHIPDeviceController *)sharedControllerWithId:(id _Nullable)contro NSMutableDictionary * resultValue = [NSMutableDictionary dictionaryWithCapacity:[value count]]; [resultValue addEntriesFromDictionary:value]; if (value[kCHIPAttributePathKey]) { - resultValue[kCHIPAttributePathKey] = deserializeAttributePath(value[kCHIPAttributePathKey]); + resultValue[kCHIPAttributePathKey] = decodeAttributePath(value[kCHIPAttributePathKey]); } if (value[kCHIPCommandPathKey]) { - resultValue[kCHIPCommandPathKey] = deserializeCommandPath(value[kCHIPCommandPathKey]); + resultValue[kCHIPCommandPathKey] = decodeCommandPath(value[kCHIPCommandPathKey]); } [result addObject:resultValue]; } return result; } ++ (NSDictionary * _Nullable)encodeXPCReadParams:(CHIPReadParams *)params +{ + if (!params) { + return nil; + } + NSMutableDictionary * result = [NSMutableDictionary dictionary]; + if (params.fabricFiltered) { + result[kFabricFilteredKey] = params.fabricFiltered; + } + return result; +} + ++ (CHIPReadParams * _Nullable)decodeXPCReadParams:(NSDictionary * _Nullable)params +{ + if (!params) { + return nil; + } + CHIPReadParams * result = [[CHIPReadParams alloc] init]; + decodeReadParams(params, result); + return result; +} + ++ (NSDictionary * _Nullable)encodeXPCSubscribeParams:(CHIPSubscribeParams *)params +{ + if (!params) { + return nil; + } + NSMutableDictionary * result = + [NSMutableDictionary dictionaryWithDictionary:[CHIPDeviceController encodeXPCReadParams:params]]; + if (params.keepPreviousSubscriptions) { + result[kKeepPreviousSubscriptionsKey] = params.keepPreviousSubscriptions; + } + if (params.autoResubscribe) { + result[kAutoResubscribeKey] = params.autoResubscribe; + } + return result; +} + ++ (CHIPSubscribeParams * _Nullable)decodeXPCSubscribeParams:(NSDictionary * _Nullable)params +{ + if (!params) { + return nil; + } + CHIPSubscribeParams * result = [[CHIPSubscribeParams alloc] init]; + decodeReadParams(params, result); + result.keepPreviousSubscriptions = params[kKeepPreviousSubscriptionsKey]; + result.autoResubscribe = params[kAutoResubscribeKey]; + return result; +} + @end NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/CHIPDeviceControllerOverXPC+AttributeCache.h b/src/darwin/Framework/CHIP/CHIPDeviceControllerOverXPC+AttributeCache.h index cd24f1134765b6..407bb9d4404dc3 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceControllerOverXPC+AttributeCache.h +++ b/src/darwin/Framework/CHIP/CHIPDeviceControllerOverXPC+AttributeCache.h @@ -21,14 +21,18 @@ NS_ASSUME_NONNULL_BEGIN +@class CHIPSubscribeParams; + @interface CHIPDeviceControllerOverXPC (AttributeCache) -- (void)subscribeAttributeCacheWithNodeId:(uint64_t)nodeId completion:(void (^)(NSError * _Nullable error))completion; +- (void)subscribeAttributeCacheWithNodeId:(uint64_t)nodeId + params:(CHIPSubscribeParams * _Nullable)params + completion:(void (^)(NSError * _Nullable error))completion; - (void)readAttributeCacheWithNodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId + endpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion; @end diff --git a/src/darwin/Framework/CHIP/CHIPDeviceControllerOverXPC+AttributeCache.m b/src/darwin/Framework/CHIP/CHIPDeviceControllerOverXPC+AttributeCache.m index 34cab94731bb4f..7ea55db94246b5 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceControllerOverXPC+AttributeCache.m +++ b/src/darwin/Framework/CHIP/CHIPDeviceControllerOverXPC+AttributeCache.m @@ -24,7 +24,9 @@ @implementation CHIPDeviceControllerOverXPC (AttributeCache) -- (void)subscribeAttributeCacheWithNodeId:(uint64_t)nodeId completion:(void (^)(NSError * _Nullable error))completion +- (void)subscribeAttributeCacheWithNodeId:(uint64_t)nodeId + params:(CHIPSubscribeParams * _Nullable)params + completion:(void (^)(NSError * _Nullable error))completion { dispatch_async(self.workQueue, ^{ dispatch_group_t group = dispatch_group_create(); @@ -56,6 +58,7 @@ - (void)subscribeAttributeCacheWithNodeId:(uint64_t)nodeId completion:(void (^)( if (handle) { [handle.proxy subscribeAttributeCacheWithController:self.controllerId nodeId:nodeId + params:[CHIPDeviceController encodeXPCSubscribeParams:params] completion:^(NSError * _Nullable error) { if (error) { CHIP_LOG_ERROR("Attribute cache subscription for " @@ -84,9 +87,9 @@ - (void)subscribeAttributeCacheWithNodeId:(uint64_t)nodeId completion:(void (^)( } - (void)readAttributeCacheWithNodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId + endpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion { dispatch_async(self.workQueue, ^{ diff --git a/src/darwin/Framework/CHIP/CHIPDeviceControllerXPCConnection.m b/src/darwin/Framework/CHIP/CHIPDeviceControllerXPCConnection.m index 0082cd82d614d3..2bcc28e9c1c6cf 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceControllerXPCConnection.m +++ b/src/darwin/Framework/CHIP/CHIPDeviceControllerXPCConnection.m @@ -148,23 +148,41 @@ - (void)deregisterReportHandlersWithController:(id)controller completion:(void (^)(void))completion { dispatch_async(_workQueue, ^{ - NSMutableDictionary * controllerDictionary = self.reportRegistry[controller]; - if (!controllerDictionary) { - completion(); - return; - } - NSNumber * nodeIdKey = [NSNumber numberWithUnsignedInteger:nodeId]; - NSMutableArray * nodeArray = controllerDictionary[nodeIdKey]; - if (!nodeArray) { + __auto_type clearRegistry = ^{ + NSMutableDictionary * controllerDictionary = self.reportRegistry[controller]; + if (!controllerDictionary) { + completion(); + return; + } + NSNumber * nodeIdKey = [NSNumber numberWithUnsignedInteger:nodeId]; + NSMutableArray * nodeArray = controllerDictionary[nodeIdKey]; + if (!nodeArray) { + completion(); + return; + } + [controllerDictionary removeObjectForKey:nodeIdKey]; + if ([controllerDictionary count] == 0) { + // Dereference proxy retainer for reports so that XPC connection may be invalidated if no longer used. + self.proxyRetainerForReports = nil; + } completion(); - return; - } - [controllerDictionary removeObjectForKey:nodeIdKey]; - if ([controllerDictionary count] == 0) { - // Dereference proxy retainer for reports so that XPC connection may be invalidated if no longer used. - self.proxyRetainerForReports = nil; - } - completion(); + }; + [self + getProxyHandleWithCompletion:^(dispatch_queue_t _Nonnull queue, CHIPDeviceControllerXPCProxyHandle * _Nullable handle) { + if (handle) { + CHIP_LOG_DEBUG("CHIP XPC connection requests to stop reports"); + [handle.proxy stopReportsWithController:controller + nodeId:nodeId + completion:^{ + __auto_type handleRetainer = handle; + (void) handleRetainer; + clearRegistry(); + }]; + } else { + CHIP_LOG_ERROR("CHIP XPC connection failed to stop reporting"); + clearRegistry(); + } + }]; }); } diff --git a/src/darwin/Framework/CHIP/CHIPDeviceOverXPC.m b/src/darwin/Framework/CHIP/CHIPDeviceOverXPC.m index 909d943cbced68..8d11e8cb902cee 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceOverXPC.m +++ b/src/darwin/Framework/CHIP/CHIPDeviceOverXPC.m @@ -17,6 +17,7 @@ #import "CHIPDeviceOverXPC.h" +#import "CHIPCluster.h" #import "CHIPDeviceController+XPC.h" #import "CHIPDeviceControllerXPCConnection.h" #import "CHIPError.h" @@ -57,9 +58,10 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue }); } -- (void)readAttributeWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId +- (void)readAttributeWithEndpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId + params:(CHIPReadParams * _Nullable)params clientQueue:(dispatch_queue_t)clientQueue completion:(CHIPDeviceResponseHandler)completion { @@ -72,6 +74,7 @@ - (void)readAttributeWithEndpointId:(NSUInteger)endpointId endpointId:endpointId clusterId:clusterId attributeId:attributeId + params:[CHIPDeviceController encodeXPCReadParams:params] completion:^(id _Nullable values, NSError * _Nullable error) { dispatch_async(clientQueue, ^{ CHIP_LOG_DEBUG("Attribute read"); @@ -91,10 +94,11 @@ - (void)readAttributeWithEndpointId:(NSUInteger)endpointId }]; } -- (void)writeAttributeWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId +- (void)writeAttributeWithEndpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + attributeId:(NSNumber *)attributeId value:(id)value + timedWriteTimeout:(NSNumber * _Nullable)timeoutMs clientQueue:(dispatch_queue_t)clientQueue completion:(CHIPDeviceResponseHandler)completion { @@ -108,6 +112,7 @@ - (void)writeAttributeWithEndpointId:(NSUInteger)endpointId clusterId:clusterId attributeId:attributeId value:value + timedWriteTimeout:timeoutMs completion:^(id _Nullable values, NSError * _Nullable error) { dispatch_async(clientQueue, ^{ CHIP_LOG_DEBUG("Attribute written"); @@ -127,10 +132,11 @@ - (void)writeAttributeWithEndpointId:(NSUInteger)endpointId }]; } -- (void)invokeCommandWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - commandId:(NSUInteger)commandId +- (void)invokeCommandWithEndpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + commandId:(NSNumber *)commandId commandFields:(id)commandFields + timedInvokeTimeout:(NSNumber * _Nullable)timeoutMs clientQueue:(dispatch_queue_t)clientQueue completion:(CHIPDeviceResponseHandler)completion { @@ -144,6 +150,7 @@ - (void)invokeCommandWithEndpointId:(NSUInteger)endpointId clusterId:clusterId commandId:commandId fields:commandFields + timedInvokeTimeout:timeoutMs completion:^(id _Nullable values, NSError * _Nullable error) { dispatch_async(clientQueue, ^{ CHIP_LOG_DEBUG("Command invoked"); @@ -163,11 +170,12 @@ - (void)invokeCommandWithEndpointId:(NSUInteger)endpointId }]; } -- (void)subscribeAttributeWithEndpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId - minInterval:(NSUInteger)minInterval - maxInterval:(NSUInteger)maxInterval +- (void)subscribeAttributeWithEndpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId + minInterval:(NSNumber *)minInterval + maxInterval:(NSNumber *)maxInterval + params:(CHIPSubscribeParams * _Nullable)params clientQueue:(dispatch_queue_t)clientQueue reportHandler:(CHIPDeviceResponseHandler)reportHandler subscriptionEstablished:(void (^_Nullable)(void))subscriptionEstablishedHandler @@ -197,12 +205,10 @@ - (void)subscribeAttributeWithEndpointId:(NSUInteger)endpointId [NSMutableArray arrayWithCapacity:[decodedValues count]]; for (NSDictionary * decodedValue in decodedValues) { CHIPAttributePath * attributePath = decodedValue[kCHIPAttributePathKey]; - if (([attributePath.endpoint unsignedIntegerValue] == endpointId - || endpointId == 0xffff) - && ([attributePath.cluster unsignedIntegerValue] == clusterId - || clusterId == 0xffffffff) - && ([attributePath.attribute unsignedIntegerValue] == attributeId - || attributeId == 0xffffffff)) { + if ((endpointId == nil || [attributePath.endpoint isEqualToNumber:endpointId]) + && (clusterId == nil || [attributePath.cluster isEqualToNumber:clusterId]) + && (attributeId == nil || + [attributePath.attribute isEqualToNumber:attributeId])) { [filteredValues addObject:decodedValue]; } } @@ -220,6 +226,7 @@ - (void)subscribeAttributeWithEndpointId:(NSUInteger)endpointId attributeId:attributeId minInterval:minInterval maxInterval:maxInterval + params:[CHIPDeviceController encodeXPCSubscribeParams:params] establishedHandler:^{ dispatch_async(clientQueue, ^{ CHIP_LOG_DEBUG("Subscription established"); diff --git a/src/darwin/Framework/CHIPTests/CHIPDeviceTests.m b/src/darwin/Framework/CHIPTests/CHIPDeviceTests.m index 0ddb2c8b99989d..b075c9e4d45838 100644 --- a/src/darwin/Framework/CHIPTests/CHIPDeviceTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPDeviceTests.m @@ -207,9 +207,10 @@ - (void)test001_ReadAttribute CHIPDevice * device = GetConnectedDevice(); dispatch_queue_t queue = dispatch_get_main_queue(); - [device readAttributeWithEndpointId:0xffff - clusterId:29 - attributeId:0 + [device readAttributeWithEndpointId:nil + clusterId:@29 + attributeId:@0 + params:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"read attribute: DeviceType values: %@, error: %@", values, error); @@ -248,10 +249,11 @@ - (void)test002_WriteAttribute NSDictionary * writeValue = [NSDictionary dictionaryWithObjectsAndKeys:@"UnsignedInteger", @"type", [NSNumber numberWithUnsignedInteger:200], @"value", nil]; - [device writeAttributeWithEndpointId:1 - clusterId:8 - attributeId:17 + [device writeAttributeWithEndpointId:@1 + clusterId:@8 + attributeId:@17 value:writeValue + timedWriteTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"write attribute: Brightness values: %@, error: %@", values, error); @@ -295,10 +297,11 @@ - (void)test003_InvokeCommand @{ @"contextTag" : @1, @"data" : @ { @"type" : @"UnsignedInteger", @"value" : @10 } } ] }; - [device invokeCommandWithEndpointId:1 - clusterId:8 - commandId:4 + [device invokeCommandWithEndpointId:@1 + clusterId:@8 + commandId:@4 commandFields:fields + timedInvokeTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"invoke command: MoveToLevelWithOnOff values: %@, error: %@", values, error); @@ -326,41 +329,6 @@ - (void)test003_InvokeCommand static void (^globalReportHandler)(id _Nullable values, NSError * _Nullable error) = nil; -#if !MANUAL_INDIVIDUAL_TEST -- (void)test004_SubscribeOnly -{ - CHIPDevice * device = GetConnectedDevice(); - dispatch_queue_t queue = dispatch_get_main_queue(); - - // Subscribe - XCTestExpectation * expectation = [self expectationWithDescription:@"subscribe OnOff attribute"]; - [device subscribeAttributeWithEndpointId:1 - clusterId:6 - attributeId:0 - minInterval:1 - maxInterval:10 - clientQueue:queue - reportHandler:^(id _Nullable values, NSError * _Nullable error) { - NSLog(@"report attribute: OnOff values: %@, error: %@", values, error); - - if (globalReportHandler) { - __auto_type callback = globalReportHandler; - callback(values, error); - } - } - subscriptionEstablished:^{ - NSLog(@"subscribe attribute: OnOff established"); - [expectation fulfill]; - }]; - - // Wait till establishment - [self waitForExpectations:[NSArray arrayWithObject:expectation] timeout:kTimeoutInSeconds]; -} -#endif - -// Report behavior is erratic on the accessory side at the moment. -// Hence this test is enabled only for individual manual test. -#if MANUAL_INDIVIDUAL_TEST - (void)test005_Subscribe { #if MANUAL_INDIVIDUAL_TEST @@ -370,14 +338,14 @@ - (void)test005_Subscribe CHIPDevice * device = GetConnectedDevice(); dispatch_queue_t queue = dispatch_get_main_queue(); -#if MANUAL_INDIVIDUAL_TEST // Subscribe XCTestExpectation * expectation = [self expectationWithDescription:@"subscribe OnOff attribute"]; - [device subscribeAttributeWithEndpointId:1 - clusterId:6 - attributeId:0 - minInterval:1 - maxInterval:10 + [device subscribeAttributeWithEndpointId:@1 + clusterId:@6 + attributeId:@0 + minInterval:@1 + maxInterval:@10 + params:nil clientQueue:queue reportHandler:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"report attribute: OnOff values: %@, error: %@", values, error); @@ -394,14 +362,13 @@ - (void)test005_Subscribe // Wait till establishment [self waitForExpectations:[NSArray arrayWithObject:expectation] timeout:kTimeoutInSeconds]; -#endif // Set up expectation for report XCTestExpectation * reportExpectation = [self expectationWithDescription:@"report received"]; - globalReportHandler = ^(id _Nullable value, NSError * _Nullable error) { + globalReportHandler = ^(id _Nullable values, NSError * _Nullable error) { XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); - XCTAssertTrue([value isKindOfClass:[NSArray class]]); - NSDictionary * result = value[0]; + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSDictionary * result = values[0]; CHIPAttributePath * path = result[@"attributePath"]; XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); XCTAssertEqual([path.cluster unsignedIntegerValue], 6); @@ -417,10 +384,11 @@ - (void)test005_Subscribe // Send commands to trigger attribute change XCTestExpectation * commandExpectation = [self expectationWithDescription:@"command responded"]; NSDictionary * fields = @{ @"type" : @"Structure", @"value" : [NSArray array] }; - [device invokeCommandWithEndpointId:1 - clusterId:6 - commandId:1 + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@1 commandFields:fields + timedInvokeTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"invoke command: On values: %@, error: %@", values, error); @@ -448,10 +416,10 @@ - (void)test005_Subscribe // Set up expectation for 2nd report reportExpectation = [self expectationWithDescription:@"receive OnOff attribute report"]; - globalReportHandler = ^(id _Nullable value, NSError * _Nullable error) { + globalReportHandler = ^(id _Nullable values, NSError * _Nullable error) { XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); - XCTAssertTrue([value isKindOfClass:[NSArray class]]); - NSDictionary * result = value[0]; + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSDictionary * result = values[0]; CHIPAttributePath * path = result[@"attributePath"]; XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); XCTAssertEqual([path.cluster unsignedIntegerValue], 6); @@ -466,10 +434,11 @@ - (void)test005_Subscribe // Send command to trigger attribute change fields = [NSDictionary dictionaryWithObjectsAndKeys:@"Structure", @"type", [NSArray array], @"value", nil]; - [device invokeCommandWithEndpointId:1 - clusterId:6 - commandId:0 + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@0 commandFields:fields + timedInvokeTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"invoke command: On values: %@, error: %@", values, error); @@ -500,7 +469,6 @@ - (void)test005_Subscribe }]; [self waitForExpectations:@[ expectation ] timeout:kTimeoutInSeconds]; } -#endif - (void)test006_ReadAttributeFailure { @@ -514,9 +482,10 @@ - (void)test006_ReadAttributeFailure dispatch_queue_t queue = dispatch_get_main_queue(); [device - readAttributeWithEndpointId:0 - clusterId:10000 - attributeId:0 + readAttributeWithEndpointId:@0 + clusterId:@10000 + attributeId:@0 + params:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"read attribute: DeviceType values: %@, error: %@", values, error); @@ -543,10 +512,11 @@ - (void)test007_WriteAttributeFailure NSDictionary * writeValue = [NSDictionary dictionaryWithObjectsAndKeys:@"UnsignedInteger", @"type", [NSNumber numberWithUnsignedInteger:200], @"value", nil]; - [device writeAttributeWithEndpointId:1 - clusterId:8 - attributeId:10000 + [device writeAttributeWithEndpointId:@1 + clusterId:@8 + attributeId:@10000 value:writeValue + timedWriteTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"write attribute: Brightness values: %@, error: %@", values, error); @@ -573,28 +543,28 @@ - (void)test008_InvokeCommandFailure CHIPDevice * device = GetConnectedDevice(); dispatch_queue_t queue = dispatch_get_main_queue(); - NSDictionary *fields = [NSDictionary dictionaryWithObjectsAndKeys: - @"Structure", @"type", - [NSArray arrayWithObjects: - [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithUnsignedInteger:0], @"tag", - [NSDictionary dictionaryWithObjectsAndKeys: - @"UnsignedInteger", @"type", - [NSNumber numberWithUnsignedInteger:0], @"value", nil], @"value", nil], - [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithUnsignedInteger:1], @"tag", - [NSDictionary dictionaryWithObjectsAndKeys: - @"UnsignedInteger", @"type", - [NSNumber numberWithUnsignedInteger:10], @"value", nil], @"value", nil], - nil], @"value", nil]; - [device invokeCommandWithEndpointId:1 clusterId:8 commandId:40000 commandFields:fields clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { - NSLog(@"invoke command: MoveToLevelWithOnOff values: %@, error: %@", values, error); - - XCTAssertNil(values); - XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], EMBER_ZCL_STATUS_UNSUPPORTED_COMMAND); - - [expectation fulfill]; - }]; + NSDictionary * fields = @{ + @"type" : @"Structure", + @"value" : @[ + @{ @"contextTag" : @0, @"data" : @ { @"type" : @"UnsignedInteger", @"value" : @0 } }, + @{ @"contextTag" : @1, @"data" : @ { @"type" : @"UnsignedInteger", @"value" : @10 } } + ] + }; + [device + invokeCommandWithEndpointId:@1 + clusterId:@8 + commandId:@40000 + commandFields:fields + timedInvokeTimeout:nil + clientQueue:queue + completion:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"invoke command: MoveToLevelWithOnOff values: %@, error: %@", values, error); + + XCTAssertNil(values); + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], EMBER_ZCL_STATUS_UNSUPPORTED_COMMAND); + + [expectation fulfill]; + }]; [self waitForExpectations:[NSArray arrayWithObject:expectation] timeout:kTimeoutInSeconds]; } @@ -629,11 +599,12 @@ - (void)test009_SubscribeFailure }]; [self waitForExpectations:@[ cleanSubscriptionExpectation ] timeout:kTimeoutInSeconds]; - [device subscribeAttributeWithEndpointId:10000 - clusterId:6 - attributeId:0 - minInterval:2 - maxInterval:10 + [device subscribeAttributeWithEndpointId:@10000 + clusterId:@6 + attributeId:@0 + minInterval:@2 + maxInterval:@10 + params:nil clientQueue:queue reportHandler:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"report attribute: OnOff values: %@, error: %@", values, error); @@ -665,9 +636,10 @@ - (void)test010_ReadAllAttribute CHIPDevice * device = GetConnectedDevice(); dispatch_queue_t queue = dispatch_get_main_queue(); - [device readAttributeWithEndpointId:1 - clusterId:29 - attributeId:0xffffffff + [device readAttributeWithEndpointId:@1 + clusterId:@29 + attributeId:nil + params:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"read attribute: DeviceType values: %@, error: %@", values, error); @@ -718,6 +690,7 @@ - (void)test011_ReadCachedAttribute NSLog(@"Subscribing..."); [attributeCacheContainer subscribeWithDeviceController:controller deviceId:kDeviceId + params:nil clientQueue:queue completion:^(NSError * _Nullable error) { NSLog(@"Subscription complete with error: %@", error); @@ -814,9 +787,9 @@ - (void)test011_ReadCachedAttribute NSLog(@"Reading from cache using generic path..."); cacheExpectation = [self expectationWithDescription:@"Attribute cache read"]; [attributeCacheContainer - readAttributeWithEndpointId:1 - clusterId:6 - attributeId:0 + readAttributeWithEndpointId:@1 + clusterId:@6 + attributeId:@0 clientQueue:queue completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Read attribute cache value: %@, error %@", values, error); @@ -837,9 +810,9 @@ - (void)test011_ReadCachedAttribute NSLog(@"Reading from cache using wildcard endpoint..."); cacheExpectation = [self expectationWithDescription:@"Attribute cache read"]; [attributeCacheContainer - readAttributeWithEndpointId:0xffff - clusterId:6 - attributeId:0 + readAttributeWithEndpointId:nil + clusterId:@6 + attributeId:@0 clientQueue:queue completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Read attribute cache value: %@, error %@", values, error); @@ -859,9 +832,9 @@ - (void)test011_ReadCachedAttribute NSLog(@"Reading from cache using wildcard cluster ID..."); cacheExpectation = [self expectationWithDescription:@"Attribute cache read"]; [attributeCacheContainer - readAttributeWithEndpointId:1 - clusterId:0xffffffff - attributeId:0 + readAttributeWithEndpointId:@1 + clusterId:nil + attributeId:@0 clientQueue:queue completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Read attribute cache value: %@, error %@", values, error); @@ -880,9 +853,9 @@ - (void)test011_ReadCachedAttribute NSLog(@"Reading from cache using wildcard attribute ID..."); cacheExpectation = [self expectationWithDescription:@"Attribute cache read"]; [attributeCacheContainer - readAttributeWithEndpointId:1 - clusterId:6 - attributeId:0xffffffff + readAttributeWithEndpointId:@1 + clusterId:@6 + attributeId:nil clientQueue:queue completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Read attribute cache value: %@, error %@", values, error); @@ -902,9 +875,9 @@ - (void)test011_ReadCachedAttribute NSLog(@"Reading from cache using wildcard endpoint ID and cluster ID..."); cacheExpectation = [self expectationWithDescription:@"Attribute cache read"]; [attributeCacheContainer - readAttributeWithEndpointId:0xffff - clusterId:0xffffffff - attributeId:0 + readAttributeWithEndpointId:nil + clusterId:nil + attributeId:@0 clientQueue:queue completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Read attribute cache value: %@, error %@", values, error); @@ -933,11 +906,12 @@ - (void)test012_SubscriptionError // Subscribe XCTestExpectation * expectation = [self expectationWithDescription:@"subscribe OnOff attribute"]; - [device subscribeAttributeWithEndpointId:1 - clusterId:6 - attributeId:0 - minInterval:1 - maxInterval:10 + [device subscribeAttributeWithEndpointId:@1 + clusterId:@6 + attributeId:@0 + minInterval:@1 + maxInterval:@10 + params:nil clientQueue:queue reportHandler:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"report attribute: OnOff values: %@, error: %@", values, error); @@ -976,10 +950,11 @@ - (void)test012_SubscriptionError // Send commands to trigger attribute change XCTestExpectation * commandExpectation = [self expectationWithDescription:@"command responded"]; NSDictionary * fields = @{ @"type" : @"Structure", @"value" : [NSArray array] }; - [device invokeCommandWithEndpointId:1 - clusterId:6 - commandId:1 + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@1 commandFields:fields + timedInvokeTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"invoke command: On values: %@, error: %@", values, error); @@ -1042,11 +1017,12 @@ - (void)test900_SubscribeAllAttributes XCTestExpectation * expectation = [self expectationWithDescription:@"subscribe OnOff attribute"]; __block void (^reportHandler)(id _Nullable values, NSError * _Nullable error) = nil; - [device subscribeAttributeWithEndpointId:1 - clusterId:6 - attributeId:0xffffffff - minInterval:2 - maxInterval:10 + [device subscribeAttributeWithEndpointId:@1 + clusterId:@6 + attributeId:@0xffffffff + minInterval:@2 + maxInterval:@10 + params:nil clientQueue:queue reportHandler:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"Subscribe all - report attribute values: %@, error: %@, report handler: %d", values, error, @@ -1085,10 +1061,11 @@ - (void)test900_SubscribeAllAttributes // Send commands to set attribute state to a known state XCTestExpectation * commandExpectation = [self expectationWithDescription:@"command responded"]; NSDictionary * fields = @{ @"type" : @"Structure", @"value" : @[] }; - [device invokeCommandWithEndpointId:1 - clusterId:6 - commandId:0 + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@0 commandFields:fields + timedInvokeTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"invoke command: On values: %@, error: %@", values, error); @@ -1114,10 +1091,11 @@ - (void)test900_SubscribeAllAttributes // Send commands to trigger attribute change commandExpectation = [self expectationWithDescription:@"command responded"]; fields = @{ @"type" : @"Structure", @"value" : @[] }; - [device invokeCommandWithEndpointId:1 - clusterId:6 - commandId:1 + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@1 commandFields:fields + timedInvokeTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"invoke command: On values: %@, error: %@", values, error); @@ -1162,10 +1140,11 @@ - (void)test900_SubscribeAllAttributes // Send command to trigger attribute change commandExpectation = [self expectationWithDescription:@"command responded"]; fields = @{ @"type" : @"Structure", @"value" : @[] }; - [device invokeCommandWithEndpointId:1 - clusterId:6 - commandId:0 + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@0 commandFields:fields + timedInvokeTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"invoke command: On values: %@, error: %@", values, error); diff --git a/src/darwin/Framework/CHIPTests/CHIPXPCListenerSampleTests.m b/src/darwin/Framework/CHIPTests/CHIPXPCListenerSampleTests.m index c4fbd2a5b99b4d..5e5502d7c35973 100644 --- a/src/darwin/Framework/CHIPTests/CHIPXPCListenerSampleTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPXPCListenerSampleTests.m @@ -154,9 +154,10 @@ - (void)getAnyDeviceControllerWithCompletion:(void (^)(id _Nullable controller, - (void)readAttributeWithController:(id)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId + endpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId + params:(NSDictionary * _Nullable)params completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion { (void) controller; @@ -173,6 +174,7 @@ - (void)readAttributeWithController:(id)controller [device readAttributeWithEndpointId:endpointId clusterId:clusterId attributeId:attributeId + params:[CHIPDeviceController decodeXPCReadParams:params] clientQueue:dispatch_get_main_queue() completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { @@ -188,10 +190,11 @@ - (void)readAttributeWithController:(id)controller - (void)writeAttributeWithController:(id)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId + endpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + attributeId:(NSNumber *)attributeId value:(id)value + timedWriteTimeout:(NSNumber *)timeoutMs completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion { (void) controller; @@ -209,6 +212,7 @@ - (void)writeAttributeWithController:(id)controller clusterId:clusterId attributeId:attributeId value:value + timedWriteTimeout:timeoutMs clientQueue:dispatch_get_main_queue() completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { @@ -224,10 +228,11 @@ - (void)writeAttributeWithController:(id)controller - (void)invokeCommandWithController:(id)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - commandId:(NSUInteger)commandId + endpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + commandId:(NSNumber *)commandId fields:(id)fields + timedInvokeTimeout:(NSNumber * _Nullable)timeoutMs completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion { (void) controller; @@ -245,6 +250,7 @@ - (void)invokeCommandWithController:(id)controller clusterId:clusterId commandId:commandId commandFields:fields + timedInvokeTimeout:nil clientQueue:dispatch_get_main_queue() completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { @@ -260,11 +266,12 @@ - (void)invokeCommandWithController:(id)controller - (void)subscribeAttributeWithController:(id)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId - minInterval:(NSUInteger)minInterval - maxInterval:(NSUInteger)maxInterval + endpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId + minInterval:(NSNumber *)minInterval + maxInterval:(NSNumber *)maxInterval + params:(NSDictionary * _Nullable)params establishedHandler:(void (^)(void))establishedHandler { __auto_type sharedController = [CHIPDeviceController sharedController]; @@ -289,6 +296,7 @@ - (void)subscribeAttributeWithController:(id)controller attributeId:attributeId minInterval:minInterval maxInterval:maxInterval + params:[CHIPDeviceController decodeXPCSubscribeParams:params] clientQueue:dispatch_get_main_queue() reportHandler:^(NSArray *> * _Nullable values, NSError * _Nullable error) { @@ -314,8 +322,28 @@ - (void)subscribeAttributeWithController:(id)controller } } +- (void)stopReportsWithController:(id _Nullable)controller nodeId:(uint64_t)nodeId completion:(void (^)(void))completion +{ + __auto_type sharedController = [CHIPDeviceController sharedController]; + if (sharedController) { + [sharedController getConnectedDevice:nodeId + queue:dispatch_get_main_queue() + completionHandler:^(CHIPDevice * _Nullable device, NSError * _Nullable error) { + if (error) { + NSLog(@"Failed to get connected device"); + } else { + [device deregisterReportHandlersWithClientQueue:dispatch_get_main_queue() completion:completion]; + } + }]; + } else { + NSLog(@"Failed to get shared controller"); + completion(); + } +} + - (void)subscribeAttributeCacheWithController:(id _Nullable)controller nodeId:(uint64_t)nodeId + params:(NSDictionary * _Nullable)params completion:(void (^)(NSError * _Nullable error))completion { __auto_type sharedController = [CHIPDeviceController sharedController]; @@ -324,6 +352,7 @@ - (void)subscribeAttributeCacheWithController:(id _Nullable)controller [attributeCacheContainer subscribeWithDeviceController:sharedController deviceId:nodeId + params:[CHIPDeviceController decodeXPCSubscribeParams:params] clientQueue:dispatch_get_main_queue() completion:^(NSError * _Nullable error) { NSNumber * nodeIdNumber = [NSNumber numberWithUnsignedLongLong:nodeId]; @@ -344,9 +373,9 @@ - (void)subscribeAttributeCacheWithController:(id _Nullable)controller - (void)readAttributeCacheWithController:(id _Nullable)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId + endpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion { CHIPAttributeCacheContainer * attributeCacheContainer = _attributeCacheDictionary[[NSNumber numberWithUnsignedLongLong:nodeId]]; @@ -551,9 +580,10 @@ - (void)test001_ReadAttribute CHIPDevice * device = GetConnectedDevice(); dispatch_queue_t queue = dispatch_get_main_queue(); - [device readAttributeWithEndpointId:0xffff - clusterId:29 - attributeId:0 + [device readAttributeWithEndpointId:nil + clusterId:@29 + attributeId:@0 + params:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"read attribute: DeviceType values: %@, error: %@", values, error); @@ -592,10 +622,11 @@ - (void)test002_WriteAttribute NSDictionary * writeValue = [NSDictionary dictionaryWithObjectsAndKeys:@"UnsignedInteger", @"type", [NSNumber numberWithUnsignedInteger:200], @"value", nil]; - [device writeAttributeWithEndpointId:1 - clusterId:8 - attributeId:17 + [device writeAttributeWithEndpointId:@1 + clusterId:@8 + attributeId:@17 value:writeValue + timedWriteTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"write attribute: Brightness values: %@, error: %@", values, error); @@ -639,10 +670,11 @@ - (void)test003_InvokeCommand @{ @"contextTag" : @1, @"data" : @ { @"type" : @"UnsignedInteger", @"value" : @10 } } ] }; - [device invokeCommandWithEndpointId:1 - clusterId:8 - commandId:4 + [device invokeCommandWithEndpointId:@1 + clusterId:@8 + commandId:@4 commandFields:fields + timedInvokeTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"invoke command: MoveToLevelWithOnOff values: %@, error: %@", values, error); @@ -681,11 +713,12 @@ - (void)test004_Subscribe CHIPDevice * device = GetConnectedDevice(); dispatch_queue_t queue = dispatch_get_main_queue(); - [device subscribeAttributeWithEndpointId:1 - clusterId:6 - attributeId:0 - minInterval:2 - maxInterval:10 + [device subscribeAttributeWithEndpointId:@1 + clusterId:@6 + attributeId:@0 + minInterval:@2 + maxInterval:@10 + params:nil clientQueue:queue reportHandler:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"report attribute: OnOff values: %@, error: %@", values, error); @@ -724,10 +757,11 @@ - (void)test004_Subscribe // Send command to trigger attribute change NSDictionary * fields = [NSDictionary dictionaryWithObjectsAndKeys:@"Structure", @"type", [NSArray array], @"value", nil]; - [device invokeCommandWithEndpointId:1 - clusterId:6 - commandId:1 + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@1 commandFields:fields + timedInvokeTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"invoke command: On values: %@, error: %@", values, error); @@ -750,6 +784,13 @@ - (void)test004_Subscribe // Wait for report [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; + + XCTestExpectation * clearExpectation = [self expectationWithDescription:@"report handlers deregistered"]; + [device deregisterReportHandlersWithClientQueue:queue + completion:^{ + [clearExpectation fulfill]; + }]; + [self waitForExpectations:@[ clearExpectation ] timeout:kTimeoutInSeconds]; } - (void)test005_ReadAttributeFailure @@ -763,9 +804,10 @@ - (void)test005_ReadAttributeFailure CHIPDevice * device = GetConnectedDevice(); dispatch_queue_t queue = dispatch_get_main_queue(); - [device readAttributeWithEndpointId:0 - clusterId:10000 - attributeId:0 + [device readAttributeWithEndpointId:@0 + clusterId:@10000 + attributeId:@0 + params:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"read attribute: DeviceType values: %@, error: %@", values, error); @@ -795,10 +837,11 @@ - (void)test006_WriteAttributeFailure NSDictionary * writeValue = [NSDictionary dictionaryWithObjectsAndKeys:@"UnsignedInteger", @"type", [NSNumber numberWithUnsignedInteger:200], @"value", nil]; - [device writeAttributeWithEndpointId:1 - clusterId:8 - attributeId:10000 + [device writeAttributeWithEndpointId:@1 + clusterId:@8 + attributeId:@10000 value:writeValue + timedWriteTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"write attribute: Brightness values: %@, error: %@", values, error); @@ -841,7 +884,9 @@ - (void)test007_InvokeCommandFailure @"UnsignedInteger", @"type", [NSNumber numberWithUnsignedInteger:10], @"value", nil], @"value", nil], nil], @"value", nil]; - [device invokeCommandWithEndpointId:1 clusterId:8 commandId:40000 commandFields:fields clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { + [device invokeCommandWithEndpointId:@1 clusterId:@8 commandId:@40000 commandFields:fields clientQueue:queue + timedInvokeTimeout:nil + completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"invoke command: MoveToLevelWithOnOff values: %@, error: %@", values, error); XCTAssertNil(values); @@ -878,11 +923,12 @@ - (void)test008_SubscribeFailure CHIPDevice * device = GetConnectedDevice(); dispatch_queue_t queue = dispatch_get_main_queue(); - [device subscribeAttributeWithEndpointId:10000 - clusterId:6 - attributeId:0 - minInterval:2 - maxInterval:10 + [device subscribeAttributeWithEndpointId:@10000 + clusterId:@6 + attributeId:@0 + minInterval:@2 + maxInterval:@10 + params:nil clientQueue:queue reportHandler:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"report attribute: OnOff values: %@, error: %@", values, error); @@ -902,7 +948,786 @@ - (void)test008_SubscribeFailure [self waitForExpectations:[NSArray arrayWithObjects:expectation, errorReportExpectation, nil] timeout:kTimeoutInSeconds]; } -- (void)test009_SubscribeAttributeCache +- (void)test009_ReadAttributeWithParams +{ +#if MANUAL_INDIVIDUAL_TEST + [self initStack]; + [self waitForCommissionee]; +#endif + XCTestExpectation * expectation = + [self expectationWithDescription:@"read DeviceDescriptor DeviceType attribute for all endpoints"]; + + CHIPDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + + CHIPReadParams * readParams = [[CHIPReadParams alloc] init]; + readParams.fabricFiltered = @NO; + [device readAttributeWithEndpointId:nil + clusterId:@29 + attributeId:@0 + params:readParams + clientQueue:queue + completion:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"read attribute: DeviceType values: %@, error: %@", values, error); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSArray * resultArray = values; + for (NSDictionary * result in resultArray) { + CHIPAttributePath * path = result[@"attributePath"]; + XCTAssertEqual([path.cluster unsignedIntegerValue], 29); + XCTAssertEqual([path.attribute unsignedIntegerValue], 0); + XCTAssertTrue([result[@"data"] isKindOfClass:[NSDictionary class]]); + XCTAssertTrue([result[@"data"][@"type"] isEqualToString:@"Array"]); + } + XCTAssertTrue([resultArray count] > 0); + } + + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; +} + +- (void)test010_SubscribeWithNoParams +{ +#if MANUAL_INDIVIDUAL_TEST + [self initStack]; + [self waitForCommissionee]; +#endif + CHIPDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + + XCTestExpectation * clearExpectation = [self expectationWithDescription:@"report handlers deregistered"]; + [device deregisterReportHandlersWithClientQueue:queue + completion:^{ + [clearExpectation fulfill]; + }]; + [self waitForExpectations:@[ clearExpectation ] timeout:kTimeoutInSeconds]; + + __block void (^firstReportHandler)(id _Nullable values, NSError * _Nullable error) = nil; + __block void (^secondReportHandler)(id _Nullable values, NSError * _Nullable error) = nil; + + // Subscribe + XCTestExpectation * subscribeExpectation = [self expectationWithDescription:@"subscribe OnOff attribute"]; + [device subscribeAttributeWithEndpointId:@1 + clusterId:@6 + attributeId:@0 + minInterval:@2 + maxInterval:@10 + params:nil + clientQueue:queue + reportHandler:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"report attribute: OnOff values: %@, error: %@", values, error); + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + if (firstReportHandler) { + __auto_type callback = firstReportHandler; + firstReportHandler = nil; + callback(values, error); + } + } + subscriptionEstablished:^{ + NSLog(@"subscribe attribute: OnOff established"); + [subscribeExpectation fulfill]; + }]; + + [self waitForExpectations:@[ subscribeExpectation ] timeout:kTimeoutInSeconds]; + + // Setup 2nd subscriber + subscribeExpectation = [self expectationWithDescription:@"subscribe CurrentLevel attribute"]; + [device subscribeAttributeWithEndpointId:@1 + clusterId:@8 + attributeId:@0 + minInterval:@2 + maxInterval:@10 + params:nil + clientQueue:queue + reportHandler:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"2nd subscriber report attribute: CurrentLevel values: %@, error: %@", values, error); + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + if (secondReportHandler) { + __auto_type callback = secondReportHandler; + secondReportHandler = nil; + callback(values, error); + } + } + subscriptionEstablished:^{ + NSLog(@"2nd subscribe attribute: CurrentLevel established"); + [subscribeExpectation fulfill]; + }]; + + // Wait till establishment + [self waitForExpectations:@[ subscribeExpectation ] timeout:kTimeoutInSeconds]; + + // Send command to clear attribute state + XCTestExpectation * clearCommandExpectation = [self expectationWithDescription:@"Clearing command invoked"]; + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@0 + commandFields:@{ @"type" : @"Structure", @"value" : @[] } + timedInvokeTimeout:nil + clientQueue:queue + completion:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"invoke command: On values: %@, error: %@", values, error); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSArray * resultArray = values; + for (NSDictionary * result in resultArray) { + CHIPCommandPath * path = result[@"commandPath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 6); + XCTAssertEqual([path.command unsignedIntegerValue], 0); + XCTAssertNil(result[@"error"]); + } + XCTAssertEqual([resultArray count], 1); + } + [clearCommandExpectation fulfill]; + }]; + [self waitForExpectations:@[ clearCommandExpectation ] timeout:kTimeoutInSeconds]; + + // Set up expectations for report + XCTestExpectation * reportExpectation = + [self expectationWithDescription:@"The 1st subscriber unexpectedly received OnOff attribute report"]; + reportExpectation.inverted = YES; + firstReportHandler = ^(id _Nullable values, NSError * _Nullable error) { + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSDictionary * result = values[0]; + CHIPAttributePath * path = result[@"attributePath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 6); + XCTAssertEqual([path.attribute unsignedIntegerValue], 0); + XCTAssertTrue([result[@"data"] isKindOfClass:[NSDictionary class]]); + XCTAssertTrue([result[@"data"][@"type"] isEqualToString:@"Boolean"]); + XCTAssertEqual([result[@"data"][@"value"] boolValue], YES); + } + [reportExpectation fulfill]; + }; + + XCTestExpectation * secondReportExpectation = + [self expectationWithDescription:@"The 2nd subscriber received CurrentLevel attribute report"]; + secondReportHandler = ^(id _Nullable values, NSError * _Nullable error) { + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSDictionary * result = values[0]; + CHIPAttributePath * path = result[@"attributePath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 8); + XCTAssertEqual([path.attribute unsignedIntegerValue], 0); + XCTAssertTrue([result[@"data"] isKindOfClass:[NSDictionary class]]); + XCTAssertTrue([result[@"data"][@"type"] isEqualToString:@"UnsignedInteger"]); + XCTAssertNotNil(result[@"data"][@"value"]); + } + [secondReportExpectation fulfill]; + }; + + // Send command to trigger attribute change + NSDictionary * fields = [NSDictionary dictionaryWithObjectsAndKeys:@"Structure", @"type", [NSArray array], @"value", nil]; + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@1 + commandFields:fields + timedInvokeTimeout:nil + clientQueue:queue + completion:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"invoke command: On values: %@, error: %@", values, error); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSArray * resultArray = values; + for (NSDictionary * result in resultArray) { + CHIPCommandPath * path = result[@"commandPath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 6); + XCTAssertEqual([path.command unsignedIntegerValue], 1); + XCTAssertNil(result[@"error"]); + } + XCTAssertEqual([resultArray count], 1); + } + }]; + + // Wait for report + [self waitForExpectations:@[ reportExpectation, secondReportExpectation ] timeout:kTimeoutInSeconds]; + + clearExpectation = [self expectationWithDescription:@"report handlers deregistered"]; + [device deregisterReportHandlersWithClientQueue:queue + completion:^{ + [clearExpectation fulfill]; + }]; + [self waitForExpectations:@[ clearExpectation ] timeout:kTimeoutInSeconds]; +} + +- (void)test011_SubscribeWithParams +{ +#if MANUAL_INDIVIDUAL_TEST + [self initStack]; + [self waitForCommissionee]; +#endif + CHIPDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + + XCTestExpectation * clearExpectation = [self expectationWithDescription:@"report handlers deregistered"]; + [device deregisterReportHandlersWithClientQueue:queue + completion:^{ + [clearExpectation fulfill]; + }]; + [self waitForExpectations:@[ clearExpectation ] timeout:kTimeoutInSeconds]; + + __block void (^firstReportHandler)(id _Nullable values, NSError * _Nullable error) = nil; + __block void (^secondReportHandler)(id _Nullable values, NSError * _Nullable error) = nil; + + // Subscribe + XCTestExpectation * subscribeExpectation = [self expectationWithDescription:@"subscribe OnOff attribute"]; + [device subscribeAttributeWithEndpointId:@1 + clusterId:@6 + attributeId:@0 + minInterval:@2 + maxInterval:@10 + params:nil + clientQueue:queue + reportHandler:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"report attribute: OnOff values: %@, error: %@", values, error); + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + if (firstReportHandler) { + __auto_type callback = firstReportHandler; + firstReportHandler = nil; + callback(values, error); + } + } + subscriptionEstablished:^{ + NSLog(@"subscribe attribute: OnOff established"); + [subscribeExpectation fulfill]; + }]; + + [self waitForExpectations:@[ subscribeExpectation ] timeout:kTimeoutInSeconds]; + + // Setup 2nd subscriber + CHIPSubscribeParams * myParams = [[CHIPSubscribeParams alloc] init]; + myParams.keepPreviousSubscriptions = @NO; + subscribeExpectation = [self expectationWithDescription:@"subscribe CurrentLevel attribute"]; + [device subscribeAttributeWithEndpointId:@1 + clusterId:@8 + attributeId:@0 + minInterval:@2 + maxInterval:@10 + params:myParams + clientQueue:queue + reportHandler:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"2nd subscriber report attribute: CurrentLevel values: %@, error: %@", values, error); + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + if (secondReportHandler) { + __auto_type callback = secondReportHandler; + secondReportHandler = nil; + callback(values, error); + } + } + subscriptionEstablished:^{ + NSLog(@"2nd subscribe attribute: CurrentLevel established"); + [subscribeExpectation fulfill]; + }]; + + // Wait till establishment + [self waitForExpectations:@[ subscribeExpectation ] timeout:kTimeoutInSeconds]; + + // Send command to clear attribute state + XCTestExpectation * clearCommandExpectation = [self expectationWithDescription:@"Clearing command invoked"]; + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@0 + commandFields:@{ @"type" : @"Structure", @"value" : @[] } + timedInvokeTimeout:nil + clientQueue:queue + completion:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"invoke command: On values: %@, error: %@", values, error); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSArray * resultArray = values; + for (NSDictionary * result in resultArray) { + CHIPCommandPath * path = result[@"commandPath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 6); + XCTAssertEqual([path.command unsignedIntegerValue], 0); + XCTAssertNil(result[@"error"]); + } + XCTAssertEqual([resultArray count], 1); + } + [clearCommandExpectation fulfill]; + }]; + [self waitForExpectations:@[ clearCommandExpectation ] timeout:kTimeoutInSeconds]; + + // Set up expectations for report + XCTestExpectation * reportExpectation = + [self expectationWithDescription:@"The 1st subscriber unexpectedly received OnOff attribute report"]; + reportExpectation.inverted = YES; + firstReportHandler = ^(id _Nullable values, NSError * _Nullable error) { + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSDictionary * result = values[0]; + CHIPAttributePath * path = result[@"attributePath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 6); + XCTAssertEqual([path.attribute unsignedIntegerValue], 0); + XCTAssertTrue([result[@"data"] isKindOfClass:[NSDictionary class]]); + XCTAssertTrue([result[@"data"][@"type"] isEqualToString:@"Boolean"]); + XCTAssertEqual([result[@"data"][@"value"] boolValue], YES); + } + [reportExpectation fulfill]; + }; + + XCTestExpectation * secondReportExpectation = + [self expectationWithDescription:@"The 2nd subscriber received CurrentLevel attribute report"]; + secondReportHandler = ^(id _Nullable values, NSError * _Nullable error) { + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSDictionary * result = values[0]; + CHIPAttributePath * path = result[@"attributePath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 8); + XCTAssertEqual([path.attribute unsignedIntegerValue], 0); + XCTAssertTrue([result[@"data"] isKindOfClass:[NSDictionary class]]); + XCTAssertTrue([result[@"data"][@"type"] isEqualToString:@"UnsignedInteger"]); + XCTAssertNotNil(result[@"data"][@"value"]); + } + [secondReportExpectation fulfill]; + }; + + // Send command to trigger attribute change + NSDictionary * fields = [NSDictionary dictionaryWithObjectsAndKeys:@"Structure", @"type", [NSArray array], @"value", nil]; + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@1 + commandFields:fields + timedInvokeTimeout:nil + clientQueue:queue + completion:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"invoke command: On values: %@, error: %@", values, error); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSArray * resultArray = values; + for (NSDictionary * result in resultArray) { + CHIPCommandPath * path = result[@"commandPath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 6); + XCTAssertEqual([path.command unsignedIntegerValue], 1); + XCTAssertNil(result[@"error"]); + } + XCTAssertEqual([resultArray count], 1); + } + }]; + + // Wait for report + [self waitForExpectations:@[ reportExpectation, secondReportExpectation ] timeout:kTimeoutInSeconds]; + + clearExpectation = [self expectationWithDescription:@"report handlers deregistered"]; + [device deregisterReportHandlersWithClientQueue:queue + completion:^{ + [clearExpectation fulfill]; + }]; + [self waitForExpectations:@[ clearExpectation ] timeout:kTimeoutInSeconds]; + + clearExpectation = [self expectationWithDescription:@"report handlers deregistered"]; + [device deregisterReportHandlersWithClientQueue:queue + completion:^{ + [clearExpectation fulfill]; + }]; + [self waitForExpectations:@[ clearExpectation ] timeout:kTimeoutInSeconds]; +} + +- (void)test012_SubscribeKeepingPreviousSubscription +{ +#if MANUAL_INDIVIDUAL_TEST + [self initStack]; + [self waitForCommissionee]; +#endif + CHIPDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + + XCTestExpectation * clearExpectation = [self expectationWithDescription:@"report handlers deregistered"]; + [device deregisterReportHandlersWithClientQueue:queue + completion:^{ + [clearExpectation fulfill]; + }]; + [self waitForExpectations:@[ clearExpectation ] timeout:kTimeoutInSeconds]; + + __block void (^firstReportHandler)(id _Nullable values, NSError * _Nullable error) = nil; + __block void (^secondReportHandler)(id _Nullable values, NSError * _Nullable error) = nil; + + // Subscribe + XCTestExpectation * subscribeExpectation = [self expectationWithDescription:@"subscribe OnOff attribute"]; + [device subscribeAttributeWithEndpointId:@1 + clusterId:@6 + attributeId:@0 + minInterval:@2 + maxInterval:@10 + params:nil + clientQueue:queue + reportHandler:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"report attribute: OnOff values: %@, error: %@", values, error); + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + if (firstReportHandler) { + __auto_type callback = firstReportHandler; + firstReportHandler = nil; + callback(values, error); + } + } + subscriptionEstablished:^{ + NSLog(@"subscribe attribute: OnOff established"); + [subscribeExpectation fulfill]; + }]; + + [self waitForExpectations:@[ subscribeExpectation ] timeout:kTimeoutInSeconds]; + + // Setup 2nd subscriber + subscribeExpectation = [self expectationWithDescription:@"subscribe CurrentLevel attribute"]; + CHIPSubscribeParams * myParams = [[CHIPSubscribeParams alloc] init]; + myParams.keepPreviousSubscriptions = @YES; + [device subscribeAttributeWithEndpointId:@1 + clusterId:@8 + attributeId:@0 + minInterval:@2 + maxInterval:@10 + params:myParams + clientQueue:queue + reportHandler:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"2nd subscriber report attribute: CurrentLevel values: %@, error: %@", values, error); + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + if (secondReportHandler) { + __auto_type callback = secondReportHandler; + secondReportHandler = nil; + callback(values, error); + } + } + subscriptionEstablished:^{ + NSLog(@"2nd subscribe attribute: CurrentLevel established"); + [subscribeExpectation fulfill]; + }]; + + // Wait till establishment + [self waitForExpectations:@[ subscribeExpectation ] timeout:kTimeoutInSeconds]; + + // Send command to clear attribute state + XCTestExpectation * clearCommandExpectation = [self expectationWithDescription:@"Clearing command invoked"]; + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@0 + commandFields:@{ @"type" : @"Structure", @"value" : @[] } + timedInvokeTimeout:nil + clientQueue:queue + completion:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"invoke command: On values: %@, error: %@", values, error); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSArray * resultArray = values; + for (NSDictionary * result in resultArray) { + CHIPCommandPath * path = result[@"commandPath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 6); + XCTAssertEqual([path.command unsignedIntegerValue], 0); + XCTAssertNil(result[@"error"]); + } + XCTAssertEqual([resultArray count], 1); + } + [clearCommandExpectation fulfill]; + }]; + [self waitForExpectations:@[ clearCommandExpectation ] timeout:kTimeoutInSeconds]; + + // Set up expectations for report + XCTestExpectation * reportExpectation = [self expectationWithDescription:@"The 1st subscriber received OnOff attribute report"]; + firstReportHandler = ^(id _Nullable values, NSError * _Nullable error) { + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSDictionary * result = values[0]; + CHIPAttributePath * path = result[@"attributePath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 6); + XCTAssertEqual([path.attribute unsignedIntegerValue], 0); + XCTAssertTrue([result[@"data"] isKindOfClass:[NSDictionary class]]); + XCTAssertTrue([result[@"data"][@"type"] isEqualToString:@"Boolean"]); + XCTAssertEqual([result[@"data"][@"value"] boolValue], YES); + } + [reportExpectation fulfill]; + }; + + XCTestExpectation * secondReportExpectation = + [self expectationWithDescription:@"The 2nd subscriber received CurrentLevel attribute report"]; + secondReportHandler = ^(id _Nullable values, NSError * _Nullable error) { + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSDictionary * result = values[0]; + CHIPAttributePath * path = result[@"attributePath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 8); + XCTAssertEqual([path.attribute unsignedIntegerValue], 0); + XCTAssertTrue([result[@"data"] isKindOfClass:[NSDictionary class]]); + XCTAssertTrue([result[@"data"][@"type"] isEqualToString:@"UnsignedInteger"]); + XCTAssertNotNil(result[@"data"][@"value"]); + } + [secondReportExpectation fulfill]; + }; + + // Send command to trigger attribute change + NSDictionary * fields = [NSDictionary dictionaryWithObjectsAndKeys:@"Structure", @"type", [NSArray array], @"value", nil]; + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@1 + commandFields:fields + timedInvokeTimeout:nil + clientQueue:queue + completion:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"invoke command: On values: %@, error: %@", values, error); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSArray * resultArray = values; + for (NSDictionary * result in resultArray) { + CHIPCommandPath * path = result[@"commandPath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 6); + XCTAssertEqual([path.command unsignedIntegerValue], 1); + XCTAssertNil(result[@"error"]); + } + XCTAssertEqual([resultArray count], 1); + } + }]; + + // Wait for report + [self waitForExpectations:@[ reportExpectation, secondReportExpectation ] timeout:kTimeoutInSeconds]; + + clearExpectation = [self expectationWithDescription:@"report handlers deregistered"]; + [device deregisterReportHandlersWithClientQueue:queue + completion:^{ + [clearExpectation fulfill]; + }]; + [self waitForExpectations:@[ clearExpectation ] timeout:kTimeoutInSeconds]; +} + +- (void)test013_TimedWriteAttribute +{ +#if MANUAL_INDIVIDUAL_TEST + [self initStack]; + [self waitForCommissionee]; +#endif + CHIPDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + + // Write an initial value + NSDictionary * writeValue = [NSDictionary + dictionaryWithObjectsAndKeys:@"UnsignedInteger", @"type", [NSNumber numberWithUnsignedInteger:200], @"value", nil]; + XCTestExpectation * expectation = [self expectationWithDescription:@"Wrote LevelControl Brightness attribute"]; + [device writeAttributeWithEndpointId:@1 + clusterId:@8 + attributeId:@17 + value:writeValue + timedWriteTimeout:nil + clientQueue:queue + completion:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"write attribute: Brightness values: %@, error: %@", values, error); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSArray * resultArray = values; + for (NSDictionary * result in resultArray) { + CHIPAttributePath * path = result[@"attributePath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 8); + XCTAssertEqual([path.attribute unsignedIntegerValue], 17); + XCTAssertNil(result[@"error"]); + } + XCTAssertEqual([resultArray count], 1); + } + + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; + + // Request a timed write with a new value + writeValue = [NSDictionary + dictionaryWithObjectsAndKeys:@"UnsignedInteger", @"type", [NSNumber numberWithUnsignedInteger:100], @"value", nil]; + expectation = [self expectationWithDescription:@"Requested timed write on LevelControl Brightness attribute"]; + [device writeAttributeWithEndpointId:@1 + clusterId:@8 + attributeId:@17 + value:writeValue + timedWriteTimeout:@1000 + clientQueue:queue + completion:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"Timed-write attribute: Brightness values: %@, error: %@", values, error); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSArray * resultArray = values; + for (NSDictionary * result in resultArray) { + CHIPAttributePath * path = result[@"attributePath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 8); + XCTAssertEqual([path.attribute unsignedIntegerValue], 17); + XCTAssertNil(result[@"error"]); + } + XCTAssertEqual([resultArray count], 1); + } + + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; + +#if 0 // The above attribute isn't for timed interaction. Hence, no verification till we have a capable attribute. + // subscribe, which should get the new value at the timeout + expectation = [self expectationWithDescription:@"Subscribed"]; + __block void (^reportHandler)(id _Nullable values, NSError * _Nullable error); + [device subscribeAttributeWithEndpointId:@1 + clusterId:@8 + attributeId:@17 + minInterval:@2 + maxInterval:@10 + params:nil + clientQueue:queue + reportHandler:^(id _Nullable value, NSError * _Nullable error) { + NSLog(@"report attribute: Brightness values: %@, error: %@", value, error); + + if (reportHandler) { + __auto_type callback = reportHandler; + callback = nil; + callback(value, error); + } + } + subscriptionEstablished:^{ + NSLog(@"subscribe attribute: Brightness established"); + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; + + // Setup report expectation + expectation = [self expectationWithDescription:@"Report received"]; + reportHandler = ^(id _Nullable values, NSError * _Nullable error) { + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSDictionary * result = values[0]; + CHIPAttributePath * path = result[@"attributePath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 8); + XCTAssertEqual([path.attribute unsignedIntegerValue], 17); + XCTAssertTrue([result[@"data"] isKindOfClass:[NSDictionary class]]); + XCTAssertTrue([result[@"data"][@"type"] isEqualToString:@"UnsignedInteger"]); + XCTAssertEqual([result[@"data"][@"value"] unsignedIntegerValue], 100); + [expectation fulfill]; + }; + // Wait for report + [self waitForExpectationsWithTimeout:(kTimeoutInSeconds + 1) handler:nil]; +#endif + + // Read back to see if the timed write has taken effect + expectation = [self expectationWithDescription:@"Read LevelControl Brightness attribute after pause"]; + [device readAttributeWithEndpointId:@1 + clusterId:@8 + attributeId:@17 + params:nil + clientQueue:queue + completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { + NSLog(@"read attribute: LevelControl Brightness values: %@, error: %@", values, error); + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + for (NSDictionary * value in values) { + CHIPAttributePath * path = value[@"attributePath"]; + XCTAssertEqual([path.endpoint unsignedShortValue], 1); + XCTAssertEqual([path.cluster unsignedLongValue], 8); + XCTAssertEqual([path.attribute unsignedLongValue], 17); + XCTAssertTrue([value[@"data"][@"type"] isEqualToString:@"UnsignedInteger"]); + XCTAssertEqual([value[@"data"][@"value"] unsignedIntegerValue], 100); + } + [expectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; +} + +- (void)test014_TimedInvokeCommand +{ +#if MANUAL_INDIVIDUAL_TEST + [self initStack]; + [self waitForCommissionee]; +#endif + XCTestExpectation * expectation = [self expectationWithDescription:@"invoke MoveToLevelWithOnOff command"]; + + CHIPDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + + NSDictionary * fields = @{ + @"type" : @"Structure", + @"value" : @[ + @{ @"contextTag" : @0, @"data" : @ { @"type" : @"UnsignedInteger", @"value" : @0 } }, + @{ @"contextTag" : @1, @"data" : @ { @"type" : @"UnsignedInteger", @"value" : @10 } } + ] + }; + [device invokeCommandWithEndpointId:@1 + clusterId:@8 + commandId:@4 + commandFields:fields + timedInvokeTimeout:@1000 + clientQueue:queue + completion:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"invoke command: MoveToLevelWithOnOff values: %@, error: %@", values, error); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSArray * resultArray = values; + for (NSDictionary * result in resultArray) { + CHIPCommandPath * path = result[@"commandPath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 8); + XCTAssertEqual([path.command unsignedIntegerValue], 4); + XCTAssertNil(result[@"error"]); + } + XCTAssertEqual([resultArray count], 1); + } + + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; + sleep(1); +} + +- (void)test900_SubscribeAttributeCache { #if MANUAL_INDIVIDUAL_TEST [self initStack]; @@ -918,6 +1743,7 @@ - (void)test009_SubscribeAttributeCache NSLog(@"Setting up attribute cache..."); [attributeCacheContainer subscribeWithDeviceController:deviceController deviceId:kDeviceId + params:nil clientQueue:queue completion:^(NSError * _Nullable error) { NSLog(@"Attribute cache subscribed attributes"); @@ -931,14 +1757,46 @@ - (void)test009_SubscribeAttributeCache expectation.inverted = YES; [self waitForExpectations:@[ expectation ] timeout:120]; + // Send command to reset attribute state + NSLog(@"Invoking clearing command..."); + expectation = [self expectationWithDescription:@"Clearing command invoked"]; + NSDictionary * fields = [NSDictionary dictionaryWithObjectsAndKeys:@"Structure", @"type", [NSArray array], @"value", nil]; + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@0 + commandFields:fields + timedInvokeTimeout:nil + clientQueue:queue + completion:^(id _Nullable values, NSError * _Nullable error) { + NSLog(@"invoked command: On values: %@, error: %@", values, error); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:error], 0); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSArray * resultArray = values; + for (NSDictionary * result in resultArray) { + CHIPCommandPath * path = result[@"commandPath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 6); + XCTAssertEqual([path.command unsignedIntegerValue], 0); + XCTAssertNil(result[@"error"]); + } + XCTAssertEqual([resultArray count], 1); + } + [expectation fulfill]; + }]; + [self waitForExpectations:@[ expectation ] timeout:kTimeoutInSeconds]; + // Send command to trigger attribute change - NSLog(@"Invoking command..."); + NSLog(@"Invoking command to trigger report..."); expectation = [self expectationWithDescription:@"Command invoked"]; - NSDictionary * fields = [NSDictionary dictionaryWithObjectsAndKeys:@"Structure", @"type", [NSArray array], @"value", nil]; - [device invokeCommandWithEndpointId:1 - clusterId:6 - commandId:1 + fields = [NSDictionary dictionaryWithObjectsAndKeys:@"Structure", @"type", [NSArray array], @"value", nil]; + [device invokeCommandWithEndpointId:@1 + clusterId:@6 + commandId:@1 commandFields:fields + timedInvokeTimeout:nil clientQueue:queue completion:^(id _Nullable values, NSError * _Nullable error) { NSLog(@"invoked command: On values: %@, error: %@", values, error); @@ -962,12 +1820,13 @@ - (void)test009_SubscribeAttributeCache [self waitForExpectations:@[ expectation ] timeout:kTimeoutInSeconds]; // Read attribute cache + sleep(1); NSLog(@"Reading from attribute cache..."); expectation = [self expectationWithDescription:@"Cache read"]; [attributeCacheContainer - readAttributeWithEndpointId:1 - clusterId:6 - attributeId:0 + readAttributeWithEndpointId:@1 + clusterId:@6 + attributeId:@0 clientQueue:queue completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Cached attribute read: %@, error: %@", values, error); diff --git a/src/darwin/Framework/CHIPTests/CHIPXPCProtocolTests.m b/src/darwin/Framework/CHIPTests/CHIPXPCProtocolTests.m index 85356cb9e68a3c..706b326a63697f 100644 --- a/src/darwin/Framework/CHIPTests/CHIPXPCProtocolTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPXPCProtocolTests.m @@ -90,18 +90,24 @@ @interface CHIPXPCProtocolTests (uint64_t fabricId, void (^completion)(id _Nullable controller, NSError * _Nullable error)); @property (readwrite, strong) void (^handleGetAnySharedRemoteController) (void (^completion)(id _Nullable controller, NSError * _Nullable error)); -@property (readwrite, strong) void (^handleReadAttribute)(id controller, uint64_t nodeId, NSUInteger endpointId, - NSUInteger clusterId, NSUInteger attributeId, void (^completion)(id _Nullable values, NSError * _Nullable error)); -@property (readwrite, strong) void (^handleWriteAttribute)(id controller, uint64_t nodeId, NSUInteger endpointId, - NSUInteger clusterId, NSUInteger attributeId, id value, void (^completion)(id _Nullable values, NSError * _Nullable error)); -@property (readwrite, strong) void (^handleInvokeCommand)(id controller, uint64_t nodeId, NSUInteger endpointId, - NSUInteger clusterId, NSUInteger commandId, id fields, void (^completion)(id _Nullable values, NSError * _Nullable error)); -@property (readwrite, strong) void (^handleSubscribeAttribute)(id controller, uint64_t nodeId, NSUInteger endpointId, - NSUInteger clusterId, NSUInteger attributeId, NSUInteger minInterval, NSUInteger maxInterval, void (^establishedHandler)(void)); +@property (readwrite, strong) void (^handleReadAttribute)(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, + NSNumber * _Nullable clusterId, NSNumber * _Nullable attributeId, CHIPReadParams * _Nullable params, + void (^completion)(id _Nullable values, NSError * _Nullable error)); +@property (readwrite, strong) void (^handleWriteAttribute) + (id controller, uint64_t nodeId, NSNumber * endpointId, NSNumber * clusterId, NSNumber * attributeId, id value, + NSNumber * _Nullable timedWriteTimeout, void (^completion)(id _Nullable values, NSError * _Nullable error)); +@property (readwrite, strong) void (^handleInvokeCommand) + (id controller, uint64_t nodeId, NSNumber * endpointId, NSNumber * clusterId, NSNumber * commandId, id fields, + NSNumber * _Nullable timedInvokeTimeout, void (^completion)(id _Nullable values, NSError * _Nullable error)); +@property (readwrite, strong) void (^handleSubscribeAttribute)(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, + NSNumber * _Nullable clusterId, NSNumber * _Nullable attributeId, NSNumber * minInterval, NSNumber * maxInterval, + CHIPSubscribeParams * _Nullable params, void (^establishedHandler)(void)); +@property (readwrite, strong) void (^handleStopReports)(id controller, uint64_t nodeId, void (^completion)(void)); @property (readwrite, strong) void (^handleSubscribeAttributeCache) - (id controller, uint64_t nodeId, void (^completion)(NSError * _Nullable error)); -@property (readwrite, strong) void (^handleReadAttributeCache)(id controller, uint64_t nodeId, NSUInteger endpointId, - NSUInteger clusterId, NSUInteger attributeId, void (^completion)(id _Nullable values, NSError * _Nullable error)); + (id controller, uint64_t nodeId, CHIPSubscribeParams * _Nullable params, void (^completion)(NSError * _Nullable error)); +@property (readwrite, strong) void (^handleReadAttributeCache) + (id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, void (^completion)(id _Nullable values, NSError * _Nullable error)); @end @@ -147,76 +153,90 @@ - (void)getAnyDeviceControllerWithCompletion:(void (^)(id _Nullable controller, - (void)readAttributeWithController:(id)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId + endpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId + params:(NSDictionary * _Nullable)params completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion { dispatch_async(dispatch_get_main_queue(), ^{ XCTAssertNotNil(self.handleReadAttribute); - self.handleReadAttribute(controller, nodeId, endpointId, clusterId, attributeId, completion); + self.handleReadAttribute( + controller, nodeId, endpointId, clusterId, attributeId, [CHIPDeviceController decodeXPCReadParams:params], completion); }); } - (void)writeAttributeWithController:(id)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId + endpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + attributeId:(NSNumber *)attributeId value:(id)value + timedWriteTimeout:(NSNumber * _Nullable)timeoutMs completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion { dispatch_async(dispatch_get_main_queue(), ^{ XCTAssertNotNil(self.handleWriteAttribute); - self.handleWriteAttribute(controller, nodeId, endpointId, clusterId, attributeId, value, completion); + self.handleWriteAttribute(controller, nodeId, endpointId, clusterId, attributeId, value, timeoutMs, completion); }); } - (void)invokeCommandWithController:(id)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - commandId:(NSUInteger)commandId + endpointId:(NSNumber *)endpointId + clusterId:(NSNumber *)clusterId + commandId:(NSNumber *)commandId fields:(id)fields + timedInvokeTimeout:(NSNumber * _Nullable)timeoutMs completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion { dispatch_async(dispatch_get_main_queue(), ^{ XCTAssertNotNil(self.handleInvokeCommand); - self.handleInvokeCommand(controller, nodeId, endpointId, clusterId, commandId, fields, completion); + self.handleInvokeCommand(controller, nodeId, endpointId, clusterId, commandId, fields, timeoutMs, completion); }); } - (void)subscribeAttributeWithController:(id)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId - minInterval:(NSUInteger)minInterval - maxInterval:(NSUInteger)maxInterval + endpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId + minInterval:(NSNumber *)minInterval + maxInterval:(NSNumber *)maxInterval + params:(NSDictionary * _Nullable)params establishedHandler:(void (^)(void))establishedHandler { dispatch_async(dispatch_get_main_queue(), ^{ XCTAssertNotNil(self.handleSubscribeAttribute); - self.handleSubscribeAttribute( - controller, nodeId, endpointId, clusterId, attributeId, minInterval, maxInterval, establishedHandler); + self.handleSubscribeAttribute(controller, nodeId, endpointId, clusterId, attributeId, minInterval, maxInterval, + [CHIPDeviceController decodeXPCSubscribeParams:params], establishedHandler); + }); +} + +- (void)stopReportsWithController:(id)controller nodeId:(uint64_t)nodeId completion:(void (^)(void))completion +{ + dispatch_async(dispatch_get_main_queue(), ^{ + XCTAssertNotNil(self.handleStopReports); + self.handleStopReports(controller, nodeId, completion); }); } - (void)subscribeAttributeCacheWithController:(id _Nullable)controller nodeId:(uint64_t)nodeId + params:(NSDictionary * _Nullable)params completion:(void (^)(NSError * _Nullable error))completion { dispatch_async(dispatch_get_main_queue(), ^{ XCTAssertNotNil(self.handleSubscribeAttributeCache); - self.handleSubscribeAttributeCache(controller, nodeId, completion); + self.handleSubscribeAttributeCache(controller, nodeId, [CHIPDeviceController decodeXPCSubscribeParams:params], completion); }); } - (void)readAttributeCacheWithController:(id _Nullable)controller nodeId:(uint64_t)nodeId - endpointId:(NSUInteger)endpointId - clusterId:(NSUInteger)clusterId - attributeId:(NSUInteger)attributeId + endpointId:(NSNumber * _Nullable)endpointId + clusterId:(NSNumber * _Nullable)clusterId + attributeId:(NSNumber * _Nullable)attributeId completion:(void (^)(id _Nullable values, NSError * _Nullable error))completion { dispatch_async(dispatch_get_main_queue(), ^{ @@ -253,27 +273,91 @@ - (void)tearDown - (void)testReadAttributeSuccess { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; + NSArray * myValues = @[ @{ + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], + @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } + } ]; + + XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; + XCTestExpectation * responseExpectation = [self expectationWithDescription:@"XPC response received"]; + + __auto_type uuid = self.controllerUUID; + _handleReadAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, CHIPReadParams * _Nullable params, + void (^completion)(id _Nullable values, NSError * _Nullable error)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertNil(params); + [callExpectation fulfill]; + completion([CHIPDeviceController encodeXPCResponseValues:myValues], nil); + }; + + [_remoteDeviceController getConnectedDevice:myNodeId + queue:dispatch_get_main_queue() + completionHandler:^(CHIPDevice * _Nullable device, NSError * _Nullable error) { + XCTAssertNotNil(device); + XCTAssertNil(error); + NSLog(@"Device acquired. Reading..."); + [device readAttributeWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId + params:nil + clientQueue:dispatch_get_main_queue() + completion:^(id _Nullable value, NSError * _Nullable error) { + NSLog(@"Read value: %@", value); + XCTAssertNotNil(value); + XCTAssertNil(error); + XCTAssertTrue([myValues isEqualTo:value]); + [responseExpectation fulfill]; + self.xpcDisconnectExpectation = + [self expectationWithDescription:@"XPC Disconnected"]; + }]; + }]; + + [self waitForExpectations:[NSArray arrayWithObjects:callExpectation, responseExpectation, nil] timeout:kTimeoutInSeconds]; + + // When read is done, connection should have been released + [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + XCTAssertNil(_xpcConnection); +} + +- (void)testReadAttributeWithParamsSuccess +{ + uint64_t myNodeId = 9876543210; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; NSArray * myValues = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } } ]; + CHIPReadParams * myParams = [[CHIPReadParams alloc] init]; + myParams.fabricFiltered = @NO; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; XCTestExpectation * responseExpectation = [self expectationWithDescription:@"XPC response received"]; __auto_type uuid = self.controllerUUID; - _handleReadAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, NSUInteger attributeId, + _handleReadAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, CHIPReadParams * _Nullable params, void (^completion)(id _Nullable values, NSError * _Nullable error)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertNotNil(params); + XCTAssertEqual([params.fabricFiltered boolValue], [myParams.fabricFiltered boolValue]); [callExpectation fulfill]; completion([CHIPDeviceController encodeXPCResponseValues:myValues], nil); }; @@ -287,6 +371,7 @@ - (void)testReadAttributeSuccess [device readAttributeWithEndpointId:myEndpointId clusterId:myClusterId attributeId:myAttributeId + params:myParams clientQueue:dispatch_get_main_queue() completion:^(id _Nullable value, NSError * _Nullable error) { NSLog(@"Read value: %@", value); @@ -309,21 +394,23 @@ - (void)testReadAttributeSuccess - (void)testReadAttributeFailure { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; NSError * myError = [NSError errorWithDomain:CHIPErrorDomain code:CHIPErrorCodeGeneralError userInfo:nil]; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; XCTestExpectation * responseExpectation = [self expectationWithDescription:@"XPC response received"]; __auto_type uuid = self.controllerUUID; - _handleReadAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, NSUInteger attributeId, + _handleReadAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, CHIPReadParams * _Nullable params, void (^completion)(id _Nullable values, NSError * _Nullable error)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertNil(params); [callExpectation fulfill]; completion(nil, myError); }; @@ -337,6 +424,7 @@ - (void)testReadAttributeFailure [device readAttributeWithEndpointId:myEndpointId clusterId:myClusterId attributeId:myAttributeId + params:nil clientQueue:dispatch_get_main_queue() completion:^(id _Nullable value, NSError * _Nullable error) { NSLog(@"Read value: %@", value); @@ -358,29 +446,30 @@ - (void)testReadAttributeFailure - (void)testWriteAttributeSuccess { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; NSDictionary * myValue = [NSDictionary dictionaryWithObjectsAndKeys:@"UnsignedInteger", @"type", [NSNumber numberWithInteger:654321], @"value", nil]; NSArray * myResults = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]] + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId] } ]; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; XCTestExpectation * responseExpectation = [self expectationWithDescription:@"XPC response received"]; __auto_type uuid = self.controllerUUID; - _handleWriteAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, NSUInteger attributeId, - id value, void (^completion)(id _Nullable values, NSError * _Nullable error)) { + _handleWriteAttribute = ^(id controller, uint64_t nodeId, NSNumber * endpointId, NSNumber * clusterId, NSNumber * attributeId, + id value, NSNumber * _Nullable timedWriteTimeout, void (^completion)(id _Nullable values, NSError * _Nullable error)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); XCTAssertTrue([value isEqualTo:myValue]); + XCTAssertNil(timedWriteTimeout); [callExpectation fulfill]; completion([CHIPDeviceController encodeXPCResponseValues:myResults], nil); }; @@ -395,6 +484,70 @@ - (void)testWriteAttributeSuccess clusterId:myClusterId attributeId:myAttributeId value:myValue + timedWriteTimeout:nil + clientQueue:dispatch_get_main_queue() + completion:^(id _Nullable value, NSError * _Nullable error) { + NSLog(@"Write response: %@", value); + XCTAssertNotNil(value); + XCTAssertNil(error); + XCTAssertTrue([myResults isEqualTo:value]); + [responseExpectation fulfill]; + self.xpcDisconnectExpectation = + [self expectationWithDescription:@"XPC Disconnected"]; + }]; + }]; + + [self waitForExpectations:[NSArray arrayWithObjects:callExpectation, responseExpectation, nil] timeout:kTimeoutInSeconds]; + + // When write is done, connection should have been released + [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + XCTAssertNil(_xpcConnection); +} + +- (void)testTimedWriteAttributeSuccess +{ + uint64_t myNodeId = 9876543210; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; + NSDictionary * myValue = + [NSDictionary dictionaryWithObjectsAndKeys:@"UnsignedInteger", @"type", [NSNumber numberWithInteger:654321], @"value", nil]; + NSNumber * myTimedWriteTimeout = @1234; + NSArray * myResults = @[ @{ + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId] + } ]; + + XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; + XCTestExpectation * responseExpectation = [self expectationWithDescription:@"XPC response received"]; + + __auto_type uuid = self.controllerUUID; + _handleWriteAttribute = ^(id controller, uint64_t nodeId, NSNumber * endpointId, NSNumber * clusterId, NSNumber * attributeId, + id value, NSNumber * _Nullable timedWriteTimeout, void (^completion)(id _Nullable values, NSError * _Nullable error)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertTrue([value isEqualTo:myValue]); + XCTAssertNotNil(timedWriteTimeout); + XCTAssertEqual([timedWriteTimeout unsignedShortValue], [myTimedWriteTimeout unsignedShortValue]); + [callExpectation fulfill]; + completion([CHIPDeviceController encodeXPCResponseValues:myResults], nil); + }; + + [_remoteDeviceController getConnectedDevice:myNodeId + queue:dispatch_get_main_queue() + completionHandler:^(CHIPDevice * _Nullable device, NSError * _Nullable error) { + XCTAssertNotNil(device); + XCTAssertNil(error); + NSLog(@"Device acquired. Writing..."); + [device writeAttributeWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId + value:myValue + timedWriteTimeout:myTimedWriteTimeout clientQueue:dispatch_get_main_queue() completion:^(id _Nullable value, NSError * _Nullable error) { NSLog(@"Write response: %@", value); @@ -417,9 +570,9 @@ - (void)testWriteAttributeSuccess - (void)testWriteAttributeFailure { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; NSDictionary * myValue = [NSDictionary dictionaryWithObjectsAndKeys:@"UnsignedInteger", @"type", [NSNumber numberWithInteger:654321], @"value", nil]; NSError * myError = [NSError errorWithDomain:CHIPErrorDomain code:CHIPErrorCodeGeneralError userInfo:nil]; @@ -427,14 +580,15 @@ - (void)testWriteAttributeFailure XCTestExpectation * responseExpectation = [self expectationWithDescription:@"XPC response received"]; __auto_type uuid = self.controllerUUID; - _handleWriteAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, NSUInteger attributeId, - id value, void (^completion)(id _Nullable values, NSError * _Nullable error)) { + _handleWriteAttribute = ^(id controller, uint64_t nodeId, NSNumber * endpointId, NSNumber * clusterId, NSNumber * attributeId, + id value, NSNumber * _Nullable timedWriteTimeout, void (^completion)(id _Nullable values, NSError * _Nullable error)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); XCTAssertTrue([value isEqualTo:myValue]); + XCTAssertNil(timedWriteTimeout); [callExpectation fulfill]; completion(nil, myError); }; @@ -449,6 +603,7 @@ - (void)testWriteAttributeFailure clusterId:myClusterId attributeId:myAttributeId value:myValue + timedWriteTimeout:nil clientQueue:dispatch_get_main_queue() completion:^(id _Nullable value, NSError * _Nullable error) { NSLog(@"Write response: %@", value); @@ -470,33 +625,33 @@ - (void)testWriteAttributeFailure - (void)testInvokeCommandSuccess { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myCommandId = 300; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myCommandId = @300; NSDictionary * myFields = [NSDictionary dictionaryWithObjectsAndKeys:@"Structure", @"type", [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Float", @"Type", [NSNumber numberWithFloat:1.0], @"value", nil]], @"value", nil]; - NSArray * myResults = @[ @{ - @"commandPath" : [CHIPCommandPath commandPathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - commandId:[NSNumber numberWithUnsignedInteger:myCommandId]] - } ]; + NSArray * myResults = @[ + @{ @"commandPath" : [CHIPCommandPath commandPathWithEndpointId:myEndpointId clusterId:myClusterId commandId:myCommandId] } + ]; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; XCTestExpectation * responseExpectation = [self expectationWithDescription:@"XPC response received"]; __auto_type uuid = self.controllerUUID; - _handleInvokeCommand = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, NSUInteger commandId, - id commandFields, void (^completion)(id _Nullable values, NSError * _Nullable error)) { - XCTAssertTrue([controller isEqualToString:uuid]); - XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(commandId, myCommandId); - XCTAssertTrue([commandFields isEqualTo:myFields]); - [callExpectation fulfill]; - completion([CHIPDeviceController encodeXPCResponseValues:myResults], nil); - }; + _handleInvokeCommand + = ^(id controller, uint64_t nodeId, NSNumber * endpointId, NSNumber * clusterId, NSNumber * commandId, id commandFields, + NSNumber * _Nullable timedInvokeTimeout, void (^completion)(id _Nullable values, NSError * _Nullable error)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([commandId unsignedLongValue], [myCommandId unsignedLongValue]); + XCTAssertTrue([commandFields isEqualTo:myFields]); + XCTAssertNil(timedInvokeTimeout); + [callExpectation fulfill]; + completion([CHIPDeviceController encodeXPCResponseValues:myResults], nil); + }; [_remoteDeviceController getConnectedDevice:myNodeId queue:dispatch_get_main_queue() @@ -508,6 +663,70 @@ - (void)testInvokeCommandSuccess clusterId:myClusterId commandId:myCommandId commandFields:myFields + timedInvokeTimeout:nil + clientQueue:dispatch_get_main_queue() + completion:^(id _Nullable value, NSError * _Nullable error) { + NSLog(@"Command response: %@", value); + XCTAssertNotNil(value); + XCTAssertNil(error); + XCTAssertTrue([myResults isEqualTo:value]); + [responseExpectation fulfill]; + self.xpcDisconnectExpectation = + [self expectationWithDescription:@"XPC Disconnected"]; + }]; + }]; + + [self waitForExpectations:[NSArray arrayWithObjects:callExpectation, responseExpectation, nil] timeout:kTimeoutInSeconds]; + + // When command is done, connection should have been released + [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + XCTAssertNil(_xpcConnection); +} + +- (void)testTimedInvokeCommandSuccess +{ + uint64_t myNodeId = 9876543210; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myCommandId = @300; + NSNumber * myTimedInvokeTimeout = @5678; + NSDictionary * myFields = [NSDictionary dictionaryWithObjectsAndKeys:@"Structure", @"type", + [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Float", @"Type", + [NSNumber numberWithFloat:1.0], @"value", nil]], + @"value", nil]; + NSArray * myResults = @[ + @{ @"commandPath" : [CHIPCommandPath commandPathWithEndpointId:myEndpointId clusterId:myClusterId commandId:myCommandId] } + ]; + XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; + XCTestExpectation * responseExpectation = [self expectationWithDescription:@"XPC response received"]; + + __auto_type uuid = self.controllerUUID; + _handleInvokeCommand + = ^(id controller, uint64_t nodeId, NSNumber * endpointId, NSNumber * clusterId, NSNumber * commandId, id commandFields, + NSNumber * _Nullable timedInvokeTimeout, void (^completion)(id _Nullable values, NSError * _Nullable error)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([commandId unsignedLongValue], [myCommandId unsignedLongValue]); + XCTAssertTrue([commandFields isEqualTo:myFields]); + XCTAssertNotNil(timedInvokeTimeout); + XCTAssertEqual([timedInvokeTimeout unsignedShortValue], [myTimedInvokeTimeout unsignedShortValue]); + [callExpectation fulfill]; + completion([CHIPDeviceController encodeXPCResponseValues:myResults], nil); + }; + + [_remoteDeviceController getConnectedDevice:myNodeId + queue:dispatch_get_main_queue() + completionHandler:^(CHIPDevice * _Nullable device, NSError * _Nullable error) { + XCTAssertNotNil(device); + XCTAssertNil(error); + NSLog(@"Device acquired. Invoking command..."); + [device invokeCommandWithEndpointId:myEndpointId + clusterId:myClusterId + commandId:myCommandId + commandFields:myFields + timedInvokeTimeout:myTimedInvokeTimeout clientQueue:dispatch_get_main_queue() completion:^(id _Nullable value, NSError * _Nullable error) { NSLog(@"Command response: %@", value); @@ -530,9 +749,9 @@ - (void)testInvokeCommandSuccess - (void)testInvokeCommandFailure { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myCommandId = 300; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myCommandId = @300; NSDictionary * myFields = [NSDictionary dictionaryWithObjectsAndKeys:@"Structure", @"type", [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:@"Float", @"Type", [NSNumber numberWithFloat:1.0], @"value", nil]], @@ -542,17 +761,19 @@ - (void)testInvokeCommandFailure XCTestExpectation * responseExpectation = [self expectationWithDescription:@"XPC response received"]; __auto_type uuid = self.controllerUUID; - _handleInvokeCommand = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, NSUInteger commandId, - id commandFields, void (^completion)(id _Nullable values, NSError * _Nullable error)) { - XCTAssertTrue([controller isEqualToString:uuid]); - XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(commandId, myCommandId); - XCTAssertTrue([commandFields isEqualTo:myFields]); - [callExpectation fulfill]; - completion(nil, myError); - }; + _handleInvokeCommand + = ^(id controller, uint64_t nodeId, NSNumber * endpointId, NSNumber * clusterId, NSNumber * commandId, id commandFields, + NSNumber * _Nullable timedInvokeTimeout, void (^completion)(id _Nullable values, NSError * _Nullable error)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([commandId unsignedLongValue], [myCommandId unsignedLongValue]); + XCTAssertTrue([commandFields isEqualTo:myFields]); + XCTAssertNil(timedInvokeTimeout); + [callExpectation fulfill]; + completion(nil, myError); + }; [_remoteDeviceController getConnectedDevice:myNodeId queue:dispatch_get_main_queue() @@ -564,6 +785,7 @@ - (void)testInvokeCommandFailure clusterId:myClusterId commandId:myCommandId commandFields:myFields + timedInvokeTimeout:nil clientQueue:dispatch_get_main_queue() completion:^(id _Nullable value, NSError * _Nullable error) { NSLog(@"Command response: %@", value); @@ -585,15 +807,15 @@ - (void)testInvokeCommandFailure - (void)testSubscribeAttributeSuccess { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; - NSUInteger myMinInterval = 5; - NSUInteger myMaxInterval = 60; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; + NSNumber * myMinInterval = @5; + NSNumber * myMaxInterval = @60; __block NSArray * myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } } ]; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; @@ -601,15 +823,17 @@ - (void)testSubscribeAttributeSuccess __block XCTestExpectation * reportExpectation = [self expectationWithDescription:@"Report sent"]; __auto_type uuid = self.controllerUUID; - _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, - NSUInteger attributeId, NSUInteger minInterval, NSUInteger maxInterval, void (^establishedHandler)(void)) { + _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, NSNumber * minInterval, NSNumber * maxInterval, CHIPSubscribeParams * _Nullable params, + void (^establishedHandler)(void)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); - XCTAssertEqual(minInterval, myMinInterval); - XCTAssertEqual(maxInterval, myMaxInterval); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertEqual([minInterval unsignedShortValue], [myMinInterval unsignedShortValue]); + XCTAssertEqual([maxInterval unsignedShortValue], [myMaxInterval unsignedShortValue]); + XCTAssertNil(params); [callExpectation fulfill]; establishedHandler(); }; @@ -628,6 +852,7 @@ - (void)testSubscribeAttributeSuccess attributeId:myAttributeId minInterval:myMinInterval maxInterval:myMaxInterval + params:nil clientQueue:dispatch_get_main_queue() reportHandler:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Report value: %@", values); @@ -656,9 +881,9 @@ - (void)testSubscribeAttributeSuccess // Inject another report reportExpectation = [self expectationWithDescription:@"2nd report sent"]; myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @771234 } } ]; [clientObject handleReportWithController:uuid @@ -669,6 +894,15 @@ - (void)testSubscribeAttributeSuccess // Wait for report [self waitForExpectations:[NSArray arrayWithObject:reportExpectation] timeout:kTimeoutInSeconds]; + // Setup stop report handler + XCTestExpectation * stopExpectation = [self expectationWithDescription:@"Reports stopped"]; + _handleStopReports = ^(id _Nullable controller, uint64_t nodeId, void (^completion)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + completion(); + [stopExpectation fulfill]; + }; + // Deregister report handler [_remoteDeviceController getConnectedDevice:myNodeId queue:dispatch_get_main_queue() @@ -681,24 +915,141 @@ - (void)testSubscribeAttributeSuccess }]; // Wait for disconnection - [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + [self waitForExpectations:@[ _xpcDisconnectExpectation, stopExpectation ] timeout:kTimeoutInSeconds]; + XCTAssertNil(_xpcConnection); +} + +- (void)testSubscribeAttributeWithParamsSuccess +{ + uint64_t myNodeId = 9876543210; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; + NSNumber * myMinInterval = @5; + NSNumber * myMaxInterval = @60; + CHIPSubscribeParams * myParams = [[CHIPSubscribeParams alloc] init]; + myParams.fabricFiltered = @NO; + myParams.keepPreviousSubscriptions = @NO; + __block NSArray * myReport = @[ @{ + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], + @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } + } ]; + XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; + XCTestExpectation * establishExpectation = [self expectationWithDescription:@"Established called"]; + __block XCTestExpectation * reportExpectation = [self expectationWithDescription:@"Report sent"]; + + __auto_type uuid = self.controllerUUID; + _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, NSNumber * minInterval, NSNumber * maxInterval, CHIPSubscribeParams * _Nullable params, + void (^establishedHandler)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertEqual([minInterval unsignedShortValue], [myMinInterval unsignedShortValue]); + XCTAssertEqual([maxInterval unsignedShortValue], [myMaxInterval unsignedShortValue]); + XCTAssertNotNil(params); + XCTAssertEqual([params.fabricFiltered boolValue], [myParams.fabricFiltered boolValue]); + XCTAssertEqual([params.keepPreviousSubscriptions boolValue], [myParams.keepPreviousSubscriptions boolValue]); + [callExpectation fulfill]; + establishedHandler(); + }; + + _xpcDisconnectExpectation = [self expectationWithDescription:@"XPC Disconnected"]; + + [_remoteDeviceController + getConnectedDevice:myNodeId + queue:dispatch_get_main_queue() + completionHandler:^(CHIPDevice * _Nullable device, NSError * _Nullable error) { + XCTAssertNotNil(device); + XCTAssertNil(error); + NSLog(@"Device acquired. Subscribing..."); + [device subscribeAttributeWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId + minInterval:myMinInterval + maxInterval:myMaxInterval + params:myParams + clientQueue:dispatch_get_main_queue() + reportHandler:^(NSArray *> * _Nullable values, NSError * _Nullable error) { + NSLog(@"Report value: %@", values); + XCTAssertNotNil(values); + XCTAssertNil(error); + XCTAssertTrue([myReport isEqualTo:values]); + [reportExpectation fulfill]; + } + subscriptionEstablished:^{ + [establishExpectation fulfill]; + }]; + }]; + + [self waitForExpectations:[NSArray arrayWithObjects:callExpectation, establishExpectation, nil] timeout:kTimeoutInSeconds]; + + // Inject report + id clientObject = _xpcConnection.remoteObjectProxy; + [clientObject handleReportWithController:uuid + nodeId:myNodeId + values:[CHIPDeviceController encodeXPCResponseValues:myReport] + error:nil]; + + // Wait for report + [self waitForExpectations:[NSArray arrayWithObject:reportExpectation] timeout:kTimeoutInSeconds]; + + // Inject another report + reportExpectation = [self expectationWithDescription:@"2nd report sent"]; + myReport = @[ @{ + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], + @"data" : @ { @"type" : @"SignedInteger", @"value" : @771234 } + } ]; + [clientObject handleReportWithController:uuid + nodeId:myNodeId + values:[CHIPDeviceController encodeXPCResponseValues:myReport] + error:nil]; + + // Wait for report + [self waitForExpectations:[NSArray arrayWithObject:reportExpectation] timeout:kTimeoutInSeconds]; + + // Setup stop report handler + XCTestExpectation * stopExpectation = [self expectationWithDescription:@"Reports stopped"]; + _handleStopReports = ^(id _Nullable controller, uint64_t nodeId, void (^completion)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + completion(); + [stopExpectation fulfill]; + }; + + // Deregister report handler + [_remoteDeviceController getConnectedDevice:myNodeId + queue:dispatch_get_main_queue() + completionHandler:^(CHIPDevice * _Nullable device, NSError * _Nullable error) { + NSLog(@"Device acquired. Deregistering..."); + [device deregisterReportHandlersWithClientQueue:dispatch_get_main_queue() + completion:^{ + NSLog(@"Deregistered"); + }]; + }]; + + // Wait for disconnection + [self waitForExpectations:@[ _xpcDisconnectExpectation, stopExpectation ] timeout:kTimeoutInSeconds]; XCTAssertNil(_xpcConnection); } - (void)testBadlyFormattedReport { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; - NSUInteger myMinInterval = 5; - NSUInteger myMaxInterval = 60; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; + NSNumber * myMinInterval = @5; + NSNumber * myMaxInterval = @60; // Incorrect serialized report value. Report should have ben a single NSDictionary __block id myReport = @{ - @"attributePath" : @[ - [NSNumber numberWithUnsignedInteger:myEndpointId], [NSNumber numberWithUnsignedInteger:myClusterId], - [NSNumber numberWithUnsignedInteger:myAttributeId] - ], + @"attributePath" : @[ myEndpointId, myClusterId, myAttributeId ], @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } }; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; @@ -707,15 +1058,17 @@ - (void)testBadlyFormattedReport reportExpectation.inverted = YES; __auto_type uuid = self.controllerUUID; - _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, - NSUInteger attributeId, NSUInteger minInterval, NSUInteger maxInterval, void (^establishedHandler)(void)) { + _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, NSNumber * minInterval, NSNumber * maxInterval, CHIPSubscribeParams * _Nullable params, + void (^establishedHandler)(void)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); - XCTAssertEqual(minInterval, myMinInterval); - XCTAssertEqual(maxInterval, myMaxInterval); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertEqual([minInterval unsignedShortValue], [myMinInterval unsignedShortValue]); + XCTAssertEqual([maxInterval unsignedShortValue], [myMaxInterval unsignedShortValue]); + XCTAssertNil(params); [callExpectation fulfill]; establishedHandler(); }; @@ -734,6 +1087,7 @@ - (void)testBadlyFormattedReport attributeId:myAttributeId minInterval:myMinInterval maxInterval:myMaxInterval + params:nil clientQueue:dispatch_get_main_queue() reportHandler:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Report value: %@", values); @@ -759,9 +1113,9 @@ - (void)testBadlyFormattedReport // Inject another report reportExpectation = [self expectationWithDescription:@"Report sent"]; myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @771234 } } ]; [clientObject handleReportWithController:uuid @@ -772,6 +1126,15 @@ - (void)testBadlyFormattedReport // Wait for report [self waitForExpectations:[NSArray arrayWithObject:reportExpectation] timeout:kTimeoutInSeconds]; + // Setup stop report handler + XCTestExpectation * stopExpectation = [self expectationWithDescription:@"Reports stopped"]; + _handleStopReports = ^(id _Nullable controller, uint64_t nodeId, void (^completion)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + completion(); + [stopExpectation fulfill]; + }; + // Deregister report handler _xpcDisconnectExpectation.inverted = NO; [_remoteDeviceController getConnectedDevice:myNodeId @@ -785,22 +1148,22 @@ - (void)testBadlyFormattedReport }]; // Wait for disconnection - [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + [self waitForExpectations:@[ _xpcDisconnectExpectation, stopExpectation ] timeout:kTimeoutInSeconds]; XCTAssertNil(_xpcConnection); } - (void)testReportWithUnrelatedEndpointId { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; - NSUInteger myMinInterval = 5; - NSUInteger myMaxInterval = 60; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; + NSNumber * myMinInterval = @5; + NSNumber * myMaxInterval = @60; __block NSArray * myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId + 1] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:@([myEndpointId unsignedShortValue] + 1) + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } } ]; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; @@ -809,15 +1172,17 @@ - (void)testReportWithUnrelatedEndpointId reportExpectation.inverted = YES; __auto_type uuid = self.controllerUUID; - _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, - NSUInteger attributeId, NSUInteger minInterval, NSUInteger maxInterval, void (^establishedHandler)(void)) { + _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, NSNumber * minInterval, NSNumber * maxInterval, CHIPSubscribeParams * _Nullable params, + void (^establishedHandler)(void)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); - XCTAssertEqual(minInterval, myMinInterval); - XCTAssertEqual(maxInterval, myMaxInterval); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertEqual([minInterval unsignedShortValue], [myMinInterval unsignedShortValue]); + XCTAssertEqual([maxInterval unsignedShortValue], [myMaxInterval unsignedShortValue]); + XCTAssertNil(params); [callExpectation fulfill]; establishedHandler(); }; @@ -836,6 +1201,7 @@ - (void)testReportWithUnrelatedEndpointId attributeId:myAttributeId minInterval:myMinInterval maxInterval:myMaxInterval + params:nil clientQueue:dispatch_get_main_queue() reportHandler:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Report value: %@", values); @@ -864,9 +1230,9 @@ - (void)testReportWithUnrelatedEndpointId // Inject another report reportExpectation = [self expectationWithDescription:@"2nd report sent"]; myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @771234 } } ]; [clientObject handleReportWithController:uuid @@ -877,6 +1243,15 @@ - (void)testReportWithUnrelatedEndpointId // Wait for report [self waitForExpectations:[NSArray arrayWithObject:reportExpectation] timeout:kTimeoutInSeconds]; + // Setup stop report handler + XCTestExpectation * stopExpectation = [self expectationWithDescription:@"Reports stopped"]; + _handleStopReports = ^(id _Nullable controller, uint64_t nodeId, void (^completion)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + completion(); + [stopExpectation fulfill]; + }; + // Deregister report handler [_remoteDeviceController getConnectedDevice:myNodeId queue:dispatch_get_main_queue() @@ -889,22 +1264,22 @@ - (void)testReportWithUnrelatedEndpointId }]; // Wait for disconnection - [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + [self waitForExpectations:@[ _xpcDisconnectExpectation, stopExpectation ] timeout:kTimeoutInSeconds]; XCTAssertNil(_xpcConnection); } - (void)testReportWithUnrelatedClusterId { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; - NSUInteger myMinInterval = 5; - NSUInteger myMaxInterval = 60; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; + NSNumber * myMinInterval = @5; + NSNumber * myMaxInterval = @60; __block NSArray * myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId + 1] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:@([myClusterId unsignedLongValue] + 1) + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } } ]; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; @@ -913,15 +1288,17 @@ - (void)testReportWithUnrelatedClusterId reportExpectation.inverted = YES; __auto_type uuid = self.controllerUUID; - _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, - NSUInteger attributeId, NSUInteger minInterval, NSUInteger maxInterval, void (^establishedHandler)(void)) { + _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, NSNumber * minInterval, NSNumber * maxInterval, CHIPSubscribeParams * _Nullable params, + void (^establishedHandler)(void)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); - XCTAssertEqual(minInterval, myMinInterval); - XCTAssertEqual(maxInterval, myMaxInterval); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertEqual([minInterval unsignedShortValue], [myMinInterval unsignedShortValue]); + XCTAssertEqual([maxInterval unsignedShortValue], [myMaxInterval unsignedShortValue]); + XCTAssertNil(params); [callExpectation fulfill]; establishedHandler(); }; @@ -940,6 +1317,7 @@ - (void)testReportWithUnrelatedClusterId attributeId:myAttributeId minInterval:myMinInterval maxInterval:myMaxInterval + params:nil clientQueue:dispatch_get_main_queue() reportHandler:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Report value: %@", values); @@ -968,9 +1346,9 @@ - (void)testReportWithUnrelatedClusterId // Inject another report reportExpectation = [self expectationWithDescription:@"2nd report sent"]; myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @771234 } } ]; [clientObject handleReportWithController:uuid @@ -981,6 +1359,15 @@ - (void)testReportWithUnrelatedClusterId // Wait for report [self waitForExpectations:[NSArray arrayWithObject:reportExpectation] timeout:kTimeoutInSeconds]; + // Setup stop report handler + XCTestExpectation * stopExpectation = [self expectationWithDescription:@"Reports stopped"]; + _handleStopReports = ^(id _Nullable controller, uint64_t nodeId, void (^completion)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + completion(); + [stopExpectation fulfill]; + }; + // Deregister report handler [_remoteDeviceController getConnectedDevice:myNodeId queue:dispatch_get_main_queue() @@ -993,22 +1380,22 @@ - (void)testReportWithUnrelatedClusterId }]; // Wait for disconnection - [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + [self waitForExpectations:@[ _xpcDisconnectExpectation, stopExpectation ] timeout:kTimeoutInSeconds]; XCTAssertNil(_xpcConnection); } - (void)testReportWithUnrelatedAttributeId { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; - NSUInteger myMinInterval = 5; - NSUInteger myMaxInterval = 60; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; + NSNumber * myMinInterval = @5; + NSNumber * myMaxInterval = @60; __block NSArray * myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId + 1]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:@([myAttributeId unsignedLongValue] + 1)], @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } } ]; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; @@ -1017,15 +1404,17 @@ - (void)testReportWithUnrelatedAttributeId reportExpectation.inverted = YES; __auto_type uuid = self.controllerUUID; - _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, - NSUInteger attributeId, NSUInteger minInterval, NSUInteger maxInterval, void (^establishedHandler)(void)) { + _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, NSNumber * minInterval, NSNumber * maxInterval, CHIPSubscribeParams * _Nullable params, + void (^establishedHandler)(void)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); - XCTAssertEqual(minInterval, myMinInterval); - XCTAssertEqual(maxInterval, myMaxInterval); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertEqual([minInterval unsignedShortValue], [myMinInterval unsignedShortValue]); + XCTAssertEqual([maxInterval unsignedShortValue], [myMaxInterval unsignedShortValue]); + XCTAssertNil(params); [callExpectation fulfill]; establishedHandler(); }; @@ -1044,6 +1433,7 @@ - (void)testReportWithUnrelatedAttributeId attributeId:myAttributeId minInterval:myMinInterval maxInterval:myMaxInterval + params:nil clientQueue:dispatch_get_main_queue() reportHandler:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Report value: %@", values); @@ -1072,9 +1462,9 @@ - (void)testReportWithUnrelatedAttributeId // Inject another report reportExpectation = [self expectationWithDescription:@"2nd report sent"]; myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @771234 } } ]; [clientObject handleReportWithController:uuid @@ -1085,6 +1475,15 @@ - (void)testReportWithUnrelatedAttributeId // Wait for report [self waitForExpectations:[NSArray arrayWithObject:reportExpectation] timeout:kTimeoutInSeconds]; + // Setup stop report handler + XCTestExpectation * stopExpectation = [self expectationWithDescription:@"Reports stopped"]; + _handleStopReports = ^(id _Nullable controller, uint64_t nodeId, void (^completion)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + completion(); + [stopExpectation fulfill]; + }; + // Deregister report handler [_remoteDeviceController getConnectedDevice:myNodeId queue:dispatch_get_main_queue() @@ -1097,22 +1496,22 @@ - (void)testReportWithUnrelatedAttributeId }]; // Wait for disconnection - [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + [self waitForExpectations:@[ _xpcDisconnectExpectation, stopExpectation ] timeout:kTimeoutInSeconds]; XCTAssertNil(_xpcConnection); } - (void)testReportWithUnrelatedNode { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; - NSUInteger myMinInterval = 5; - NSUInteger myMaxInterval = 60; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; + NSNumber * myMinInterval = @5; + NSNumber * myMaxInterval = @60; __block NSArray * myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } } ]; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; @@ -1121,15 +1520,17 @@ - (void)testReportWithUnrelatedNode reportExpectation.inverted = YES; __auto_type uuid = self.controllerUUID; - _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, - NSUInteger attributeId, NSUInteger minInterval, NSUInteger maxInterval, void (^establishedHandler)(void)) { + _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, NSNumber * minInterval, NSNumber * maxInterval, CHIPSubscribeParams * _Nullable params, + void (^establishedHandler)(void)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); - XCTAssertEqual(minInterval, myMinInterval); - XCTAssertEqual(maxInterval, myMaxInterval); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertEqual([minInterval unsignedShortValue], [myMinInterval unsignedShortValue]); + XCTAssertEqual([maxInterval unsignedShortValue], [myMaxInterval unsignedShortValue]); + XCTAssertNil(params); [callExpectation fulfill]; establishedHandler(); }; @@ -1148,6 +1549,7 @@ - (void)testReportWithUnrelatedNode attributeId:myAttributeId minInterval:myMinInterval maxInterval:myMaxInterval + params:nil clientQueue:dispatch_get_main_queue() reportHandler:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Report value: %@", values); @@ -1176,9 +1578,9 @@ - (void)testReportWithUnrelatedNode // Inject another report reportExpectation = [self expectationWithDescription:@"2nd report sent"]; myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @771234 } } ]; [clientObject handleReportWithController:uuid @@ -1189,6 +1591,15 @@ - (void)testReportWithUnrelatedNode // Wait for report [self waitForExpectations:[NSArray arrayWithObject:reportExpectation] timeout:kTimeoutInSeconds]; + // Setup stop report handler + XCTestExpectation * stopExpectation = [self expectationWithDescription:@"Reports stopped"]; + _handleStopReports = ^(id _Nullable controller, uint64_t nodeId, void (^completion)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + completion(); + [stopExpectation fulfill]; + }; + // Deregister report handler [_remoteDeviceController getConnectedDevice:myNodeId queue:dispatch_get_main_queue() @@ -1201,22 +1612,22 @@ - (void)testReportWithUnrelatedNode }]; // Wait for disconnection - [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + [self waitForExpectations:@[ _xpcDisconnectExpectation, stopExpectation ] timeout:kTimeoutInSeconds]; XCTAssertNil(_xpcConnection); } - (void)testSubscribeMultiEndpoints { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; - NSUInteger myMinInterval = 5; - NSUInteger myMaxInterval = 60; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; + NSNumber * myMinInterval = @5; + NSNumber * myMaxInterval = @60; __block NSArray * myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } } ]; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; @@ -1224,15 +1635,17 @@ - (void)testSubscribeMultiEndpoints __block XCTestExpectation * reportExpectation = [self expectationWithDescription:@"Report sent"]; __auto_type uuid = self.controllerUUID; - _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, - NSUInteger attributeId, NSUInteger minInterval, NSUInteger maxInterval, void (^establishedHandler)(void)) { + _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, NSNumber * minInterval, NSNumber * maxInterval, CHIPSubscribeParams * _Nullable params, + void (^establishedHandler)(void)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, 0xffff); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); - XCTAssertEqual(minInterval, myMinInterval); - XCTAssertEqual(maxInterval, myMaxInterval); + XCTAssertNil(endpointId); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertEqual([minInterval unsignedShortValue], [myMinInterval unsignedShortValue]); + XCTAssertEqual([maxInterval unsignedShortValue], [myMaxInterval unsignedShortValue]); + XCTAssertNil(params); [callExpectation fulfill]; establishedHandler(); }; @@ -1246,11 +1659,12 @@ - (void)testSubscribeMultiEndpoints XCTAssertNotNil(device); XCTAssertNil(error); NSLog(@"Device acquired. Subscribing..."); - [device subscribeAttributeWithEndpointId:0xffff + [device subscribeAttributeWithEndpointId:nil clusterId:myClusterId attributeId:myAttributeId minInterval:myMinInterval maxInterval:myMaxInterval + params:nil clientQueue:dispatch_get_main_queue() reportHandler:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Report value: %@", values); @@ -1279,9 +1693,9 @@ - (void)testSubscribeMultiEndpoints // Inject another report reportExpectation = [self expectationWithDescription:@"2nd report sent"]; myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @771234 } } ]; [clientObject handleReportWithController:uuid @@ -1292,6 +1706,15 @@ - (void)testSubscribeMultiEndpoints // Wait for report [self waitForExpectations:[NSArray arrayWithObject:reportExpectation] timeout:kTimeoutInSeconds]; + // Setup stop report handler + XCTestExpectation * stopExpectation = [self expectationWithDescription:@"Reports stopped"]; + _handleStopReports = ^(id _Nullable controller, uint64_t nodeId, void (^completion)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + completion(); + [stopExpectation fulfill]; + }; + // Deregister report handler [_remoteDeviceController getConnectedDevice:myNodeId queue:dispatch_get_main_queue() @@ -1304,22 +1727,22 @@ - (void)testSubscribeMultiEndpoints }]; // Wait for disconnection - [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + [self waitForExpectations:@[ _xpcDisconnectExpectation, stopExpectation ] timeout:kTimeoutInSeconds]; XCTAssertNil(_xpcConnection); } - (void)testSubscribeMultiClusters { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; - NSUInteger myMinInterval = 5; - NSUInteger myMaxInterval = 60; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; + NSNumber * myMinInterval = @5; + NSNumber * myMaxInterval = @60; __block NSArray * myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } } ]; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; @@ -1327,15 +1750,17 @@ - (void)testSubscribeMultiClusters __block XCTestExpectation * reportExpectation = [self expectationWithDescription:@"Report sent"]; __auto_type uuid = self.controllerUUID; - _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, - NSUInteger attributeId, NSUInteger minInterval, NSUInteger maxInterval, void (^establishedHandler)(void)) { + _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, NSNumber * minInterval, NSNumber * maxInterval, CHIPSubscribeParams * _Nullable params, + void (^establishedHandler)(void)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, 0xffffffff); - XCTAssertEqual(attributeId, myAttributeId); - XCTAssertEqual(minInterval, myMinInterval); - XCTAssertEqual(maxInterval, myMaxInterval); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertNil(clusterId); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertEqual([minInterval unsignedShortValue], [myMinInterval unsignedShortValue]); + XCTAssertEqual([maxInterval unsignedShortValue], [myMaxInterval unsignedShortValue]); + XCTAssertNil(params); [callExpectation fulfill]; establishedHandler(); }; @@ -1350,10 +1775,11 @@ - (void)testSubscribeMultiClusters XCTAssertNil(error); NSLog(@"Device acquired. Subscribing..."); [device subscribeAttributeWithEndpointId:myEndpointId - clusterId:0xffffffff + clusterId:nil attributeId:myAttributeId minInterval:myMinInterval maxInterval:myMaxInterval + params:nil clientQueue:dispatch_get_main_queue() reportHandler:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Report value: %@", values); @@ -1382,9 +1808,9 @@ - (void)testSubscribeMultiClusters // Inject another report reportExpectation = [self expectationWithDescription:@"2nd report sent"]; myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @771234 } } ]; [clientObject handleReportWithController:uuid @@ -1395,6 +1821,15 @@ - (void)testSubscribeMultiClusters // Wait for report [self waitForExpectations:[NSArray arrayWithObject:reportExpectation] timeout:kTimeoutInSeconds]; + // Setup stop report handler + XCTestExpectation * stopExpectation = [self expectationWithDescription:@"Reports stopped"]; + _handleStopReports = ^(id _Nullable controller, uint64_t nodeId, void (^completion)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + completion(); + [stopExpectation fulfill]; + }; + // Deregister report handler [_remoteDeviceController getConnectedDevice:myNodeId queue:dispatch_get_main_queue() @@ -1407,22 +1842,22 @@ - (void)testSubscribeMultiClusters }]; // Wait for disconnection - [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + [self waitForExpectations:@[ _xpcDisconnectExpectation, stopExpectation ] timeout:kTimeoutInSeconds]; XCTAssertNil(_xpcConnection); } - (void)testSubscribeMultiAttributes { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; - NSUInteger myMinInterval = 5; - NSUInteger myMaxInterval = 60; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; + NSNumber * myMinInterval = @5; + NSNumber * myMaxInterval = @60; __block NSArray * myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } } ]; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; @@ -1430,15 +1865,17 @@ - (void)testSubscribeMultiAttributes __block XCTestExpectation * reportExpectation = [self expectationWithDescription:@"Report sent"]; __auto_type uuid = self.controllerUUID; - _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, - NSUInteger attributeId, NSUInteger minInterval, NSUInteger maxInterval, void (^establishedHandler)(void)) { + _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, NSNumber * minInterval, NSNumber * maxInterval, CHIPSubscribeParams * _Nullable params, + void (^establishedHandler)(void)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, 0xffffffff); - XCTAssertEqual(minInterval, myMinInterval); - XCTAssertEqual(maxInterval, myMaxInterval); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertNil(attributeId); + XCTAssertEqual([minInterval unsignedShortValue], [myMinInterval unsignedShortValue]); + XCTAssertEqual([maxInterval unsignedShortValue], [myMaxInterval unsignedShortValue]); + XCTAssertNil(params); [callExpectation fulfill]; establishedHandler(); }; @@ -1454,9 +1891,10 @@ - (void)testSubscribeMultiAttributes NSLog(@"Device acquired. Subscribing..."); [device subscribeAttributeWithEndpointId:myEndpointId clusterId:myClusterId - attributeId:0xffffffff + attributeId:nil minInterval:myMinInterval maxInterval:myMaxInterval + params:nil clientQueue:dispatch_get_main_queue() reportHandler:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Report value: %@", values); @@ -1485,9 +1923,9 @@ - (void)testSubscribeMultiAttributes // Inject another report reportExpectation = [self expectationWithDescription:@"2nd report sent"]; myReport = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @771234 } } ]; [clientObject handleReportWithController:uuid @@ -1498,6 +1936,15 @@ - (void)testSubscribeMultiAttributes // Wait for report [self waitForExpectations:[NSArray arrayWithObject:reportExpectation] timeout:kTimeoutInSeconds]; + // Setup stop report handler + XCTestExpectation * stopExpectation = [self expectationWithDescription:@"Reports stopped"]; + _handleStopReports = ^(id _Nullable controller, uint64_t nodeId, void (^completion)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + completion(); + [stopExpectation fulfill]; + }; + // Deregister report handler [_remoteDeviceController getConnectedDevice:myNodeId queue:dispatch_get_main_queue() @@ -1510,39 +1957,41 @@ - (void)testSubscribeMultiAttributes }]; // Wait for disconnection - [self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds]; + [self waitForExpectations:@[ _xpcDisconnectExpectation, stopExpectation ] timeout:kTimeoutInSeconds]; XCTAssertNil(_xpcConnection); } - (void)testMutiSubscriptions { uint64_t nodeIds[] = { 9876543210, 9876543211 }; - NSUInteger endpointIds[] = { 100, 150 }; - NSUInteger clusterIds[] = { 200, 250 }; - NSUInteger attributeIds[] = { 300, 350 }; - NSUInteger minIntervals[] = { 5, 7 }; - NSUInteger maxIntervals[] = { 60, 68 }; + NSNumber * endpointIds[] = { @100, @150 }; + NSNumber * clusterIds[] = { @200, @250 }; + NSNumber * attributeIds[] = { @300, @350 }; + NSNumber * minIntervals[] = { @5, @7 }; + NSNumber * maxIntervals[] = { @60, @68 }; __block uint64_t myNodeId = nodeIds[0]; - __block NSUInteger myEndpointId = endpointIds[0]; - __block NSUInteger myClusterId = clusterIds[0]; - __block NSUInteger myAttributeId = attributeIds[0]; - __block NSUInteger myMinInterval = minIntervals[0]; - __block NSUInteger myMaxInterval = maxIntervals[0]; + __block NSNumber * myEndpointId = endpointIds[0]; + __block NSNumber * myClusterId = clusterIds[0]; + __block NSNumber * myAttributeId = attributeIds[0]; + __block NSNumber * myMinInterval = minIntervals[0]; + __block NSNumber * myMaxInterval = maxIntervals[0]; __block NSArray * myReports; __block XCTestExpectation * callExpectation; __block XCTestExpectation * establishExpectation; __block NSArray * reportExpectations; __auto_type uuid = self.controllerUUID; - _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, - NSUInteger attributeId, NSUInteger minInterval, NSUInteger maxInterval, void (^establishedHandler)(void)) { + _handleSubscribeAttribute = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, NSNumber * minInterval, NSNumber * maxInterval, CHIPSubscribeParams * _Nullable params, + void (^establishedHandler)(void)) { XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); - XCTAssertEqual(minInterval, myMinInterval); - XCTAssertEqual(maxInterval, myMaxInterval); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); + XCTAssertEqual([minInterval unsignedShortValue], [myMinInterval unsignedShortValue]); + XCTAssertEqual([maxInterval unsignedShortValue], [myMaxInterval unsignedShortValue]); + XCTAssertNil(params); [callExpectation fulfill]; establishedHandler(); }; @@ -1571,6 +2020,7 @@ - (void)testMutiSubscriptions attributeId:myAttributeId minInterval:myMinInterval maxInterval:myMaxInterval + params:nil clientQueue:dispatch_get_main_queue() reportHandler:^(NSArray *> * _Nullable values, NSError * _Nullable error) { NSLog(@"Subscriber [%d] report value: %@", i, values); @@ -1597,17 +2047,15 @@ - (void)testMutiSubscriptions [self expectationWithDescription:[NSString stringWithFormat:@"Report(%d) for second subscriber sent", count]], nil]; myReports = @[ @[ @{ - @"attributePath" : - [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:endpointIds[0]] - clusterId:[NSNumber numberWithUnsignedInteger:clusterIds[0]] - attributeId:[NSNumber numberWithUnsignedInteger:attributeIds[0]]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:endpointIds[0] + clusterId:clusterIds[0] + attributeId:attributeIds[0]], @"data" : @ { @"type" : @"SignedInteger", @"value" : [NSNumber numberWithInteger:123456 + count * 100] } } ], @[ @{ - @"attributePath" : - [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:endpointIds[1]] - clusterId:[NSNumber numberWithUnsignedInteger:clusterIds[1]] - attributeId:[NSNumber numberWithUnsignedInteger:attributeIds[1]]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:endpointIds[1] + clusterId:clusterIds[1] + attributeId:attributeIds[1]], @"data" : @ { @"type" : @"SignedInteger", @"value" : [NSNumber numberWithInteger:123457 + count * 100] } } ] ]; @@ -1623,9 +2071,19 @@ - (void)testMutiSubscriptions [self waitForExpectations:reportExpectations timeout:kTimeoutInSeconds]; } + // Setup stop report handler + XCTestExpectation * stopExpectation = [self expectationWithDescription:@"Reports stopped"]; + __auto_type nodeToStop = nodeIds[0]; + _handleStopReports = ^(id _Nullable controller, uint64_t nodeId, void (^completion)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, nodeToStop); + completion(); + [stopExpectation fulfill]; + }; + // Deregister report handler for first subscriber __auto_type deregisterExpectation = [self expectationWithDescription:@"First subscriber deregistered"]; - [_remoteDeviceController getConnectedDevice:nodeIds[0] + [_remoteDeviceController getConnectedDevice:nodeToStop queue:dispatch_get_main_queue() completionHandler:^(CHIPDevice * _Nullable device, NSError * _Nullable error) { NSLog(@"Device acquired. Deregistering..."); @@ -1636,7 +2094,7 @@ - (void)testMutiSubscriptions }]; }]; - [self waitForExpectations:[NSArray arrayWithObject:deregisterExpectation] timeout:kTimeoutInSeconds]; + [self waitForExpectations:@[ stopExpectation, deregisterExpectation ] timeout:kTimeoutInSeconds]; // Inject reports for (int count = 0; count < 1; count++) { @@ -1647,17 +2105,15 @@ - (void)testMutiSubscriptions reportExpectations[0].inverted = YES; myReports = @[ @[ @{ - @"attributePath" : - [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:endpointIds[0]] - clusterId:[NSNumber numberWithUnsignedInteger:clusterIds[0]] - attributeId:[NSNumber numberWithUnsignedInteger:attributeIds[0]]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:endpointIds[0] + clusterId:clusterIds[0] + attributeId:attributeIds[0]], @"data" : @ { @"type" : @"SignedInteger", @"value" : [NSNumber numberWithInteger:223456 + count * 100] } } ], @[ @{ - @"attributePath" : - [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:endpointIds[1]] - clusterId:[NSNumber numberWithUnsignedInteger:clusterIds[1]] - attributeId:[NSNumber numberWithUnsignedInteger:attributeIds[1]]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:endpointIds[1] + clusterId:clusterIds[1] + attributeId:attributeIds[1]], @"data" : @ { @"type" : @"SignedInteger", @"value" : [NSNumber numberWithInteger:223457 + count * 100] } } ] ]; @@ -1673,9 +2129,19 @@ - (void)testMutiSubscriptions [self waitForExpectations:reportExpectations timeout:kTimeoutInSeconds]; } + // Setup stop report handler + stopExpectation = [self expectationWithDescription:@"Reports stopped"]; + nodeToStop = nodeIds[1]; + _handleStopReports = ^(id _Nullable controller, uint64_t nodeId, void (^completion)(void)) { + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, nodeToStop); + completion(); + [stopExpectation fulfill]; + }; + // Deregister report handler for second subscriber __auto_type secondDeregisterExpectation = [self expectationWithDescription:@"Second subscriber deregistered"]; - [_remoteDeviceController getConnectedDevice:nodeIds[1] + [_remoteDeviceController getConnectedDevice:nodeToStop queue:dispatch_get_main_queue() completionHandler:^(CHIPDevice * _Nullable device, NSError * _Nullable error) { NSLog(@"Device acquired. Deregistering..."); @@ -1687,7 +2153,7 @@ - (void)testMutiSubscriptions }]; // Wait for deregistration and disconnection - [self waitForExpectations:[NSArray arrayWithObjects:secondDeregisterExpectation, _xpcDisconnectExpectation, nil] + [self waitForExpectations:@[ secondDeregisterExpectation, _xpcDisconnectExpectation, stopExpectation ] timeout:kTimeoutInSeconds]; XCTAssertNil(_xpcConnection); @@ -1701,17 +2167,15 @@ - (void)testMutiSubscriptions reportExpectations[1].inverted = YES; myReports = @[ @[ @{ - @"attributePath" : - [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:endpointIds[0]] - clusterId:[NSNumber numberWithUnsignedInteger:clusterIds[0]] - attributeId:[NSNumber numberWithUnsignedInteger:attributeIds[0]]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:endpointIds[0] + clusterId:clusterIds[0] + attributeId:attributeIds[0]], @"data" : @ { @"type" : @"SignedInteger", @"value" : [NSNumber numberWithInteger:223456 + count * 100] } } ], @[ @{ - @"attributePath" : - [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:endpointIds[1]] - clusterId:[NSNumber numberWithUnsignedInteger:clusterIds[1]] - attributeId:[NSNumber numberWithUnsignedInteger:attributeIds[1]]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:endpointIds[1] + clusterId:clusterIds[1] + attributeId:attributeIds[1]], @"data" : @ { @"type" : @"SignedInteger", @"value" : [NSNumber numberWithInteger:223457 + count * 100] } } ] ]; @@ -1767,17 +2231,58 @@ - (void)testSubscribeAttributeCacheSuccess __auto_type uuid = self.controllerUUID; __auto_type attributeCacheContainer = [[CHIPAttributeCacheContainer alloc] init]; - _handleSubscribeAttributeCache = ^(id controller, uint64_t nodeId, void (^completion)(NSError * _Nullable error)) { - NSLog(@"Subscribe attribute cache called"); - XCTAssertTrue([controller isEqualToString:uuid]); - XCTAssertEqual(nodeId, myNodeId); - [callExpectation fulfill]; - completion(nil); - }; + _handleSubscribeAttributeCache + = ^(id controller, uint64_t nodeId, CHIPSubscribeParams * _Nullable params, void (^completion)(NSError * _Nullable error)) { + NSLog(@"Subscribe attribute cache called"); + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + XCTAssertNil(params); + [callExpectation fulfill]; + completion(nil); + }; + + _xpcDisconnectExpectation = [self expectationWithDescription:@"XPC Disconnected"]; + [attributeCacheContainer subscribeWithDeviceController:_remoteDeviceController + deviceId:myNodeId + params:nil + clientQueue:dispatch_get_main_queue() + completion:^(NSError * _Nullable error) { + NSLog(@"Subscribe completion called with error: %@", error); + XCTAssertNil(error); + [responseExpectation fulfill]; + }]; + + [self waitForExpectations:@[ callExpectation, responseExpectation, self.xpcDisconnectExpectation ] timeout:kTimeoutInSeconds]; + XCTAssertNil(_xpcConnection); +} + +- (void)testSubscribeAttributeCacheWithParamsSuccess +{ + uint64_t myNodeId = 9876543210; + CHIPSubscribeParams * myParams = [[CHIPSubscribeParams alloc] init]; + myParams.fabricFiltered = @YES; + myParams.keepPreviousSubscriptions = @YES; + XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; + XCTestExpectation * responseExpectation = [self expectationWithDescription:@"XPC response received"]; + + __auto_type uuid = self.controllerUUID; + __auto_type attributeCacheContainer = [[CHIPAttributeCacheContainer alloc] init]; + _handleSubscribeAttributeCache + = ^(id controller, uint64_t nodeId, CHIPSubscribeParams * _Nullable params, void (^completion)(NSError * _Nullable error)) { + NSLog(@"Subscribe attribute cache called"); + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + XCTAssertNotNil(params); + XCTAssertEqual([params.fabricFiltered boolValue], [myParams.fabricFiltered boolValue]); + XCTAssertEqual([params.keepPreviousSubscriptions boolValue], [myParams.keepPreviousSubscriptions boolValue]); + [callExpectation fulfill]; + completion(nil); + }; _xpcDisconnectExpectation = [self expectationWithDescription:@"XPC Disconnected"]; [attributeCacheContainer subscribeWithDeviceController:_remoteDeviceController deviceId:myNodeId + params:myParams clientQueue:dispatch_get_main_queue() completion:^(NSError * _Nullable error) { NSLog(@"Subscribe completion called with error: %@", error); @@ -1798,17 +2303,20 @@ - (void)testSubscribeAttributeCacheFailure __auto_type uuid = self.controllerUUID; __auto_type attributeCacheContainer = [[CHIPAttributeCacheContainer alloc] init]; - _handleSubscribeAttributeCache = ^(id controller, uint64_t nodeId, void (^completion)(NSError * _Nullable error)) { - NSLog(@"Subscribe attribute cache called"); - XCTAssertTrue([controller isEqualToString:uuid]); - XCTAssertEqual(nodeId, myNodeId); - [callExpectation fulfill]; - completion(myError); - }; + _handleSubscribeAttributeCache + = ^(id controller, uint64_t nodeId, CHIPSubscribeParams * _Nullable params, void (^completion)(NSError * _Nullable error)) { + NSLog(@"Subscribe attribute cache called"); + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + XCTAssertNil(params); + [callExpectation fulfill]; + completion(myError); + }; _xpcDisconnectExpectation = [self expectationWithDescription:@"XPC Disconnected"]; [attributeCacheContainer subscribeWithDeviceController:_remoteDeviceController deviceId:myNodeId + params:nil clientQueue:dispatch_get_main_queue() completion:^(NSError * _Nullable error) { NSLog(@"Subscribe completion called with error: %@", error); @@ -1823,13 +2331,13 @@ - (void)testSubscribeAttributeCacheFailure - (void)testReadAttributeCacheSuccess { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; NSArray * myValues = @[ @{ - @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:[NSNumber numberWithUnsignedInteger:myEndpointId] - clusterId:[NSNumber numberWithUnsignedInteger:myClusterId] - attributeId:[NSNumber numberWithUnsignedInteger:myAttributeId]], + @"attributePath" : [CHIPAttributePath attributePathWithEndpointId:myEndpointId + clusterId:myClusterId + attributeId:myAttributeId], @"data" : @ { @"type" : @"SignedInteger", @"value" : @123456 } } ]; @@ -1839,27 +2347,30 @@ - (void)testReadAttributeCacheSuccess __auto_type uuid = self.controllerUUID; __auto_type attributeCacheContainer = [[CHIPAttributeCacheContainer alloc] init]; - _handleSubscribeAttributeCache = ^(id controller, uint64_t nodeId, void (^completion)(NSError * _Nullable error)) { - NSLog(@"Subscribe attribute cache called"); - XCTAssertTrue([controller isEqualToString:uuid]); - XCTAssertEqual(nodeId, myNodeId); - completion(nil); - }; - - _handleReadAttributeCache = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, - NSUInteger attributeId, void (^completion)(id _Nullable values, NSError * _Nullable error)) { + _handleSubscribeAttributeCache + = ^(id controller, uint64_t nodeId, CHIPSubscribeParams * _Nullable params, void (^completion)(NSError * _Nullable error)) { + NSLog(@"Subscribe attribute cache called"); + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + XCTAssertNil(params); + completion(nil); + }; + + _handleReadAttributeCache = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, void (^completion)(id _Nullable values, NSError * _Nullable error)) { NSLog(@"Read attribute cache called"); XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); [callExpectation fulfill]; completion([CHIPDeviceController encodeXPCResponseValues:myValues], nil); }; [attributeCacheContainer subscribeWithDeviceController:_remoteDeviceController deviceId:myNodeId + params:nil clientQueue:dispatch_get_main_queue() completion:^(NSError * _Nullable error) { NSLog(@"Subscribe completion called with error: %@", error); @@ -1888,9 +2399,9 @@ - (void)testReadAttributeCacheSuccess - (void)testReadAttributeCacheFailure { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; NSError * myError = [NSError errorWithDomain:CHIPErrorDomain code:CHIPErrorCodeGeneralError userInfo:nil]; XCTestExpectation * subscribeExpectation = [self expectationWithDescription:@"Cache subscription complete"]; XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"]; @@ -1898,27 +2409,30 @@ - (void)testReadAttributeCacheFailure __auto_type uuid = self.controllerUUID; __auto_type attributeCacheContainer = [[CHIPAttributeCacheContainer alloc] init]; - _handleSubscribeAttributeCache = ^(id controller, uint64_t nodeId, void (^completion)(NSError * _Nullable error)) { - NSLog(@"Subscribe attribute cache called"); - XCTAssertTrue([controller isEqualToString:uuid]); - XCTAssertEqual(nodeId, myNodeId); - completion(nil); - }; - - _handleReadAttributeCache = ^(id controller, uint64_t nodeId, NSUInteger endpointId, NSUInteger clusterId, - NSUInteger attributeId, void (^completion)(id _Nullable values, NSError * _Nullable error)) { + _handleSubscribeAttributeCache + = ^(id controller, uint64_t nodeId, CHIPSubscribeParams * _Nullable params, void (^completion)(NSError * _Nullable error)) { + NSLog(@"Subscribe attribute cache called"); + XCTAssertTrue([controller isEqualToString:uuid]); + XCTAssertEqual(nodeId, myNodeId); + XCTAssertNil(params); + completion(nil); + }; + + _handleReadAttributeCache = ^(id controller, uint64_t nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId, + NSNumber * _Nullable attributeId, void (^completion)(id _Nullable values, NSError * _Nullable error)) { NSLog(@"Read attribute cache called"); XCTAssertTrue([controller isEqualToString:uuid]); XCTAssertEqual(nodeId, myNodeId); - XCTAssertEqual(endpointId, myEndpointId); - XCTAssertEqual(clusterId, myClusterId); - XCTAssertEqual(attributeId, myAttributeId); + XCTAssertEqual([endpointId unsignedShortValue], [myEndpointId unsignedShortValue]); + XCTAssertEqual([clusterId unsignedLongValue], [myClusterId unsignedLongValue]); + XCTAssertEqual([attributeId unsignedLongValue], [myAttributeId unsignedLongValue]); [callExpectation fulfill]; completion(nil, myError); }; [attributeCacheContainer subscribeWithDeviceController:_remoteDeviceController deviceId:myNodeId + params:nil clientQueue:dispatch_get_main_queue() completion:^(NSError * _Nullable error) { NSLog(@"Subscribe completion called with error: %@", error); @@ -1946,9 +2460,9 @@ - (void)testReadAttributeCacheFailure - (void)testXPCConnectionFailure { uint64_t myNodeId = 9876543210; - NSUInteger myEndpointId = 100; - NSUInteger myClusterId = 200; - NSUInteger myAttributeId = 300; + NSNumber * myEndpointId = @100; + NSNumber * myClusterId = @200; + NSNumber * myAttributeId = @300; XCTestExpectation * responseExpectation = [self expectationWithDescription:@"Read response received"]; // Test with a device controller which wouldn't connect to XPC listener successfully @@ -1966,6 +2480,7 @@ - (void)testXPCConnectionFailure [device readAttributeWithEndpointId:myEndpointId clusterId:myClusterId attributeId:myAttributeId + params:nil clientQueue:dispatch_get_main_queue() completion:^(id _Nullable value, NSError * _Nullable error) { NSLog(@"Read value: %@", value);