From acd95fcb40711c7493da443c7be5f3e8817c289a Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Tue, 14 Jun 2022 10:18:42 +0200 Subject: [PATCH] [chip-tool] Add vector arguments supports for write interactions --- .../commands/clusters/ComplexArgument.h | 11 +- .../commands/clusters/WriteAttributeCommand.h | 139 ++++++++++++++---- examples/chip-tool/templates/commands.zapt | 51 ++----- .../interaction_model/InteractionModel.cpp | 60 +++++--- .../interaction_model/InteractionModel.h | 105 ++++++++++--- 5 files changed, 250 insertions(+), 116 deletions(-) diff --git a/examples/chip-tool/commands/clusters/ComplexArgument.h b/examples/chip-tool/commands/clusters/ComplexArgument.h index 689b2e6f9a217e..d090b3744d55ff 100644 --- a/examples/chip-tool/commands/clusters/ComplexArgument.h +++ b/examples/chip-tool/commands/clusters/ComplexArgument.h @@ -308,8 +308,17 @@ template class TypedComplexArgument : public ComplexArgument { public: + TypedComplexArgument() {} TypedComplexArgument(T * request) : mRequest(request) {} - ~TypedComplexArgument() { ComplexArgumentParser::Finalize(*mRequest); } + ~TypedComplexArgument() + { + if (mRequest != nullptr) + { + ComplexArgumentParser::Finalize(*mRequest); + } + } + + void SetArgument(T * request) { mRequest = request; }; CHIP_ERROR Parse(const char * label, const char * json) { diff --git a/examples/chip-tool/commands/clusters/WriteAttributeCommand.h b/examples/chip-tool/commands/clusters/WriteAttributeCommand.h index 93ca6d167fc41b..91f6575922628f 100644 --- a/examples/chip-tool/commands/clusters/WriteAttributeCommand.h +++ b/examples/chip-tool/commands/clusters/WriteAttributeCommand.h @@ -23,23 +23,92 @@ #include "DataModelLogger.h" #include "ModelCommand.h" +template > class WriteAttribute : public InteractionModelWriter, public ModelCommand, public chip::app::WriteClient::Callback { public: WriteAttribute(CredentialIssuerCommands * credsIssuerConfig) : InteractionModelWriter(this), ModelCommand("write-by-id", credsIssuerConfig) { - AddArgument("cluster-id", 0, UINT32_MAX, &mClusterId); - AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId); - AddArgument("attribute-value", &mAttributeValue); + AddArgument("cluster-ids", 0, UINT32_MAX, &mClusterIds, + "Comma-separated list of cluster ids to write to (e.g. \"6\" or \"8,0x201\")."); + AddArgument("attribute-ids", 0, UINT32_MAX, &mAttributeIds, + "Comma-separated list of attribute ids to write (e.g. \"0\" or \"1,0xFFFC,0xFFFD\")."); + AddArgument("attribute-value", &mAttributeValues, "Comma-separated list of attribute values to write."); AddArguments(); } WriteAttribute(chip::ClusterId clusterId, CredentialIssuerCommands * credsIssuerConfig) : - InteractionModelWriter(this), ModelCommand("write-by-id", credsIssuerConfig), mClusterId(clusterId) + InteractionModelWriter(this), ModelCommand("write-by-id", credsIssuerConfig), mClusterIds(1, clusterId) { - AddArgument("attribute-id", 0, UINT32_MAX, &mAttributeId); - AddArgument("attribute-value", &mAttributeValue); + AddArgument("attribute-ids", 0, UINT32_MAX, &mAttributeIds, + "Comma-separated list of attribute ids to write (e.g. \"0\" or \"1,0xFFFC,0xFFFD\")."); + AddArgument("attribute-value", &mAttributeValues, "Comma-separated list of attribute values to write."); + AddArguments(); + } + + template + WriteAttribute(chip::ClusterId clusterId, const char * attributeName, long long minValue, maxType maxValue, + chip::AttributeId attributeId, CredentialIssuerCommands * credsIssuerConfig) : + InteractionModelWriter(this), + ModelCommand("write", credsIssuerConfig), mClusterIds(1, clusterId), mAttributeIds(1, attributeId) + { + AddArgument("attribute-name", attributeName, "The attribute name to write."); + AddArgument("attribute-value", static_cast(minValue), static_cast(maxValue), &mAttributeValues, + "The attribute value to write."); + AddArguments(); + } + + template + WriteAttribute(chip::ClusterId clusterId, const char * attributeName, int minValue, maxType maxValue, + chip::AttributeId attributeId, CredentialIssuerCommands * credsIssuerConfig) : + InteractionModelWriter(this), + ModelCommand("write", credsIssuerConfig), mClusterIds(1, clusterId), mAttributeIds(1, attributeId) + { + AddArgument("attribute-name", attributeName, "The attribute name to write."); + AddArgument("attribute-value", static_cast(minValue), static_cast(maxValue), &mAttributeValues, + "The attribute value to write."); + AddArguments(); + } + + WriteAttribute(chip::ClusterId clusterId, const char * attributeName, float minValue, float maxValue, + chip::AttributeId attributeId, CredentialIssuerCommands * credsIssuerConfig) : + InteractionModelWriter(this), + ModelCommand("write", credsIssuerConfig), mClusterIds(1, clusterId), mAttributeIds(1, attributeId) + { + AddArgument("attribute-name", attributeName, "The attribute name to write."); + AddArgument("attribute-value", minValue, maxValue, &mAttributeValues, "The attribute value to write."); + AddArguments(); + } + + WriteAttribute(chip::ClusterId clusterId, const char * attributeName, double minValue, double maxValue, + chip::AttributeId attributeId, CredentialIssuerCommands * credsIssuerConfig) : + InteractionModelWriter(this), + ModelCommand("write", credsIssuerConfig), mClusterIds(1, clusterId), mAttributeIds(1, attributeId) + { + AddArgument("attribute-name", attributeName, "The attribute name to write."); + AddArgument("attribute-value", minValue, maxValue, &mAttributeValues, "The attribute value to write."); + AddArguments(); + } + + WriteAttribute(chip::ClusterId clusterId, const char * attributeName, chip::AttributeId attributeId, + CredentialIssuerCommands * credsIssuerConfig) : + InteractionModelWriter(this), + ModelCommand("write", credsIssuerConfig), mClusterIds(1, clusterId), mAttributeIds(1, attributeId) + { + AddArgument("attribute-name", attributeName, "The attribute name to write."); + AddArgument("attribute-value", &mAttributeValues, "The attribute value to write."); + AddArguments(); + } + + WriteAttribute(chip::ClusterId clusterId, const char * attributeName, chip::AttributeId attributeId, + TypedComplexArgument & attributeParser, CredentialIssuerCommands * credsIssuerConfig) : + InteractionModelWriter(this), + ModelCommand("write", credsIssuerConfig), mClusterIds(1, clusterId), mAttributeIds(1, attributeId) + { + attributeParser.SetArgument(&mAttributeValues); + AddArgument("attribute-name", attributeName, "The attribute name to write."); + AddArgument("attribute-value", &attributeParser, "The attribute value to write."); AddArguments(); } @@ -47,12 +116,12 @@ class WriteAttribute : public InteractionModelWriter, public ModelCommand, publi CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override { - return WriteAttribute::SendCommand(device, endpointIds.at(0), mClusterId, mAttributeId, mAttributeValue); + return WriteAttribute::SendCommand(device, endpointIds, mClusterIds, mAttributeIds, mAttributeValues); } CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override { - return WriteAttribute::SendGroupCommand(groupId, fabricIndex, mClusterId, mAttributeId, mAttributeValue); + return WriteAttribute::SendGroupCommand(groupId, fabricIndex, mClusterIds, mAttributeIds, mAttributeValues); } /////////// WriteClient Callback Interface ///////// @@ -79,23 +148,27 @@ class WriteAttribute : public InteractionModelWriter, public ModelCommand, publi SetCommandExitStatus(mError); } - template - CHIP_ERROR SendCommand(chip::DeviceProxy * device, chip::EndpointId endpointId, chip::ClusterId clusterId, - chip::AttributeId attributeId, const T & value) + CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds, + std::vector clusterIds, std::vector attributeIds, const T & values) { - ChipLogProgress(chipTool, "Sending WriteAttribute to cluster " ChipLogFormatMEI " on endpoint %u", - ChipLogValueMEI(clusterId), endpointId); - return InteractionModelWriter::WriteAttribute(device, endpointId, clusterId, attributeId, value, mTimedInteractionTimeoutMs, - mSuppressResponse, mDataVersion, mRepeatCount, mRepeatDelayInMs); + return InteractionModelWriter::WriteAttribute(device, endpointIds, clusterIds, attributeIds, values, + mTimedInteractionTimeoutMs, mSuppressResponse, mDataVersions, mRepeatCount, + mRepeatDelayInMs); } - template - CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex, chip::ClusterId clusterId, - chip::AttributeId attributeId, const T & value) + CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex, std::vector clusterIds, + std::vector attributeIds, const T & value) { ChipLogDetail(chipTool, "Sending Write Attribute to Group %u, on Fabric %x, for cluster %u with attributeId %u", groupId, - fabricIndex, clusterId, attributeId); - return InteractionModelWriter::WriteGroupAttribute(groupId, fabricIndex, clusterId, attributeId, value, mDataVersion); + fabricIndex, clusterIds.at(0), attributeIds.at(0)); + chip::Optional dataVersion = chip::NullOptional; + if (mDataVersions.HasValue()) + { + dataVersion.SetValue(mDataVersions.Value().at(0)); + } + + return InteractionModelWriter::WriteGroupAttribute(groupId, fabricIndex, clusterIds.at(0), attributeIds.at(0), value, + dataVersion); } protected: @@ -109,7 +182,8 @@ class WriteAttribute : public InteractionModelWriter, public ModelCommand, publi { AddArgument("timedInteractionTimeoutMs", 0, UINT16_MAX, &mTimedInteractionTimeoutMs, "If provided, do a timed write with the given timed interaction timeout."); - AddArgument("data-version", 0, UINT32_MAX, &mDataVersion); + AddArgument("data-version", 0, UINT32_MAX, &mDataVersions, + "Comma-separated list of data versions for the clusters being written."); AddArgument("suppressResponse", 0, 1, &mSuppressResponse); AddArgument("repeat-count", 1, UINT16_MAX, &mRepeatCount); AddArgument("repeat-delay-ms", 0, UINT16_MAX, &mRepeatDelayInMs); @@ -117,13 +191,28 @@ class WriteAttribute : public InteractionModelWriter, public ModelCommand, publi } private: - chip::ClusterId mClusterId; - chip::AttributeId mAttributeId; + std::vector mClusterIds; + std::vector mAttributeIds; + CHIP_ERROR mError = CHIP_NO_ERROR; chip::Optional mTimedInteractionTimeoutMs; - chip::Optional mDataVersion = chip::NullOptional; + chip::Optional> mDataVersions; chip::Optional mSuppressResponse; - CustomArgument mAttributeValue; chip::Optional mRepeatCount; chip::Optional mRepeatDelayInMs; + + T mAttributeValues; +}; + +template +class WriteAttributeAsComplex : public WriteAttribute +{ +public: + WriteAttributeAsComplex(chip::ClusterId clusterId, const char * attributeName, chip::AttributeId attributeId, + CredentialIssuerCommands * credsIssuerConfig) : + WriteAttribute(clusterId, attributeName, attributeId, mAttributeParser, credsIssuerConfig) + {} + +private: + TypedComplexArgument mAttributeParser; }; diff --git a/examples/chip-tool/templates/commands.zapt b/examples/chip-tool/templates/commands.zapt index 55939cdbf4411c..25c8a54859f471 100644 --- a/examples/chip-tool/templates/commands.zapt +++ b/examples/chip-tool/templates/commands.zapt @@ -64,45 +64,6 @@ private: {{/zcl_commands_source_client}} -{{#zcl_attributes_server}} -{{#if isWritable}} -class Write{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}: public WriteAttribute -{ -public: - Write{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}(CredentialIssuerCommands * credsIssuerConfig): WriteAttribute("{{asUpperCamelCase name}}", credsIssuerConfig){{#if_chip_complex}}, mComplex(&mValue){{/if_chip_complex}} - { - AddArgument("attr-name", "{{asDelimitedCommand (asUpperCamelCase name)}}"); - {{#if_chip_complex}} - AddArgument("attr-value", &mComplex); - {{else if (isString type)}} - AddArgument("attr-value", &mValue); - {{else}} - AddArgument("attr-value", {{asTypeMinValue type}}, {{asTypeMaxValue type}}, &mValue); - {{/if_chip_complex}} - WriteAttribute::AddArguments(); - } - - ~Write{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}() {} - - CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override - { - return WriteAttribute::SendCommand(device, endpointIds.at(0), {{asHex parent.code 8}}, {{asHex code 8}}, mValue); - } - - CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override - { - return WriteAttribute::SendGroupCommand(groupId, fabricIndex, {{asHex parent.code 8}}, {{asHex code 8}}, mValue); - } - -private: - {{zapTypeToEncodableClusterObjectType type ns=parent.name forceNotOptional=true}} mValue; -{{#if_chip_complex}} - TypedComplexArgument<{{zapTypeToEncodableClusterObjectType type ns=parent.name forceNotOptional=true}}> mComplex; -{{/if_chip_complex}} -}; - -{{/if}} -{{/zcl_attributes_server}} {{/zcl_clusters}} /*----------------------------------------------------------------------------*\ @@ -130,10 +91,16 @@ void registerCluster{{asUpperCamelCase name}}(Commands & commands, CredentialIss {{#zcl_attributes_server}} make_unique(Id, "{{asDelimitedCommand (asUpperCamelCase name)}}", Attributes::{{asUpperCamelCase name}}::Id, credsIssuerConfig), // {{/zcl_attributes_server}} - make_unique(Id, credsIssuerConfig), // + make_unique>(Id, credsIssuerConfig), // {{#zcl_attributes_server}} {{#if isWritable}} - make_unique(credsIssuerConfig), // + {{#if_chip_complex}} + make_unique>(Id, "{{asDelimitedCommand (asUpperCamelCase name)}}", Attributes::{{asUpperCamelCase name}}::Id, credsIssuerConfig), // + {{else if (isString type)}} + make_unique>(Id, "{{asDelimitedCommand (asUpperCamelCase name)}}", Attributes::{{asUpperCamelCase name}}::Id, credsIssuerConfig), // + {{else}} + make_unique>(Id, "{{asDelimitedCommand (asUpperCamelCase name)}}", {{asTypeMinValue type}}, {{asTypeMaxValue type}}, Attributes::{{asUpperCamelCase name}}::Id, credsIssuerConfig), // + {{/if_chip_complex}} {{/if}} {{/zcl_attributes_server}} make_unique(Id, credsIssuerConfig), // @@ -166,7 +133,7 @@ void registerClusterAny(Commands & commands, CredentialIssuerCommands * credsIss commands_list clusterCommands = { make_unique(credsIssuerConfig), // make_unique(credsIssuerConfig), // - make_unique(credsIssuerConfig), // + make_unique>(credsIssuerConfig), // make_unique(credsIssuerConfig), // make_unique(credsIssuerConfig), // make_unique(credsIssuerConfig), // diff --git a/src/app/tests/suites/commands/interaction_model/InteractionModel.cpp b/src/app/tests/suites/commands/interaction_model/InteractionModel.cpp index 91cb73b35ef714..526106c56d4a07 100644 --- a/src/app/tests/suites/commands/interaction_model/InteractionModel.cpp +++ b/src/app/tests/suites/commands/interaction_model/InteractionModel.cpp @@ -174,16 +174,14 @@ void InteractionModel::OnDone(CommandSender * client) } } -CHIP_ERROR InteractionModelReports::ReportAttribute(DeviceProxy * device, std::vector endpointIds, - std::vector clusterIds, std::vector attributeIds, - ReadClient::InteractionType interactionType, uint16_t minInterval, - uint16_t maxInterval, const Optional & fabricFiltered, - const Optional> & dataVersions, - const Optional & keepSubscriptions) +CHIP_ERROR InteractionModelConfig::GetAttributePaths(std::vector endpointIds, std::vector clusterIds, + std::vector attributeIds, + const Optional> & dataVersions, + AttributePathsConfig & pathsConfig) { + const size_t endpointCount = endpointIds.size(); const size_t clusterCount = clusterIds.size(); const size_t attributeCount = attributeIds.size(); - const size_t endpointCount = endpointIds.size(); const size_t dataVersionsCount = dataVersions.HasValue() ? dataVersions.Value().size() : 0; VerifyOrReturnError(clusterCount > 0 && clusterCount <= kMaxAllowedPaths, CHIP_ERROR_INVALID_ARGUMENT); @@ -193,6 +191,7 @@ CHIP_ERROR InteractionModelReports::ReportAttribute(DeviceProxy * device, std::v const bool hasSameIdsCount = (clusterCount == attributeCount) && (clusterCount == endpointCount) && (dataVersionsCount == 0 || clusterCount == dataVersionsCount); + const bool multipleClusters = clusterCount > 1 && attributeCount == 1 && endpointCount == 1 && (dataVersionsCount == 0 || dataVersionsCount == 1); const bool multipleAttributes = @@ -225,21 +224,17 @@ CHIP_ERROR InteractionModelReports::ReportAttribute(DeviceProxy * device, std::v else { ChipLogError(chipTool, - "\n%sAttribute commands targetting multiple paths needs to have: \n \t * One element with multiple ids (for " + "\nCommand targetting multiple paths needs to have: \n \t * One element with multiple ids (for " "example 1 cluster id, 1 attribute id, 2 endpoint ids)\n\t * Or the same " "number of ids (for examples 2 cluster ids, 2 attribute ids and 2 endpoint ids).\n The current command has %u " "cluster ids, %u attribute ids, %u endpoint ids.", - interactionType == ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read", static_cast(clusterCount), static_cast(attributeCount), static_cast(endpointCount)); return CHIP_ERROR_INVALID_ARGUMENT; } - ChipLogProgress(chipTool, - "Sending %sAttribute to:", interactionType == ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read"); + pathsConfig.count = pathsCount; - AttributePathParams attributePathParams[kMaxAllowedPaths]; - DataVersionFilter dataVersionFilter[kMaxAllowedPaths]; for (size_t i = 0; i < pathsCount; i++) { ClusterId clusterId = clusterIds.at((hasSameIdsCount || multipleClusters) ? i : 0); @@ -251,33 +246,50 @@ CHIP_ERROR InteractionModelReports::ReportAttribute(DeviceProxy * device, std::v if (clusterId != kInvalidClusterId) { - attributePathParams[i].mClusterId = clusterId; + pathsConfig.attributePathParams[i].mClusterId = clusterId; } if (attributeId != kInvalidAttributeId) { - attributePathParams[i].mAttributeId = attributeId; + pathsConfig.attributePathParams[i].mAttributeId = attributeId; } if (endpointId != kInvalidEndpointId) { - attributePathParams[i].mEndpointId = endpointId; + pathsConfig.attributePathParams[i].mEndpointId = endpointId; } if (dataVersions.HasValue()) { - DataVersion dataVersion = dataVersions.Value().at((hasSameIdsCount || multipleDataVersions) ? i : 0); - dataVersionFilter[i].mEndpointId = endpointId; - dataVersionFilter[i].mClusterId = clusterId; - dataVersionFilter[i].mDataVersion.SetValue(dataVersion); + DataVersion dataVersion = dataVersions.Value().at((hasSameIdsCount || multipleDataVersions) ? i : 0); + pathsConfig.dataVersionFilter[i].mEndpointId = endpointId; + pathsConfig.dataVersionFilter[i].mClusterId = clusterId; + pathsConfig.dataVersionFilter[i].mDataVersion.SetValue(dataVersion); } } + return CHIP_NO_ERROR; +} + +CHIP_ERROR InteractionModelReports::ReportAttribute(DeviceProxy * device, std::vector endpointIds, + std::vector clusterIds, std::vector attributeIds, + ReadClient::InteractionType interactionType, uint16_t minInterval, + uint16_t maxInterval, const Optional & fabricFiltered, + const Optional> & dataVersions, + const Optional & keepSubscriptions) +{ + InteractionModelConfig::AttributePathsConfig pathsConfig; + ReturnErrorOnFailure( + InteractionModelConfig::GetAttributePaths(endpointIds, clusterIds, attributeIds, dataVersions, pathsConfig)); + + ChipLogProgress(chipTool, + "Sending %sAttribute to:", interactionType == ReadClient::InteractionType::Subscribe ? "Subscribe" : "Read"); + ReadPrepareParams params(device->GetSecureSession().Value()); params.mpEventPathParamsList = nullptr; params.mEventPathParamsListSize = 0; - params.mpAttributePathParamsList = attributePathParams; - params.mAttributePathParamsListSize = pathsCount; + params.mpAttributePathParamsList = pathsConfig.attributePathParams; + params.mAttributePathParamsListSize = pathsConfig.count; if (fabricFiltered.HasValue()) { @@ -286,8 +298,8 @@ CHIP_ERROR InteractionModelReports::ReportAttribute(DeviceProxy * device, std::v if (dataVersions.HasValue()) { - params.mpDataVersionFilterList = dataVersionFilter; - params.mDataVersionFilterListSize = pathsCount; + params.mpDataVersionFilterList = pathsConfig.dataVersionFilter; + params.mDataVersionFilterListSize = pathsConfig.count; } if (interactionType == ReadClient::InteractionType::Subscribe) diff --git a/src/app/tests/suites/commands/interaction_model/InteractionModel.h b/src/app/tests/suites/commands/interaction_model/InteractionModel.h index b588aa9de762c2..591c0d75e5d0f9 100644 --- a/src/app/tests/suites/commands/interaction_model/InteractionModel.h +++ b/src/app/tests/suites/commands/interaction_model/InteractionModel.h @@ -29,6 +29,22 @@ constexpr uint8_t kMaxAllowedPaths = 10; +class InteractionModelConfig +{ +public: + struct AttributePathsConfig + { + size_t count = 0; + chip::app::AttributePathParams attributePathParams[kMaxAllowedPaths]; + chip::app::DataVersionFilter dataVersionFilter[kMaxAllowedPaths]; + }; + + static CHIP_ERROR GetAttributePaths(std::vector endpointIds, std::vector clusterIds, + std::vector attributeIds, + const chip::Optional> & dataVersions, + AttributePathsConfig & pathsConfig); +}; + class InteractionModelReports { public: @@ -172,38 +188,37 @@ class InteractionModelWriter protected: template - CHIP_ERROR WriteAttribute(chip::DeviceProxy * device, chip::EndpointId endpointId, chip::ClusterId clusterId, - chip::AttributeId attributeId, const T & value, - const chip::Optional & timedInteractionTimeoutMs = chip::NullOptional, - const chip::Optional & suppressResponse = chip::NullOptional, - const chip::Optional & dataVersion = chip::NullOptional, - const chip::Optional & repeatCount = chip::NullOptional, - const chip::Optional & repeatDelayInMs = chip::NullOptional) + CHIP_ERROR WriteAttribute(chip::DeviceProxy * device, std::vector endpointIds, + std::vector clusterIds, std::vector attributeIds, + const std::vector & values, + const chip::Optional & timedInteractionTimeoutMs = chip::NullOptional, + const chip::Optional & suppressResponse = chip::NullOptional, + const chip::Optional> & dataVersions = chip::NullOptional, + const chip::Optional & repeatCount = chip::NullOptional, + const chip::Optional & repeatDelayInMs = chip::NullOptional) { + InteractionModelConfig::AttributePathsConfig pathsConfig; + ReturnErrorOnFailure( + InteractionModelConfig::GetAttributePaths(endpointIds, clusterIds, attributeIds, dataVersions, pathsConfig)); + + VerifyOrReturnError(pathsConfig.count == values.size() || values.size() == 1, CHIP_ERROR_INVALID_ARGUMENT); + uint16_t repeat = repeatCount.ValueOr(1); while (repeat--) { - chip::app::AttributePathParams attributePathParams; - if (endpointId != chip::kInvalidEndpointId) - { - attributePathParams.mEndpointId = endpointId; - } - - if (clusterId != chip::kInvalidClusterId) - { - attributePathParams.mClusterId = clusterId; - } - - if (attributeId != chip::kInvalidAttributeId) - { - attributePathParams.mAttributeId = attributeId; - } mWriteClient = std::make_unique(device->GetExchangeManager(), &mChunkedWriteCallback, timedInteractionTimeoutMs, suppressResponse.ValueOr(false)); VerifyOrReturnError(mWriteClient != nullptr, CHIP_ERROR_NO_MEMORY); - ReturnErrorOnFailure(mWriteClient->EncodeAttribute(attributePathParams, value, dataVersion)); + for (uint8_t i = 0; i < pathsConfig.count; i++) + { + auto & path = pathsConfig.attributePathParams[i]; + auto & dataVersion = pathsConfig.dataVersionFilter[i].mDataVersion; + const T & value = i >= values.size() ? values.at(0) : values.at(i); + ReturnErrorOnFailure(EncodeAttribute(path, dataVersion, value)); + } + ReturnErrorOnFailure(mWriteClient->SendWriteRequest(device->GetSecureSession().Value())); if (repeatDelayInMs.HasValue()) @@ -215,6 +230,28 @@ class InteractionModelWriter return CHIP_NO_ERROR; } + template + CHIP_ERROR WriteAttribute(chip::DeviceProxy * device, std::vector endpointIds, + std::vector clusterIds, std::vector attributeIds, const T & value, + const chip::Optional & timedInteractionTimeoutMs = chip::NullOptional, + const chip::Optional & suppressResponse = chip::NullOptional, + const chip::Optional> & dataVersions = chip::NullOptional, + const chip::Optional & repeatCount = chip::NullOptional, + const chip::Optional & repeatDelayInMs = chip::NullOptional) + { + std::vector values = { value }; + return WriteAttribute(device, endpointIds, clusterIds, attributeIds, values, timedInteractionTimeoutMs, suppressResponse, + dataVersions, repeatCount, repeatDelayInMs); + } + + template + CHIP_ERROR WriteGroupAttribute(chip::GroupId groupId, chip::FabricIndex fabricIndex, chip::ClusterId clusterId, + chip::AttributeId attributeId, const std::vector & value, + const chip::Optional & dataVersion = chip::NullOptional) + { + return CHIP_ERROR_NOT_IMPLEMENTED; + } + template CHIP_ERROR WriteGroupAttribute(chip::GroupId groupId, chip::FabricIndex fabricIndex, chip::ClusterId clusterId, chip::AttributeId attributeId, const T & value, @@ -246,6 +283,21 @@ class InteractionModelWriter std::unique_ptr mWriteClient; chip::app::ChunkedWriteCallback mChunkedWriteCallback; + +private: + template + CHIP_ERROR EncodeAttribute(const chip::app::AttributePathParams & path, const chip::Optional & dataVersion, + T value, typename std::enable_if::value>::type * = 0) + { + return mWriteClient->EncodeAttribute(path, value, dataVersion); + } + + template + CHIP_ERROR EncodeAttribute(const chip::app::AttributePathParams & path, const chip::Optional & dataVersion, + T value, typename std::enable_if::value>::type * = 0) + { + return mWriteClient->EncodeAttribute(path, *value, dataVersion); + } }; class InteractionModel : public InteractionModelReports, @@ -293,7 +345,12 @@ class InteractionModel : public InteractionModelReports, chip::DeviceProxy * device = GetDevice(identity); VerifyOrReturnError(device != nullptr, CHIP_ERROR_INCORRECT_STATE); - return InteractionModelWriter::WriteAttribute(device, endpointId, clusterId, attributeId, value, timedInteractionTimeoutMs); + std::vector endpointIds = { endpointId }; + std::vector clusterIds = { clusterId }; + std::vector attributeIds = { attributeId }; + + return InteractionModelWriter::WriteAttribute(device, endpointIds, clusterIds, attributeIds, value, + timedInteractionTimeoutMs, suppressResponse, dataVersion); } template