From 9451aa5dd3c1c928d296492dff14ae24dca072ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Mon, 16 Dec 2024 16:12:58 +0100 Subject: [PATCH 01/19] Update spec_clusters.md (#36850) Fix script reference --- docs/ids_and_codes/spec_clusters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ids_and_codes/spec_clusters.md b/docs/ids_and_codes/spec_clusters.md index 43db0725793a8a..2500e7de00ee2f 100644 --- a/docs/ids_and_codes/spec_clusters.md +++ b/docs/ids_and_codes/spec_clusters.md @@ -1,5 +1,5 @@ # List of currently defined spec clusters -This file was **AUTOMATICALLY** generated by `python scripts/generate_spec_xml.py`. DO NOT EDIT BY HAND! +This file was **AUTOMATICALLY** generated. Refer to this page: [data_model](/data_model/README.md). DO NOT EDIT BY HAND! | ID (Decimal) | ID (hex) | Name | |--------------|----------|----------------------------------------------------------| From d162e3a92f1033bff9d6d8675bb7b961b8c1d8a7 Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Mon, 16 Dec 2024 16:33:10 +0100 Subject: [PATCH 02/19] Bash completion for chip example applications (#36841) --- scripts/helpers/bash-completion.sh | 104 ++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 15 deletions(-) diff --git a/scripts/helpers/bash-completion.sh b/scripts/helpers/bash-completion.sh index 6737f2149cc5f9..26239419d3e587 100644 --- a/scripts/helpers/bash-completion.sh +++ b/scripts/helpers/bash-completion.sh @@ -28,6 +28,58 @@ _chip_tool_get_options() { "$@" --help 2>&1 | awk -F'[[]|[]]' '/^[[]--/{ print $2 }' } +_chip_app() { + + local cur prev words cword split + _init_completion -s || return + + case "$prev" in + --ble-device) + readarray -t words < <(ls -I '*:*' /sys/class/bluetooth) + # Get the list of Bluetooth devices without the 'hci' prefix. + readarray -t COMPREPLY < <(compgen -W "${words[*]#hci}" -- "$cur") + return + ;; + --custom-flow) + readarray -t COMPREPLY < <(compgen -W "0 1 2" -- "$cur") + return + ;; + --capabilities) + # The capabilities option is a bit-field with 3 bits currently defined. + readarray -t COMPREPLY < <(compgen -W "001 010 011 100 101 111" -- "$cur") + return + ;; + --KVS) + _filedir + return + ;; + --PICS) + _filedir + return + ;; + --trace_file) + _filedir + return + ;; + --trace_log | --trace_decode) + readarray -t COMPREPLY < <(compgen -W "0 1" -- "$cur") + return + ;; + --trace-to) + readarray -t COMPREPLY < <(compgen -W "json perfetto" -- "$cur") + compopt -o nospace + return + ;; + esac + + case "$cur" in + -*) + readarray -t COMPREPLY < <(compgen -W "$(_parse_help "$1")" -- "$cur") + ;; + esac + +} + _chip_tool() { local cur prev words cword split @@ -36,34 +88,56 @@ _chip_tool() { # Get command line arguments up to the cursor position local args=("${COMP_WORDS[@]:0:$cword+1}") - local command=0 case "$prev" in --commissioner-name) readarray -t COMPREPLY < <(compgen -W "alpha beta gamma 4 5 6 7 8 9" -- "$cur") + return + ;; + --only-allow-trusted-cd-keys) + readarray -t COMPREPLY < <(compgen -W "0 1" -- "$cur") + return ;; - --paa-trust-store-path | --cd-trust-store-path) + --paa-trust-store-path | --cd-trust-store-path | --dac-revocation-set-path) _filedir -d + return ;; --storage-directory) _filedir -d + return ;; - *) - command=1 + --trace-to) + readarray -t COMPREPLY < <(compgen -W "json perfetto" -- "$cur") + compopt -o nospace + return ;; esac - if [ "$command" -eq 1 ]; then - case "$cur" in - -*) - words=$(_chip_tool_get_options "${args[@]}") - ;; - *) - words=$(_chip_tool_get_commands "${args[@]}") - ;; - esac - readarray -t COMPREPLY < <(compgen -W "$words" -- "$cur") - fi + case "$cur" in + -*) + words=$(_chip_tool_get_options "${args[@]}") + ;; + *) + words=$(_chip_tool_get_commands "${args[@]}") + ;; + esac + readarray -t COMPREPLY < <(compgen -W "$words" -- "$cur") } +complete -F _chip_app chip-air-purifier-app +complete -F _chip_app chip-all-clusters-app +complete -F _chip_app chip-bridge-app +complete -F _chip_app chip-dishwasher-app +complete -F _chip_app chip-energy-management-app +complete -F _chip_app chip-lighting-app +complete -F _chip_app chip-lock-app +complete -F _chip_app chip-log-source-app +complete -F _chip_app chip-microwave-oven-app +complete -F _chip_app chip-ota-provider-app +complete -F _chip_app chip-ota-requestor-app +complete -F _chip_app chip-refrigerator-app +complete -F _chip_app chip-rvc-app +complete -F _chip_app chip-tv-app +complete -F _chip_app chip-tv-casting-app + complete -F _chip_tool chip-tool From 43f66f00b084dac758021c8e1779cc7bf1603133 Mon Sep 17 00:00:00 2001 From: Wang Qixiang <43193572+wqx6@users.noreply.github.com> Date: Tue, 17 Dec 2024 01:07:09 +0800 Subject: [PATCH 03/19] Make XOccupiedToUnoccupiedDelay attributes in OccupancySensing cluster managed by AAI (#36777) * Make XOccupiedToUnoccupiedDelay attributes managed by AAI * add document * add more document --- .../all-clusters-app.matter | 4 +- .../placeholder/linux/apps/app1/config.matter | 6 +- .../placeholder/linux/apps/app2/config.matter | 6 +- .../occupancy-sensor-server.cpp | 14 +- .../zcl/zcl-with-test-extensions.json | 9 +- src/app/zap-templates/zcl/zcl.json | 9 +- .../zap-generated/attributes/Accessors.cpp | 141 ------------------ .../zap-generated/attributes/Accessors.h | 18 --- 8 files changed, 30 insertions(+), 177 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index fb770209b996a3..071a3fcf7c5b76 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -9047,7 +9047,7 @@ endpoint 1 { ram attribute occupancySensorTypeBitmap default = 1; callback attribute holdTime; callback attribute holdTimeLimits; - ram attribute PIROccupiedToUnoccupiedDelay default = 10; + callback attribute PIROccupiedToUnoccupiedDelay; callback attribute featureMap; ram attribute clusterRevision default = 5; } @@ -9505,7 +9505,7 @@ endpoint 2 { ram attribute occupancySensorTypeBitmap default = 1; callback attribute holdTime; callback attribute holdTimeLimits; - ram attribute PIROccupiedToUnoccupiedDelay default = 10; + callback attribute PIROccupiedToUnoccupiedDelay; callback attribute featureMap; ram attribute clusterRevision default = 5; } diff --git a/examples/placeholder/linux/apps/app1/config.matter b/examples/placeholder/linux/apps/app1/config.matter index a6a1aa5c7f5a64..fe5fe0bfe6d84b 100644 --- a/examples/placeholder/linux/apps/app1/config.matter +++ b/examples/placeholder/linux/apps/app1/config.matter @@ -9645,13 +9645,13 @@ endpoint 1 { ram attribute occupancy; ram attribute occupancySensorType; ram attribute occupancySensorTypeBitmap; - ram attribute PIROccupiedToUnoccupiedDelay default = 0x00; + callback attribute PIROccupiedToUnoccupiedDelay; ram attribute PIRUnoccupiedToOccupiedDelay default = 0x00; ram attribute PIRUnoccupiedToOccupiedThreshold default = 1; - ram attribute ultrasonicOccupiedToUnoccupiedDelay default = 0x00; + callback attribute ultrasonicOccupiedToUnoccupiedDelay; ram attribute ultrasonicUnoccupiedToOccupiedDelay default = 0x00; ram attribute ultrasonicUnoccupiedToOccupiedThreshold default = 1; - ram attribute physicalContactOccupiedToUnoccupiedDelay default = 0x00; + callback attribute physicalContactOccupiedToUnoccupiedDelay; ram attribute physicalContactUnoccupiedToOccupiedDelay default = 0x00; ram attribute physicalContactUnoccupiedToOccupiedThreshold default = 1; callback attribute featureMap; diff --git a/examples/placeholder/linux/apps/app2/config.matter b/examples/placeholder/linux/apps/app2/config.matter index 0373748d9de69e..68de2f9ffba90e 100644 --- a/examples/placeholder/linux/apps/app2/config.matter +++ b/examples/placeholder/linux/apps/app2/config.matter @@ -9540,13 +9540,13 @@ endpoint 1 { ram attribute occupancy; ram attribute occupancySensorType; ram attribute occupancySensorTypeBitmap; - ram attribute PIROccupiedToUnoccupiedDelay default = 0x00; + callback attribute PIROccupiedToUnoccupiedDelay; ram attribute PIRUnoccupiedToOccupiedDelay default = 0x00; ram attribute PIRUnoccupiedToOccupiedThreshold default = 1; - ram attribute ultrasonicOccupiedToUnoccupiedDelay default = 0x00; + callback attribute ultrasonicOccupiedToUnoccupiedDelay; ram attribute ultrasonicUnoccupiedToOccupiedDelay default = 0x00; ram attribute ultrasonicUnoccupiedToOccupiedThreshold default = 1; - ram attribute physicalContactOccupiedToUnoccupiedDelay default = 0x00; + callback attribute physicalContactOccupiedToUnoccupiedDelay; ram attribute physicalContactUnoccupiedToOccupiedDelay default = 0x00; ram attribute physicalContactUnoccupiedToOccupiedThreshold default = 1; callback attribute featureMap; diff --git a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp index cd7ba5b8f659c2..03eaaa46475d1c 100644 --- a/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp +++ b/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp @@ -59,8 +59,12 @@ CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValu case Attributes::FeatureMap::Id: ReturnErrorOnFailure(aEncoder.Encode(mFeature)); break; - case Attributes::HoldTime::Id: { - + case Attributes::HoldTime::Id: + case Attributes::PIROccupiedToUnoccupiedDelay::Id: + case Attributes::UltrasonicOccupiedToUnoccupiedDelay::Id: + case Attributes::PhysicalContactOccupiedToUnoccupiedDelay::Id: { + // HoldTime is equivalent to the legacy *OccupiedToUnoccupiedDelay attributes. + // The AAI will read/write these attributes at the same storage for one endpoint. uint16_t * holdTime = GetHoldTimeForEndpoint(aPath.mEndpointId); if (holdTime == nullptr) @@ -190,12 +194,6 @@ CHIP_ERROR SetHoldTime(EndpointId endpointId, uint16_t newHoldTime) MatterReportingAttributeChangeCallback(endpointId, OccupancySensing::Id, Attributes::HoldTime::Id); } - // Blindly try to write RAM-backed legacy attributes (will fail silently if absent) - // to keep them in sync. - (void) Attributes::PIROccupiedToUnoccupiedDelay::Set(endpointId, newHoldTime); - (void) Attributes::UltrasonicOccupiedToUnoccupiedDelay::Set(endpointId, newHoldTime); - (void) Attributes::PhysicalContactOccupiedToUnoccupiedDelay::Set(endpointId, newHoldTime); - return CHIP_NO_ERROR; } diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index 0912be1df2db37..14179bb5566bfc 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -294,7 +294,14 @@ "ClientsSupportedPerFabric", "MaximumCheckInBackOff" ], - "Occupancy Sensing": ["HoldTimeLimits", "HoldTime", "FeatureMap"], + "Occupancy Sensing": [ + "HoldTimeLimits", + "HoldTime", + "PIROccupiedToUnoccupiedDelay", + "UltrasonicOccupiedToUnoccupiedDelay", + "PhysicalContactOccupiedToUnoccupiedDelay", + "FeatureMap" + ], "Operational Credentials": [ "SupportedFabrics", "CommissionedFabrics", diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index 3a62c4c84ca6eb..728d3acdad1f06 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -288,7 +288,14 @@ "ClientsSupportedPerFabric", "MaximumCheckInBackOff" ], - "Occupancy Sensing": ["HoldTimeLimits", "HoldTime", "FeatureMap"], + "Occupancy Sensing": [ + "HoldTimeLimits", + "HoldTime", + "PIROccupiedToUnoccupiedDelay", + "UltrasonicOccupiedToUnoccupiedDelay", + "PhysicalContactOccupiedToUnoccupiedDelay", + "FeatureMap" + ], "Operational Credentials": [ "SupportedFabrics", "CommissionedFabrics", diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp index afb3da76dc8bc3..10f67cad3ffd77 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp @@ -32754,53 +32754,6 @@ Protocols::InteractionModel::Status Set(EndpointId endpoint, } // namespace OccupancySensorTypeBitmap -namespace PIROccupiedToUnoccupiedDelay { - -Protocols::InteractionModel::Status Get(EndpointId endpoint, uint16_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - Protocols::InteractionModel::Status status = - emberAfReadAttribute(endpoint, Clusters::OccupancySensing::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - *value = Traits::StorageToWorking(temp); - return status; -} - -Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value, MarkAttributeDirty markDirty) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(ConcreteAttributePath(endpoint, Clusters::OccupancySensing::Id, Id), - EmberAfWriteDataInput(writable, ZCL_INT16U_ATTRIBUTE_TYPE).SetMarkDirty(markDirty)); -} - -Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::OccupancySensing::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE); -} - -} // namespace PIROccupiedToUnoccupiedDelay - namespace PIRUnoccupiedToOccupiedDelay { Protocols::InteractionModel::Status Get(EndpointId endpoint, uint16_t * value) @@ -32895,53 +32848,6 @@ Protocols::InteractionModel::Status Set(EndpointId endpoint, uint8_t value) } // namespace PIRUnoccupiedToOccupiedThreshold -namespace UltrasonicOccupiedToUnoccupiedDelay { - -Protocols::InteractionModel::Status Get(EndpointId endpoint, uint16_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - Protocols::InteractionModel::Status status = - emberAfReadAttribute(endpoint, Clusters::OccupancySensing::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - *value = Traits::StorageToWorking(temp); - return status; -} - -Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value, MarkAttributeDirty markDirty) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(ConcreteAttributePath(endpoint, Clusters::OccupancySensing::Id, Id), - EmberAfWriteDataInput(writable, ZCL_INT16U_ATTRIBUTE_TYPE).SetMarkDirty(markDirty)); -} - -Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::OccupancySensing::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE); -} - -} // namespace UltrasonicOccupiedToUnoccupiedDelay - namespace UltrasonicUnoccupiedToOccupiedDelay { Protocols::InteractionModel::Status Get(EndpointId endpoint, uint16_t * value) @@ -33036,53 +32942,6 @@ Protocols::InteractionModel::Status Set(EndpointId endpoint, uint8_t value) } // namespace UltrasonicUnoccupiedToOccupiedThreshold -namespace PhysicalContactOccupiedToUnoccupiedDelay { - -Protocols::InteractionModel::Status Get(EndpointId endpoint, uint16_t * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - Protocols::InteractionModel::Status status = - emberAfReadAttribute(endpoint, Clusters::OccupancySensing::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - *value = Traits::StorageToWorking(temp); - return status; -} - -Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value, MarkAttributeDirty markDirty) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(ConcreteAttributePath(endpoint, Clusters::OccupancySensing::Id, Id), - EmberAfWriteDataInput(writable, ZCL_INT16U_ATTRIBUTE_TYPE).SetMarkDirty(markDirty)); -} - -Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::OccupancySensing::Id, Id, writable, ZCL_INT16U_ATTRIBUTE_TYPE); -} - -} // namespace PhysicalContactOccupiedToUnoccupiedDelay - namespace PhysicalContactUnoccupiedToOccupiedDelay { Protocols::InteractionModel::Status Get(EndpointId endpoint, uint16_t * value) diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h index c79c0657c5b11b..d77633d6d72bbc 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h @@ -4913,12 +4913,6 @@ Protocols::InteractionModel::Status Set(EndpointId endpoint, MarkAttributeDirty markDirty); } // namespace OccupancySensorTypeBitmap -namespace PIROccupiedToUnoccupiedDelay { -Protocols::InteractionModel::Status Get(EndpointId endpoint, uint16_t * value); // int16u -Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value); -Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value, MarkAttributeDirty markDirty); -} // namespace PIROccupiedToUnoccupiedDelay - namespace PIRUnoccupiedToOccupiedDelay { Protocols::InteractionModel::Status Get(EndpointId endpoint, uint16_t * value); // int16u Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value); @@ -4931,12 +4925,6 @@ Protocols::InteractionModel::Status Set(EndpointId endpoint, uint8_t value); Protocols::InteractionModel::Status Set(EndpointId endpoint, uint8_t value, MarkAttributeDirty markDirty); } // namespace PIRUnoccupiedToOccupiedThreshold -namespace UltrasonicOccupiedToUnoccupiedDelay { -Protocols::InteractionModel::Status Get(EndpointId endpoint, uint16_t * value); // int16u -Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value); -Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value, MarkAttributeDirty markDirty); -} // namespace UltrasonicOccupiedToUnoccupiedDelay - namespace UltrasonicUnoccupiedToOccupiedDelay { Protocols::InteractionModel::Status Get(EndpointId endpoint, uint16_t * value); // int16u Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value); @@ -4949,12 +4937,6 @@ Protocols::InteractionModel::Status Set(EndpointId endpoint, uint8_t value); Protocols::InteractionModel::Status Set(EndpointId endpoint, uint8_t value, MarkAttributeDirty markDirty); } // namespace UltrasonicUnoccupiedToOccupiedThreshold -namespace PhysicalContactOccupiedToUnoccupiedDelay { -Protocols::InteractionModel::Status Get(EndpointId endpoint, uint16_t * value); // int16u -Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value); -Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value, MarkAttributeDirty markDirty); -} // namespace PhysicalContactOccupiedToUnoccupiedDelay - namespace PhysicalContactUnoccupiedToOccupiedDelay { Protocols::InteractionModel::Status Get(EndpointId endpoint, uint16_t * value); // int16u Protocols::InteractionModel::Status Set(EndpointId endpoint, uint16_t value); From 33dda32476a032eb96ff42e442ffea2a39871d28 Mon Sep 17 00:00:00 2001 From: Jake Ororke Date: Mon, 16 Dec 2024 13:02:13 -0800 Subject: [PATCH 04/19] [Fix] Possible fix for matter-test-scripts issue #227: Remove PICS from OPSTATE tests (#34290) * Possible fix for matter-test-scripts issue #227: - Removed PICS checks and replaced with attribute and command checks from endpoint during tests. * Restyled by autopep8 * Updated TC_OpstateCommon.py: - Removed some variables that were no longer needed * Updated TC_RVCOPSTATE_2_1 test module: - Removed automatable PICS checks and replaced with attributes available to be gathered from endpoint. * Restyled by autopep8 * Restyled by isort * Updated TC_RVCOPSTATE_2_1 test module: - Adding back in missing time import and test runner comments into test module * Updated TC_RVCOPSTATE_2_1 test module: - Replaced input() with wait_for_user_input() in test script - Added back in short sleep to script, not sure why it got removed. * Resolving Linting issue in TC_RVCOPSTATE_2_1: - Had to remove "test_step" variable that was attempting to be called in wait_for_user_input() as it was not being defined earlier in the test module. * Updating TC_RVCOPSTATE_2_1 test module: - Minor change to remove unneeded f-string from wait_for_user_input(). * Updated TC_RVCOPSTATE_2_1 test module: - Re-imported the test_step variable for test steps 6 and 7 manual testing that were accidentally removed - Re-imported the variable being called in the self.wait_for_user_input() * Updated TC_RVCOPSTATE_2_1 test module: - Replaced missing test_step variable and calls for it in self.wait_for_user_input() * Restyled by autopep8 * Updated TC_OpstateCommon and TC_RVCOPSTATE_2_1: - Removed oprtnlstate_attr_id variable and if statements as it is a mandatory attribute. - Created new common functions in OpstateCommon test module to create dictionary containing attributes and commands. - Renamed some variables that had upper case letters to contain only lower case letters. - Removed creating variable for events and returned PICS checks for those in TC_OpstateCommon test module as not currently able to automate * Restyled by autopep8 * Updated TC_OpstateCommon module: - Removed unneeded local variable "phase_list_attr_id" as lint mentioned it is not being used in test 2_3. * Updated TC_OpstateCommon and TC_RVCOPSTATE_2_1: - Removed variable functions and replaced with calling named attributes in if checks directly. * Restyled by autopep8 * Updated matter_testing_support, OpstateCommon, and RVCOPSTATE_2_1 modules: - Added attributes_guard to matter_testing_support helper module to check if attributes are in attributes list using has_attributes function - Changed attributes checks to using attributes_guard function in OpstateCommon and RVCOPSTATE_2_1 test modules * Restyled by autopep8 * Restyled by isort * Updated TC_OpstateCommon.py: - Resolved linting errors * Updating method for attributes_guard functionality * Updated TC_RVCOPSTATE_2_1 test module: - Debugging to find issue why test is failing in CI pipeline. * Updating TC_RVCOPSTATE_2_1 test module: - Continuing effort to resolve issue with CI pipeline * Updated TC_OpstateCommon, TC_RVCOPSTATE_2_1, and matter_testing support: - Resolved issues with attributes_guard function in matter_testing support module * Restyled by autopep8 * Updated TC_RVCOPSTATE_2_1 test module: - changed verbosity in CI arguments to make it quieter. * Updating matter_testing support module: - Updated attributes_guard function to make it async * Updating TC_OpstateCommon and TC_RVCOPSTATE_2_1 test modules: - Updated method for attributes_guard functionality. - Added additional check to make sure that endpoint is not 0 or not provided in command line * Restyled by autopep8 * Updated matter_testing helper module: - Resolved linting error * Updating TC_RVCOPSTATE_2_1 test module: - Resolving linting error * Update src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py Adding coding change from Cecille! Co-authored-by: C Freeman * Updating OPSTATECommon and RVCOPSTATE_2_1 modules: - Updated to using attribute_guard function in place of attributes_guard. * Updated matter_testing, added new TC_TestAttrAvail modules: - Updated matter_testing support module to include new command_guard() and feature_guard() - Created standalone test to show that guard functionality works for CASE, PASE, and no factory reset commissioning - Added TC_TestAttrAvail to slow tests as it takes ~30 seconds to run the tests * Restyled by autopep8 * Restyled by isort * Updated TC_OpstateCommon python module: - Updated to using new command_guard() for OPSTATE tests * Updated matter_testing, TC_OpstateCommon, and TC_TestAttrAvail modules: - Resolving linting errors * Restyled by isort * Update src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py Adding commi from Cecille to the code here to help better clarify and explain reasoning for this coding change. Co-authored-by: C Freeman --------- Co-authored-by: Restyled.io Co-authored-by: C Freeman --- src/python_testing/TC_OpstateCommon.py | 335 ++++++++---------- src/python_testing/TC_RVCOPSTATE_2_1.py | 17 +- src/python_testing/TC_TestAttrAvail.py | 164 +++++++++ .../chip/testing/matter_testing.py | 101 ++++++ src/python_testing/test_metadata.yaml | 1 + 5 files changed, 433 insertions(+), 185 deletions(-) create mode 100644 src/python_testing/TC_TestAttrAvail.py diff --git a/src/python_testing/TC_OpstateCommon.py b/src/python_testing/TC_OpstateCommon.py index 557b7606ccbea3..1a4cfbe7150e30 100644 --- a/src/python_testing/TC_OpstateCommon.py +++ b/src/python_testing/TC_OpstateCommon.py @@ -210,8 +210,8 @@ def STEPS_TC_OPSTATE_BASE_1_1(self) -> list[TestStep]: async def TEST_TC_OPSTATE_BASE_1_1(self, endpoint=1, cluster_revision=1, feature_map=0): cluster = self.test_info.cluster attributes = cluster.Attributes - events = cluster.Events commands = cluster.Commands + events = cluster.Events self.init_test() @@ -245,7 +245,7 @@ async def TEST_TC_OPSTATE_BASE_1_1(self, endpoint=1, cluster_revision=1, feature attributes.ClusterRevision.attribute_id ] - if self.check_pics(f"{self.test_info.pics_code}.S.A0002"): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.CountdownTime): expected_value.append(attributes.CountdownTime.attribute_id) await self.read_and_expect_array_contains(endpoint=endpoint, @@ -259,7 +259,7 @@ async def TEST_TC_OPSTATE_BASE_1_1(self, endpoint=1, cluster_revision=1, feature events.OperationalError.event_id, ] - if self.check_pics(f"{self.test_info.pics_code}.S.E01"): + if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.E01")): expected_value.append(events.OperationCompletion.event_id) await self.read_and_expect_array_contains(endpoint=endpoint, @@ -270,19 +270,19 @@ async def TEST_TC_OPSTATE_BASE_1_1(self, endpoint=1, cluster_revision=1, feature self.step(6) expected_value = [] - if (self.check_pics(f"{self.test_info.pics_code}.S.C00.Rsp") or - self.check_pics(f"{self.test_info.pics_code}.S.C03.Rsp")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Pause)) or + (await self.command_guard(endpoint=endpoint, command=commands.Resume))): expected_value.append(commands.Pause.command_id) - if (self.check_pics(f"{self.test_info.pics_code}.S.C01.Rsp") or - self.check_pics(f"{self.test_info.pics_code}.S.C02.Rsp")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Stop)) or + (await self.command_guard(endpoint=endpoint, command=commands.Start))): expected_value.append(commands.Stop.command_id) - if self.check_pics(f"{self.test_info.pics_code}.S.C02.Rsp"): + if await self.command_guard(endpoint=endpoint, command=commands.Start): expected_value.append(commands.Start.command_id) - if (self.check_pics(f"{self.test_info.pics_code}.S.C03.Rsp") or - self.check_pics(f"{self.test_info.pics_code}.S.C00.Rsp")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Pause)) or + (await self.command_guard(endpoint=endpoint, command=commands.Resume))): expected_value.append(commands.Resume.command_id) await self.read_and_expect_array_contains(endpoint=endpoint, @@ -293,10 +293,10 @@ async def TEST_TC_OPSTATE_BASE_1_1(self, endpoint=1, cluster_revision=1, feature self.step(7) expected_value = [] - if (self.check_pics(f"{self.test_info.pics_code}.S.C00.Rsp") or - self.check_pics(f"{self.test_info.pics_code}.S.C01.Rsp") or - self.check_pics(f"{self.test_info.pics_code}.S.C02.Rsp") or - self.check_pics(f"{self.test_info.pics_code}.S.C03.Rsp")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Pause)) or + (await self.command_guard(endpoint=endpoint, command=commands.Resume)) or + (await self.command_guard(endpoint=endpoint, command=commands.Stop)) or + (await self.command_guard(endpoint=endpoint, command=commands.Start))): expected_value.append(commands.OperationalCommandResponse.command_id) await self.read_and_expect_array_contains(endpoint=endpoint, @@ -344,7 +344,7 @@ async def TEST_TC_OPSTATE_BASE_2_1(self, endpoint=1): # STEP 2: TH reads from the DUT the PhaseList attribute self.step(2) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0000")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.PhaseList): phase_list = await self.read_expect_success(endpoint=endpoint, attribute=attributes.PhaseList) if phase_list is not NullValue: @@ -354,7 +354,7 @@ async def TEST_TC_OPSTATE_BASE_2_1(self, endpoint=1): # STEP 3: TH reads from the DUT the CurrentPhase attribute self.step(3) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0001")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.CurrentPhase): current_phase = await self.read_expect_success(endpoint=endpoint, attribute=attributes.CurrentPhase) if (phase_list == NullValue) or (not phase_list): @@ -366,7 +366,7 @@ async def TEST_TC_OPSTATE_BASE_2_1(self, endpoint=1): # STEP 4: TH reads from the DUT the CountdownTime attribute self.step(4) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0002")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.CountdownTime): countdown_time = await self.read_expect_success(endpoint=endpoint, attribute=attributes.CountdownTime) if countdown_time is not NullValue: @@ -375,7 +375,7 @@ async def TEST_TC_OPSTATE_BASE_2_1(self, endpoint=1): # STEP 5: TH reads from the DUT the OperationalStateList attribute self.step(5) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0003")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.OperationalStateList): operational_state_list = await self.read_expect_success(endpoint=endpoint, attribute=attributes.OperationalStateList) defined_states = [state.value for state in cluster.Enums.OperationalStateEnum @@ -396,73 +396,72 @@ async def TEST_TC_OPSTATE_BASE_2_1(self, endpoint=1): # STEP 6: TH reads from the DUT the OperationalState attribute self.step(6) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0004")): - operational_state = await self.read_expect_success(endpoint=endpoint, - attribute=attributes.OperationalState) - in_range = (0x80 <= operational_state <= 0xBF) - asserts.assert_true(operational_state in defined_states or in_range, - "OperationalState has an invalid ID value!") - - # STEP 6a: Manually put the device in the Stopped(0x00) operational state - self.step("6a") - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.M.ST_STOPPED")): - self.send_manual_or_pipe_command(name="OperationalStateChange", - device=self.device, - operation="Stop") - # STEP 6b: TH reads from the DUT the OperationalState attribute - self.step("6b") - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kStopped) - else: - self.skip_step("6b") + operational_state = await self.read_expect_success(endpoint=endpoint, + attribute=attributes.OperationalState) + in_range = (0x80 <= operational_state <= 0xBF) + asserts.assert_true(operational_state in defined_states or in_range, + "OperationalState has an invalid ID value!") + + # STEP 6a: Manually put the device in the Stopped(0x00) operational state + self.step("6a") + if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.M.ST_STOPPED")): + self.send_manual_or_pipe_command(name="OperationalStateChange", + device=self.device, + operation="Stop") + # STEP 6b: TH reads from the DUT the OperationalState attribute + self.step("6b") + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kStopped) + else: + self.skip_step("6b") - # STEP 6c: Manually put the device in the Running(0x01) operational state - self.step("6c") - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.M.ST_RUNNING")): - self.send_manual_or_pipe_command(name="OperationalStateChange", - device=self.device, - operation="Start") - # STEP 6d: TH reads from the DUT the OperationalState attribute - self.step("6d") - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kRunning) - else: - self.skip_step("6d") + # STEP 6c: Manually put the device in the Running(0x01) operational state + self.step("6c") + if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.M.ST_RUNNING")): + self.send_manual_or_pipe_command(name="OperationalStateChange", + device=self.device, + operation="Start") + # STEP 6d: TH reads from the DUT the OperationalState attribute + self.step("6d") + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kRunning) + else: + self.skip_step("6d") - # STEP 6e: Manually put the device in the Paused(0x02) operational state - self.step("6e") - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.M.ST_PAUSED")): - self.send_manual_or_pipe_command(name="OperationalStateChange", - device=self.device, - operation="Pause") - # STEP 6f: TH reads from the DUT the OperationalState attribute - self.step("6f") - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kPaused) - else: - self.skip_step("6f") + # STEP 6e: Manually put the device in the Paused(0x02) operational state + self.step("6e") + if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.M.ST_PAUSED")): + self.send_manual_or_pipe_command(name="OperationalStateChange", + device=self.device, + operation="Pause") + # STEP 6f: TH reads from the DUT the OperationalState attribute + self.step("6f") + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kPaused) + else: + self.skip_step("6f") - # STEP 6g: Manually put the device in the Error(0x03) operational state - self.step("6g") - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.M.ST_ERROR")): - self.send_manual_or_pipe_command(name="OperationalStateChange", - device=self.device, - operation="OnFault", - param=cluster.Enums.ErrorStateEnum.kUnableToStartOrResume) - # STEP 6h: TH reads from the DUT the OperationalState attribute - self.step("6h") - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kError) - else: - self.skip_step("6h") + # STEP 6g: Manually put the device in the Error(0x03) operational state + self.step("6g") + if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.M.ST_ERROR")): + self.send_manual_or_pipe_command(name="OperationalStateChange", + device=self.device, + operation="OnFault", + param=cluster.Enums.ErrorStateEnum.kUnableToStartOrResume) + # STEP 6h: TH reads from the DUT the OperationalState attribute + self.step("6h") + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kError) + else: + self.skip_step("6h") # STEP 7: TH reads from the DUT the OperationalError attribute self.step(7) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0005")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.OperationalError): operational_error = await self.read_expect_success(endpoint=endpoint, attribute=attributes.OperationalError) # Defined Errors @@ -566,7 +565,9 @@ def STEPS_TC_OPSTATE_BASE_2_2(self) -> list[TestStep]: async def TEST_TC_OPSTATE_BASE_2_2(self, endpoint=1): cluster = self.test_info.cluster attributes = cluster.Attributes + commands = cluster.Commands + generated_cmd_list = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attributes.GeneratedCommandList) self.init_test() @@ -595,7 +596,7 @@ async def TEST_TC_OPSTATE_BASE_2_2(self, endpoint=1): # STEP 3: TH reads from the DUT the OperationalStateList attribute self.step(3) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0003")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.OperationalStateList): operational_state_list = await self.read_expect_success(endpoint=endpoint, attribute=attributes.OperationalStateList) @@ -610,22 +611,20 @@ async def TEST_TC_OPSTATE_BASE_2_2(self, endpoint=1): # STEP 4: TH sends Start command to the DUT self.step(4) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C02.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Start)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Start(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) # STEP 5: TH reads from the DUT the OperationalState attribute self.step(5) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0004")): - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kRunning) + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kRunning) # STEP 6: TH reads from the DUT the OperationalError attribute self.step(6) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0005")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.OperationalError): await self.read_and_expect_property_value(endpoint=endpoint, attribute=attributes.OperationalError, attr_property="errorStateID", @@ -633,7 +632,7 @@ async def TEST_TC_OPSTATE_BASE_2_2(self, endpoint=1): # STEP 7: TH reads from the DUT the CountdownTime attribute self.step(7) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0002")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.CountdownTime): initial_countdown_time = await self.read_expect_success(endpoint=endpoint, attribute=attributes.CountdownTime) if initial_countdown_time is not NullValue: @@ -642,7 +641,7 @@ async def TEST_TC_OPSTATE_BASE_2_2(self, endpoint=1): # STEP 8: TH reads from the DUT the PhaseList attribute self.step(8) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0000")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.PhaseList): phase_list = await self.read_expect_success(endpoint=endpoint, attribute=attributes.PhaseList) phase_list_len = 0 @@ -653,7 +652,7 @@ async def TEST_TC_OPSTATE_BASE_2_2(self, endpoint=1): # STEP 9: TH reads from the DUT the CurrentPhase attribute self.step(9) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0001")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.CurrentPhase): current_phase = await self.read_expect_success(endpoint=endpoint, attribute=attributes.CurrentPhase) if (phase_list == NullValue) or (not phase_list): @@ -666,12 +665,12 @@ async def TEST_TC_OPSTATE_BASE_2_2(self, endpoint=1): # STEP 10: TH waits for {PIXIT.WAITTIME.COUNTDOWN} self.step(10) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0002")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.CountdownTime): time.sleep(wait_time) # STEP 11: TH reads from the DUT the CountdownTime attribute self.step(11) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0002")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.CountdownTime): countdown_time = await self.read_expect_success(endpoint=endpoint, attribute=attributes.CountdownTime) @@ -683,31 +682,27 @@ async def TEST_TC_OPSTATE_BASE_2_2(self, endpoint=1): # STEP 12: TH sends Start command to the DUT self.step(12) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C02.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Start)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Start(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) # STEP 13: TH sends Stop command to the DUT self.step(13) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C01.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Stop)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Stop(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) # STEP 14: TH reads from the DUT the OperationalState attribute self.step(14) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0004")): - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kStopped) + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kStopped) # STEP 15: TH sends Stop command to the DUT self.step(15) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C01.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Stop)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Stop(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) @@ -722,9 +717,9 @@ async def TEST_TC_OPSTATE_BASE_2_2(self, endpoint=1): # STEP 17: TH sends Start command to the DUT self.step(17) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.M.ERR_UNABLE_TO_START_OR_RESUME") and - self.check_pics(f"{self.test_info.pics_code}.S.C02.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if self.pics_guard((self.check_pics(f"{self.test_info.pics_code}.S.M.ERR_UNABLE_TO_START_OR_RESUME")) and + ((await self.command_guard(endpoint=endpoint, command=commands.Start)) and + (commands.OperationalCommandResponse.command_id in generated_cmd_list))): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Start(), expected_response=cluster.Enums.ErrorStateEnum.kUnableToStartOrResume) @@ -757,7 +752,9 @@ def STEPS_TC_OPSTATE_BASE_2_3(self) -> list[TestStep]: async def TEST_TC_OPSTATE_BASE_2_3(self, endpoint=1): cluster = self.test_info.cluster attributes = cluster.Attributes + commands = cluster.Commands + generated_cmd_list = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attributes.GeneratedCommandList) self.init_test() @@ -786,37 +783,34 @@ async def TEST_TC_OPSTATE_BASE_2_3(self, endpoint=1): # STEP 3: TH reads from the DUT the OperationalStateList attribute self.step(3) - if self.pics_guard(self.check_pics((f"{self.test_info.pics_code}.S.A0003"))): - operational_state_list = await self.read_expect_success(endpoint=endpoint, - attribute=attributes.OperationalStateList) + operational_state_list = await self.read_expect_success(endpoint=endpoint, + attribute=attributes.OperationalStateList) - operational_state_list_ids = [op_state.operationalStateID for op_state in operational_state_list] + operational_state_list_ids = [op_state.operationalStateID for op_state in operational_state_list] - defined_states = [state.value for state in cluster.Enums.OperationalStateEnum - if state != cluster.Enums.OperationalStateEnum.kUnknownEnumValue] + defined_states = [state.value for state in cluster.Enums.OperationalStateEnum + if state != cluster.Enums.OperationalStateEnum.kUnknownEnumValue] - for state in defined_states: - if state not in operational_state_list_ids: - asserts.fail(f"The list shall include structs with the following OperationalStateIds: {defined_states}") + for state in defined_states: + if state not in operational_state_list_ids: + asserts.fail(f"The list shall include structs with the following OperationalStateIds: {defined_states}") # STEP 4: TH sends Pause command to the DUT self.step(4) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C00.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Pause)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Pause(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) # STEP 5: TH reads from the DUT the OperationalState attribute self.step(5) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0004")): - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kPaused) + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kPaused) # STEP 6: TH reads from the DUT the CountdownTime attribute self.step(6) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0002")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.CountdownTime): initial_countdown_time = await self.read_expect_success(endpoint=endpoint, attribute=attributes.CountdownTime) if initial_countdown_time is not NullValue: @@ -830,7 +824,7 @@ async def TEST_TC_OPSTATE_BASE_2_3(self, endpoint=1): # STEP 8: TH reads from the DUT the CountdownTime attribute self.step(8) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0002")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.CountdownTime): countdown_time = await self.read_expect_success(endpoint=endpoint, attribute=attributes.CountdownTime) @@ -842,31 +836,27 @@ async def TEST_TC_OPSTATE_BASE_2_3(self, endpoint=1): # STEP 9: TH sends Pause command to the DUT self.step(9) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C00.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Pause)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Pause(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) # STEP 10: TH sends Resume command to the DUT self.step(10) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C03.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Resume)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Resume(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) # STEP 11: TH reads from the DUT the OperationalState attribute self.step(11) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0004")): - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kRunning) + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kRunning) # STEP 12: TH sends Resume command to the DUT self.step(12) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C03.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Resume)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Resume(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) @@ -880,16 +870,14 @@ async def TEST_TC_OPSTATE_BASE_2_3(self, endpoint=1): # STEP 14: TH sends Pause command to the DUT self.step(14) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C00.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Pause)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Pause(), expected_response=cluster.Enums.ErrorStateEnum.kCommandInvalidInState) # STEP 15: TH sends Resume command to the DUT self.step(15) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C03.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Resume)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Resume(), expected_response=cluster.Enums.ErrorStateEnum.kCommandInvalidInState) @@ -904,16 +892,14 @@ async def TEST_TC_OPSTATE_BASE_2_3(self, endpoint=1): # STEP 17: TH sends Pause command to the DUT self.step(17) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C00.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Pause)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Pause(), expected_response=cluster.Enums.ErrorStateEnum.kCommandInvalidInState) # STEP 18: TH sends Resume command to the DUT self.step(18) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C03.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Resume)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Resume(), expected_response=cluster.Enums.ErrorStateEnum.kCommandInvalidInState) @@ -946,7 +932,7 @@ async def TEST_TC_OPSTATE_BASE_2_4(self, endpoint=1): # STEP 1: Commission DUT to TH (can be skipped if done in a preceding test) self.step(1) - if self.pics_guard(error_event_gen): + if error_event_gen: # STEP 2: Set up a subscription to the OperationalError event self.step(2) # Subscribe to Events and when they are sent push them to a queue for checking later @@ -976,10 +962,11 @@ async def TEST_TC_OPSTATE_BASE_2_4(self, endpoint=1): # STEP 4: TH reads from the DUT the OperationalState attribute self.step(4) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0004")): - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kError) + + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kError) + else: self.skip_step(2) self.skip_step(3) @@ -1017,7 +1004,10 @@ def STEPS_TC_OPSTATE_BASE_2_5(self) -> list[TestStep]: async def TEST_TC_OPSTATE_BASE_2_5(self, endpoint=1): cluster = self.test_info.cluster attributes = cluster.Attributes + commands = cluster.Commands + generated_cmd_list = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attributes.GeneratedCommandList) + events = cluster.Events self.init_test() @@ -1058,25 +1048,23 @@ async def TEST_TC_OPSTATE_BASE_2_5(self, endpoint=1): # STEP 4: TH sends Start command to the DUT self.step(4) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C02.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Start)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Start(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) # STEP 5: TH reads from the DUT the CountdownTime attribute self.step(5) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0002")): + if await self.attribute_guard(endpoint=endpoint, attribute=attributes.CountdownTime): initial_countdown_time = await self.read_expect_success(endpoint=endpoint, attribute=attributes.CountdownTime) if initial_countdown_time is not NullValue: # STEP 6: TH reads from the DUT the OperationalState attribute self.step(6) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0004")): - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kRunning) + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kRunning) # STEP 7: TH waits for initial-countdown-time self.step(7) @@ -1085,8 +1073,7 @@ async def TEST_TC_OPSTATE_BASE_2_5(self, endpoint=1): # STEP 8: TH sends Stop command to the DUT self.step(8) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C01.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Stop)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Stop(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) @@ -1109,10 +1096,9 @@ async def TEST_TC_OPSTATE_BASE_2_5(self, endpoint=1): # STEP 10: TH reads from the DUT the OperationalState attribute self.step(10) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0004")): - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kStopped) + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kStopped) # STEP 11: Restart DUT self.step(11) @@ -1135,33 +1121,29 @@ async def TEST_TC_OPSTATE_BASE_2_5(self, endpoint=1): # STEP 13: TH sends Start command to the DUT self.step(13) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C02.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Start)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Start(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) # STEP 14: TH reads from the DUT the OperationalState attribute self.step(14) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0004")): - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kRunning) + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kRunning) # STEP 15: TH sends Pause command to the DUT self.step(15) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C00.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Pause)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Pause(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) # STEP 16: TH reads from the DUT the OperationalState attribute self.step(16) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0004")): - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kPaused) + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kPaused) # STEP 17: TH waits for half of initial-countdown-time self.step(17) @@ -1169,18 +1151,16 @@ async def TEST_TC_OPSTATE_BASE_2_5(self, endpoint=1): # STEP 18: TH sends Resume command to the DUT self.step(18) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C03.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Resume)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Resume(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) # STEP 19: TH reads from the DUT the OperationalState attribute self.step(19) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.A0004")): - await self.read_and_expect_value(endpoint=endpoint, - attribute=attributes.OperationalState, - expected_value=cluster.Enums.OperationalStateEnum.kRunning) + await self.read_and_expect_value(endpoint=endpoint, + attribute=attributes.OperationalState, + expected_value=cluster.Enums.OperationalStateEnum.kRunning) # STEP 20: TH waits for initial-countdown-time self.step(20) @@ -1188,8 +1168,7 @@ async def TEST_TC_OPSTATE_BASE_2_5(self, endpoint=1): # STEP 21: TH sends Stop command to the DUT self.step(21) - if self.pics_guard(self.check_pics(f"{self.test_info.pics_code}.S.C01.Rsp") and - self.check_pics(f"{self.test_info.pics_code}.S.C04.Tx")): + if ((await self.command_guard(endpoint=endpoint, command=commands.Stop)) and (commands.OperationalCommandResponse.command_id in generated_cmd_list)): await self.send_cmd_expect_response(endpoint=endpoint, cmd=commands.Stop(), expected_response=cluster.Enums.ErrorStateEnum.kNoError) diff --git a/src/python_testing/TC_RVCOPSTATE_2_1.py b/src/python_testing/TC_RVCOPSTATE_2_1.py index 428aa9a5ab14fd..4fc63fbe236632 100644 --- a/src/python_testing/TC_RVCOPSTATE_2_1.py +++ b/src/python_testing/TC_RVCOPSTATE_2_1.py @@ -85,6 +85,8 @@ def TC_RVCOPSTATE_2_1(self) -> list[str]: @async_test_body async def test_TC_RVCOPSTATE_2_1(self): + if self.matter_test_config.endpoint is None or self.matter_test_config.endpoint == 0: + asserts.fail("--endpoint must be set and not set to 0 for this test to run correctly.") self.endpoint = self.get_endpoint() asserts.assert_false(self.endpoint is None, "--endpoint must be included on the command line in.") self.is_ci = self.check_pics("PICS_SDK_CI_ONLY") @@ -94,7 +96,8 @@ async def test_TC_RVCOPSTATE_2_1(self): asserts.fail("The --app-pid flag must be set when PICS_SDK_CI_ONLY is set") self.app_pipe = self.app_pipe + str(app_pid) - attributes = Clusters.RvcOperationalState.Attributes + cluster = Clusters.RvcOperationalState + attributes = cluster.Attributes self.print_step(1, "Commissioning, already done") @@ -102,7 +105,7 @@ async def test_TC_RVCOPSTATE_2_1(self): if self.is_ci: self.write_to_app_pipe({"Name": "Reset"}) - if self.check_pics("RVCOPSTATE.S.A0000"): + if await self.attribute_guard(endpoint=self.endpoint, attribute=attributes.PhaseList): self.print_step(2, "Read PhaseList attribute") phase_list = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.PhaseList) @@ -115,7 +118,7 @@ async def test_TC_RVCOPSTATE_2_1(self): asserts.assert_less_equal(phase_list_len, 32, "PhaseList length(%d) must be less than 32!" % phase_list_len) - if self.check_pics("RVCOPSTATE.S.A0001"): + if await self.attribute_guard(endpoint=self.endpoint, attribute=attributes.CurrentPhase): self.print_step(3, "Read CurrentPhase attribute") current_phase = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CurrentPhase) logging.info("CurrentPhase: %s" % (current_phase)) @@ -126,7 +129,7 @@ async def test_TC_RVCOPSTATE_2_1(self): asserts.assert_true(0 <= current_phase < phase_list_len, "CurrentPhase(%s) must be between 0 and %d" % (current_phase, (phase_list_len - 1))) - if self.check_pics("RVCOPSTATE.S.A0002"): + if await self.attribute_guard(endpoint=self.endpoint, attribute=attributes.CountdownTime): self.print_step(4, "Read CountdownTime attribute") countdown_time = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.CountdownTime) @@ -136,7 +139,7 @@ async def test_TC_RVCOPSTATE_2_1(self): asserts.assert_true(countdown_time >= 0 and countdown_time <= 259200, "CountdownTime(%s) must be between 0 and 259200" % countdown_time) - if self.check_pics("RVCOPSTATE.S.A0003"): + if await self.attribute_guard(endpoint=self.endpoint, attribute=attributes.OperationalStateList): self.print_step(5, "Read OperationalStateList attribute") operational_state_list = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.OperationalStateList) @@ -159,7 +162,7 @@ async def test_TC_RVCOPSTATE_2_1(self): asserts.assert_true(error_state_present, "The OperationalStateList does not have an ID entry of Error(0x03)") - if self.check_pics("RVCOPSTATE.S.A0004"): + if await self.attribute_guard(endpoint=self.endpoint, attribute=attributes.OperationalState): self.print_step(6, "Read OperationalState attribute") operational_state = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.OperationalState) @@ -226,7 +229,7 @@ async def test_TC_RVCOPSTATE_2_1(self): self.wait_for_user_input(prompt_msg=f"{test_step}, and press Enter when done.\n") await self.read_and_validate_opstate(step="6n", expected_state=Clusters.RvcOperationalState.Enums.OperationalStateEnum.kDocked) - if self.check_pics("RVCOPSTATE.S.A0005"): + if await self.attribute_guard(endpoint=self.endpoint, attribute=attributes.OperationalError): self.print_step(7, "Read OperationalError attribute") operational_error = await self.read_mod_attribute_expect_success(endpoint=self.endpoint, attribute=attributes.OperationalError) diff --git a/src/python_testing/TC_TestAttrAvail.py b/src/python_testing/TC_TestAttrAvail.py new file mode 100644 index 00000000000000..b2fc40eae600c6 --- /dev/null +++ b/src/python_testing/TC_TestAttrAvail.py @@ -0,0 +1,164 @@ +# +# Copyright (c) 2023 Project CHIP Authors +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments +# for details about the block below. +# +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${ALL_CLUSTERS_APP} +# app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# script-args: > +# --storage-path admin_storage.json +# --manual-code 10054912339 +# --PICS src/app/tests/suites/certification/ci-pics-values +# --trace-to json:${TRACE_TEST_JSON}.json +# --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# --endpoint 1 +# factory-reset: true +# quiet: true +# run2: +# app: ${ALL_CLUSTERS_APP} +# app-args: --discriminator 1234 --passcode 20202021 --KVS kvs1 +# script-args: > +# --storage-path admin_storage.json +# --discriminator 1234 +# --passcode 20202021 +# --endpoint 1 +# --commissioning-method on-network +# factory-reset: true +# quiet: true +# run3: +# app: ${ALL_CLUSTERS_APP} +# app-args: --discriminator 1234 --KVS kvs1 +# script-args: > +# --storage-path admin_storage.json +# --endpoint 1 +# --discriminator 1234 +# --passcode 20202021 +# factory-reset: false +# quiet: true +# === END CI TEST ARGUMENTS === + +# Run 1: Tests PASE connection using manual code +# Run 2: Tests CASE connection using manual discriminator and passcode +# Run 3: Tests without factory reset + +import asyncio + +import chip.clusters as Clusters +from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + + +class TC_TestAttrAvail(MatterBaseTest): + # Using get_code and a modified version of setup_class_helper functions from chip.testing.basic_composition module + def get_code(self, dev_ctrl): + created_codes = [] + for idx, discriminator in enumerate(self.matter_test_config.discriminators): + created_codes.append(dev_ctrl.CreateManualCode(discriminator, self.matter_test_config.setup_passcodes[idx])) + + setup_codes = self.matter_test_config.qr_code_content + self.matter_test_config.manual_code + created_codes + if not setup_codes: + return None + asserts.assert_equal(len(setup_codes), 1, + "Require exactly one of either --qr-code, --manual-code or (--discriminator and --passcode).") + return setup_codes[0] + + async def setup_class_helper(self, allow_pase: bool = True): + dev_ctrl = self.default_controller + self.problems = [] + + node_id = self.dut_node_id + + task_list = [] + if allow_pase and self.get_code(dev_ctrl): + setup_code = self.get_code(dev_ctrl) + pase_future = dev_ctrl.EstablishPASESession(setup_code, self.dut_node_id) + task_list.append(asyncio.create_task(pase_future)) + + case_future = dev_ctrl.GetConnectedDevice(nodeid=node_id, allowPASE=False) + task_list.append(asyncio.create_task(case_future)) + + for task in task_list: + asyncio.ensure_future(task) + + done, pending = await asyncio.wait(task_list, return_when=asyncio.FIRST_COMPLETED) + + for task in pending: + try: + task.cancel() + await task + except asyncio.CancelledError: + pass + + wildcard_read = (await dev_ctrl.Read(node_id, [()])) + + # ======= State kept for use by all tests ======= + # All endpoints in "full object" indexing format + self.endpoints = wildcard_read.attributes + + def steps_TC_TestAttrAvail(self) -> list[TestStep]: + return [ + TestStep(1, "Commissioning, already done", is_commissioning=True), + TestStep(2, "Checking OperationalState attribute is available on endpoint"), + TestStep(3, "Checking Operational Resume command is available on endpoint"), + TestStep(4, "Checking Timezone feature is available on endpoint"), + ] + + def TC_TestAttrAvail(self) -> list[str]: + return ["RVCOPSTATE.S"] + + @async_test_body + async def setup_class(self): + super().setup_class() + await self.setup_class_helper() + + # ======= START OF ACTUAL TESTS ======= + @async_test_body + async def test_TC_TestAttrAvail(self): + self.step(1) + + if self.matter_test_config.endpoint is None or self.matter_test_config.endpoint == 0: + asserts.fail("--endpoint must be set and not set to 0 for this test to run correctly.") + self.endpoint = self.get_endpoint() + asserts.assert_false(self.endpoint is None, "--endpoint must be included on the command line in.") + + cluster = Clusters.RvcOperationalState + attributes = cluster.Attributes + commands = cluster.Commands + self.th1 = self.default_controller + + self.step(2) + attr_should_be_there = await self.attribute_guard(endpoint=self.endpoint, attribute=attributes.OperationalState) + asserts.assert_true(attr_should_be_there, True) + self.print_step("Operational State Attr", attr_should_be_there) + + self.step(3) + cmd_should_be_there = await self.command_guard(endpoint=self.endpoint, command=commands.Resume) + asserts.assert_true(cmd_should_be_there, True) + self.print_step("Operational Resume Command available ", cmd_should_be_there) + + self.step(4) + feat_should_be_there = await self.feature_guard(endpoint=self.endpoint, cluster=Clusters.BooleanStateConfiguration, feature_int=Clusters.BooleanStateConfiguration.Bitmaps.Feature.kAudible) + asserts.assert_true(feat_should_be_there, True) + self.print_step("Boolean State Config Audio Feature available ", feat_should_be_there) + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py index 3b3fb6270b613c..0ad55369e106cb 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py @@ -1124,6 +1124,12 @@ def setup_class(self): self.current_step_index = 0 self.step_start_time = datetime.now(timezone.utc) self.step_skipped = False + self.global_wildcard = asyncio.wait_for(self.default_controller.Read(self.dut_node_id, [(Clusters.Descriptor), Attribute.AttributePath(None, None, GlobalAttributeIds.ATTRIBUTE_LIST_ID), Attribute.AttributePath( + None, None, GlobalAttributeIds.FEATURE_MAP_ID), Attribute.AttributePath(None, None, GlobalAttributeIds.ACCEPTED_COMMAND_LIST_ID)]), timeout=60) + # self.stored_global_wildcard stores value of self.global_wildcard after first async call. + # Because setup_class can be called before commissioning, this variable is lazy-initialized + # where the read is deferred until the first guard function call that requires global attributes. + self.stored_global_wildcard = None def setup_test(self): self.current_step_index = 0 @@ -1455,6 +1461,66 @@ def pics_guard(self, pics_condition: bool): self.mark_current_step_skipped() return pics_condition + async def attribute_guard(self, endpoint: int, attribute: ClusterObjects.ClusterAttributeDescriptor): + """Similar to pics_guard above, except checks a condition and if False marks the test step as skipped and + returns False using attributes against attributes_list, otherwise returns True. + For example can be used to check if a test step should be run: + + self.step("1") + if self.attribute_guard(condition1_needs_to_be_true_to_execute): + # do the test for step 1 + + self.step("2") + if self.attribute_guard(condition2_needs_to_be_false_to_skip_step): + # skip step 2 if condition not met + """ + if self.stored_global_wildcard is None: + self.stored_global_wildcard = await self.global_wildcard + attr_condition = _has_attribute(wildcard=self.stored_global_wildcard, endpoint=endpoint, attribute=attribute) + if not attr_condition: + self.mark_current_step_skipped() + return attr_condition + + async def command_guard(self, endpoint: int, command: ClusterObjects.ClusterCommand): + """Similar to attribute_guard above, except checks a condition and if False marks the test step as skipped and + returns False using command id against AcceptedCmdsList, otherwise returns True. + For example can be used to check if a test step should be run: + + self.step("1") + if self.command_guard(condition1_needs_to_be_true_to_execute): + # do the test for step 1 + + self.step("2") + if self.command_guard(condition2_needs_to_be_false_to_skip_step): + # skip step 2 if condition not met + """ + if self.stored_global_wildcard is None: + self.stored_global_wildcard = await self.global_wildcard + cmd_condition = _has_command(wildcard=self.stored_global_wildcard, endpoint=endpoint, command=command) + if not cmd_condition: + self.mark_current_step_skipped() + return cmd_condition + + async def feature_guard(self, endpoint: int, cluster: ClusterObjects.ClusterObjectDescriptor, feature_int: IntFlag): + """Similar to command_guard and attribute_guard above, except checks a condition and if False marks the test step as skipped and + returns False using feature id against feature_map, otherwise returns True. + For example can be used to check if a test step should be run: + + self.step("1") + if self.feature_guard(condition1_needs_to_be_true_to_execute): + # do the test for step 1 + + self.step("2") + if self.feature_guard(condition2_needs_to_be_false_to_skip_step): + # skip step 2 if condition not met + """ + if self.stored_global_wildcard is None: + self.stored_global_wildcard = await self.global_wildcard + feat_condition = _has_feature(wildcard=self.stored_global_wildcard, endpoint=endpoint, cluster=cluster, feature=feature_int) + if not feat_condition: + self.mark_current_step_skipped() + return feat_condition + def mark_current_step_skipped(self): try: steps = self.get_test_steps(self.current_test_info.name) @@ -2105,6 +2171,41 @@ def has_attribute(attribute: ClusterObjects.ClusterAttributeDescriptor) -> Endpo return partial(_has_attribute, attribute=attribute) +def _has_command(wildcard, endpoint, command: ClusterObjects.ClusterCommand) -> bool: + cluster = get_cluster_from_command(command) + try: + cmd_list = wildcard.attributes[endpoint][cluster][cluster.Attributes.AcceptedCommandList] + if not isinstance(cmd_list, list): + asserts.fail( + f"Failed to read mandatory AcceptedCommandList command value for cluster {cluster} on endpoint {endpoint}: {cmd_list}.") + return command.command_id in cmd_list + except KeyError: + return False + + +def has_command(command: ClusterObjects.ClusterCommand) -> EndpointCheckFunction: + """ EndpointCheckFunction that can be passed as a parameter to the run_if_endpoint_matches decorator. + + Use this function with the run_if_endpoint_matches decorator to run this test on all endpoints with + the specified attribute. For example, given a device with the following conformance + + EP0: cluster A, B, C + EP1: cluster D with command d, E + EP2, cluster D with command d + EP3, cluster D without command d + + And the following test specification: + @run_if_endpoint_matches(has_command(Clusters.D.Commands.d)) + test_mytest(self): + ... + + If you run this test with --endpoint 1 or --endpoint 2, the test will be run. If you run this test + with any other --endpoint the run_if_endpoint_matches decorator will call the on_skip function to + notify the test harness that the test is not applicable to this node and the test will not be run. + """ + return partial(_has_command, command=command) + + def _has_feature(wildcard, endpoint: int, cluster: ClusterObjects.ClusterObjectDescriptor, feature: IntFlag) -> bool: try: feature_map = wildcard.attributes[endpoint][cluster][cluster.Attributes.FeatureMap] diff --git a/src/python_testing/test_metadata.yaml b/src/python_testing/test_metadata.yaml index a6f0ba5bf6174e..dcabdeffdadb1d 100644 --- a/src/python_testing/test_metadata.yaml +++ b/src/python_testing/test_metadata.yaml @@ -97,6 +97,7 @@ slow_tests: - { name: TC_PS_2_3.py, duration: 30 seconds } - { name: TC_RR_1_1.py, duration: 25 seconds } - { name: TC_SWTCH.py, duration: 1 minute } + - { name: TC_TestAttrAvail.py, duration: 30 seconds } - { name: TC_TIMESYNC_2_10.py, duration: 20 seconds } - { name: TC_TIMESYNC_2_11.py, duration: 30 seconds } - { name: TC_TIMESYNC_2_12.py, duration: 20 seconds } From e3277eb02ed8115de5887e8beca0e35007ba71f3 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Mon, 16 Dec 2024 14:30:05 -0800 Subject: [PATCH 05/19] Enforce a maximum entry limit during append operations (#36843) * Enforce a maximum entry limit during append operations * Add test for this change --- .../user-label-server/user-label-server.cpp | 1 + .../TestUserLabelClusterConstraints.yaml | 32 +++++++++++++++++++ src/platform/DeviceInfoProvider.cpp | 11 +++++-- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/app/clusters/user-label-server/user-label-server.cpp b/src/app/clusters/user-label-server/user-label-server.cpp index e1ea85cf01a78a..0030f628097696 100644 --- a/src/app/clusters/user-label-server/user-label-server.cpp +++ b/src/app/clusters/user-label-server/user-label-server.cpp @@ -143,6 +143,7 @@ CHIP_ERROR UserLabelAttrAccess::WriteLabelList(const ConcreteDataAttributePath & return provider->SetUserLabelList(endpoint, labelList); } + if (aPath.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem) { Structs::LabelStruct::DecodableType entry; diff --git a/src/app/tests/suites/TestUserLabelClusterConstraints.yaml b/src/app/tests/suites/TestUserLabelClusterConstraints.yaml index 4074def78d82d1..935fe88c2b662c 100644 --- a/src/app/tests/suites/TestUserLabelClusterConstraints.yaml +++ b/src/app/tests/suites/TestUserLabelClusterConstraints.yaml @@ -55,3 +55,35 @@ tests: ] response: error: CONSTRAINT_ERROR + + - label: "Attempt to write a large label list" + command: "writeAttribute" + attribute: "LabelList" + arguments: + value: [ + # Example repeated user labels to blow up the maximum allowed + { Label: "roomName", Value: "master bedroom 1" }, + { Label: "orientation", Value: "east" }, + { Label: "floor", Value: "2" }, + { Label: "roomType", Value: "bedroom" }, + { Label: "someKey5", Value: "someVal5" }, + { Label: "someKey6", Value: "someVal6" }, + { Label: "someKey7", Value: "someVal7" }, + { Label: "someKey8", Value: "someVal8" }, + { Label: "someKey9", Value: "someVal9" }, + { Label: "someKey10", Value: "someVal10" }, + { Label: "someKey11", Value: "someVal11" }, + { Label: "someKey12", Value: "someVal12" }, + { Label: "someKey13", Value: "someVal13" }, + { Label: "someKey14", Value: "someVal14" }, + { Label: "someKey15", Value: "someVal15" }, + { Label: "someKey16", Value: "someVal16" }, + { Label: "someKey17", Value: "someVal17" }, + { Label: "someKey18", Value: "someVal18" }, + { Label: "someKey19", Value: "someVal19" }, + { Label: "someKey20", Value: "someVal20" }, + ] + response: + # When the cluster runs out of capacity to store these entries, + # we expect a FAILURE get returned. + error: FAILURE diff --git a/src/platform/DeviceInfoProvider.cpp b/src/platform/DeviceInfoProvider.cpp index 92ad84d86d49b8..28191cd4f82352 100644 --- a/src/platform/DeviceInfoProvider.cpp +++ b/src/platform/DeviceInfoProvider.cpp @@ -82,11 +82,16 @@ CHIP_ERROR DeviceInfoProvider::AppendUserLabel(EndpointId endpoint, const UserLa { size_t length; - // Increase the size of UserLabelList by 1 + // Fetch current list length ReturnErrorOnFailure(GetUserLabelLength(endpoint, length)); - ReturnErrorOnFailure(SetUserLabelLength(endpoint, length + 1)); - // Append the user label at the end of UserLabelList + if (length >= kMaxUserLabelListLength) + { + return CHIP_ERROR_NO_MEMORY; + } + + // Add the new entry to the list + ReturnErrorOnFailure(SetUserLabelLength(endpoint, length + 1)); ReturnErrorOnFailure(SetUserLabelAt(endpoint, length, label)); return CHIP_NO_ERROR; From 4e445861ce93eec07f0c93a02f309eb34ae7489f Mon Sep 17 00:00:00 2001 From: James Swan <122404367+swan-amazon@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:50:41 -0800 Subject: [PATCH 06/19] Feature/enhanced setup flow feature (#34065) * Add initial feature logic for Terms and Conditions (TC) acknowledgements This commit introduces the initial logic for handling Terms and Conditions (TC) acknowledgements in the General Commissioning cluster. The logic includes support for setting and checking TC acknowledgements and versions during the commissioning process. Changes include: - Handling TC acknowledgements and TC acknowledgement version in the pairing command. - Logic to read TC attributes and check TC acceptance in the General Commissioning server. - Introduction of classes to manage TC acceptance logic. - Initialization and use of TC providers in the server setup. - Addition of a new commissioning stage for TC acknowledgements in the commissioning flow. The feature logic is currently disabled and will be enabled in an example in a subsequent commit. * ./scripts/helpers/restyle-diff.sh @{u} * Ignore file reference check on TermsAndConditionsManager.cpp The TermsAndConditionsManager.cpp file is only referenced within sample apps that utilize the Terms and Conditions feature. * Make `terms and conditions required` build configurable: - Moved the configuration from core into app buildconfig - renamed the flag to expand `TC` into `TERMS AND CONDITIONS` - updated includes in general-commissioning to include the right header - added the configuration as a build option into targets.py/host.py - updated unit test * Move terms and conditions to its own target and include cpp file - Create a separate source set for terms and conditions - include the manager cpp in that file - make the build conditional (this required flag moving) - fixed typo in targets.py to make things compile Compile-tested only (the -terms-and-conditions variant of all clusters compiled) * Fix mangled license blurb * Remove edited date for CHIPConfig.h * Fix unit tests dependencies * Add back some includes --------- Co-authored-by: Andrei Litvin --- scripts/build/build/targets.py | 1 + scripts/build/builders/host.py | 7 + .../build/testdata/all_targets_linux_x64.txt | 2 +- src/app/BUILD.gn | 1 + src/app/FailSafeContext.cpp | 9 +- src/app/FailSafeContext.h | 18 +- src/app/chip_data_model.cmake | 3 +- .../general-commissioning-server.cpp | 374 +++++++++++++-- src/app/common_flags.gni | 4 + src/app/server/BUILD.gn | 22 +- .../DefaultTermsAndConditionsProvider.cpp | 251 ++++++++++ .../DefaultTermsAndConditionsProvider.h | 152 ++++++ src/app/server/TermsAndConditionsManager.cpp | 80 ++++ src/app/server/TermsAndConditionsManager.h | 45 ++ src/app/server/TermsAndConditionsProvider.h | 224 +++++++++ src/app/tests/BUILD.gn | 5 +- .../TestDefaultTermsAndConditionsProvider.cpp | 435 ++++++++++++++++++ src/include/platform/CHIPDeviceEvent.h | 1 + src/lib/support/DefaultStorageKeyAllocator.h | 6 +- 19 files changed, 1587 insertions(+), 53 deletions(-) create mode 100644 src/app/server/DefaultTermsAndConditionsProvider.cpp create mode 100644 src/app/server/DefaultTermsAndConditionsProvider.h create mode 100644 src/app/server/TermsAndConditionsManager.cpp create mode 100644 src/app/server/TermsAndConditionsManager.h create mode 100644 src/app/server/TermsAndConditionsProvider.h create mode 100644 src/app/tests/TestDefaultTermsAndConditionsProvider.cpp diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index 0bb25ef9a06b75..d7935e95ffeaaf 100755 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -197,6 +197,7 @@ def BuildHostTarget(): target.AppendModifier('disable-dnssd-tests', enable_dnssd_tests=False).OnlyIfRe('-tests') target.AppendModifier('chip-casting-simplified', chip_casting_simplified=True).OnlyIfRe('-tv-casting-app') target.AppendModifier('googletest', use_googletest=True).OnlyIfRe('-tests') + target.AppendModifier('terms-and-conditions', terms_and_conditions_required=True) return target diff --git a/scripts/build/builders/host.py b/scripts/build/builders/host.py index 7fe5823f37b7a8..fd84901a5adaba 100644 --- a/scripts/build/builders/host.py +++ b/scripts/build/builders/host.py @@ -336,6 +336,7 @@ def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE, chip_casting_simplified: Optional[bool] = None, disable_shell=False, use_googletest=False, + terms_and_conditions_required: Optional[bool] = None, ): super(HostBuilder, self).__init__( root=os.path.join(root, 'examples', app.ExamplePath()), @@ -459,6 +460,12 @@ def __init__(self, root, runner, app: HostApp, board=HostBoard.NATIVE, if chip_casting_simplified is not None: self.extra_gn_options.append(f'chip_casting_simplified={str(chip_casting_simplified).lower()}') + if terms_and_conditions_required is not None: + if terms_and_conditions_required: + self.extra_gn_options.append('chip_terms_and_conditions_required=true') + else: + self.extra_gn_options.append('chip_terms_and_conditions_required=false') + if self.board == HostBoard.ARM64: if not use_clang: raise Exception("Cross compile only supported using clang") diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt index f3330ffc3fe090..05fec168c491c6 100644 --- a/scripts/build/testdata/all_targets_linux_x64.txt +++ b/scripts/build/testdata/all_targets_linux_x64.txt @@ -9,7 +9,7 @@ efr32-{brd2704b,brd4316a,brd4317a,brd4318a,brd4319a,brd4186a,brd4187a,brd2601b,b esp32-{m5stack,c3devkit,devkitc,qemu}-{all-clusters,all-clusters-minimal,energy-management,ota-provider,ota-requestor,shell,light,lock,bridge,temperature-measurement,ota-requestor,tests}[-rpc][-ipv6only][-tracing] genio-lighting-app linux-fake-tests[-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-pw-fuzztest][-coverage][-dmalloc][-clang] -linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,thermostat,java-matter-controller,kotlin-matter-controller,minmdns,light,light-data-model-no-unique-id,lock,shell,ota-provider,ota-requestor,simulated-app1,simulated-app2,python-bindings,tv-app,tv-casting-app,bridge,fabric-admin,fabric-bridge,fabric-sync,tests,chip-cert,address-resolve-tool,contact-sensor,dishwasher,microwave-oven,refrigerator,rvc,air-purifier,lit-icd,air-quality-sensor,network-manager,energy-management,water-leak-detector}[-nodeps][-nlfaultinject][-platform-mdns][-minmdns-verbose][-libnl][-same-event-loop][-no-interactive][-ipv6only][-no-ble][-no-wifi][-no-thread][-no-shell][-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-pw-fuzztest][-coverage][-dmalloc][-clang][-test][-rpc][-with-ui][-evse-test-event][-enable-dnssd-tests][-disable-dnssd-tests][-chip-casting-simplified][-googletest] +linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,thermostat,java-matter-controller,kotlin-matter-controller,minmdns,light,light-data-model-no-unique-id,lock,shell,ota-provider,ota-requestor,simulated-app1,simulated-app2,python-bindings,tv-app,tv-casting-app,bridge,fabric-admin,fabric-bridge,fabric-sync,tests,chip-cert,address-resolve-tool,contact-sensor,dishwasher,microwave-oven,refrigerator,rvc,air-purifier,lit-icd,air-quality-sensor,network-manager,energy-management,water-leak-detector}[-nodeps][-nlfaultinject][-platform-mdns][-minmdns-verbose][-libnl][-same-event-loop][-no-interactive][-ipv6only][-no-ble][-no-wifi][-no-thread][-no-shell][-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-pw-fuzztest][-coverage][-dmalloc][-clang][-test][-rpc][-with-ui][-evse-test-event][-enable-dnssd-tests][-disable-dnssd-tests][-chip-casting-simplified][-googletest][-terms-and-conditions] linux-x64-efr32-test-runner[-clang] imx-{chip-tool,lighting-app,thermostat,all-clusters-app,all-clusters-minimal-app,ota-provider-app}[-release] infineon-psoc6-{lock,light,all-clusters,all-clusters-minimal}[-ota][-updateimage][-trustm] diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index 14fcfc96e45543..fd286ff7c9c2d4 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -76,6 +76,7 @@ buildconfig_header("app_buildconfig") { "CHIP_DEVICE_CONFIG_DYNAMIC_SERVER=${chip_build_controller_dynamic_server}", "CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP=${chip_enable_busy_handling_for_operational_session_setup}", "CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING=${chip_data_model_extra_logging}", + "CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED=${chip_terms_and_conditions_required}", ] visibility = [ ":app_config" ] diff --git a/src/app/FailSafeContext.cpp b/src/app/FailSafeContext.cpp index 95a5b267f2aa5e..372ee323930d67 100644 --- a/src/app/FailSafeContext.cpp +++ b/src/app/FailSafeContext.cpp @@ -86,9 +86,12 @@ void FailSafeContext::ScheduleFailSafeCleanup(FabricIndex fabricIndex, bool addN SetFailSafeArmed(false); ChipDeviceEvent event{ .Type = DeviceEventType::kFailSafeTimerExpired, - .FailSafeTimerExpired = { .fabricIndex = fabricIndex, - .addNocCommandHasBeenInvoked = addNocCommandInvoked, - .updateNocCommandHasBeenInvoked = updateNocCommandInvoked } }; + .FailSafeTimerExpired = { + .fabricIndex = fabricIndex, + .addNocCommandHasBeenInvoked = addNocCommandInvoked, + .updateNocCommandHasBeenInvoked = updateNocCommandInvoked, + .updateTermsAndConditionsHasBeenInvoked = mUpdateTermsAndConditionsHasBeenInvoked, + } }; CHIP_ERROR status = PlatformMgr().PostEvent(&event); if (status != CHIP_NO_ERROR) diff --git a/src/app/FailSafeContext.h b/src/app/FailSafeContext.h index 48e11e0845395b..af177bd2a8d5fc 100644 --- a/src/app/FailSafeContext.h +++ b/src/app/FailSafeContext.h @@ -56,6 +56,7 @@ class FailSafeContext void SetUpdateNocCommandInvoked() { mUpdateNocCommandHasBeenInvoked = true; } void SetAddTrustedRootCertInvoked() { mAddTrustedRootCertHasBeenInvoked = true; } void SetCsrRequestForUpdateNoc(bool isForUpdateNoc) { mIsCsrRequestForUpdateNoc = isForUpdateNoc; } + void SetUpdateTermsAndConditionsHasBeenInvoked() { mUpdateTermsAndConditionsHasBeenInvoked = true; } /** * @brief @@ -91,6 +92,7 @@ class FailSafeContext bool UpdateNocCommandHasBeenInvoked() const { return mUpdateNocCommandHasBeenInvoked; } bool AddTrustedRootCertHasBeenInvoked() const { return mAddTrustedRootCertHasBeenInvoked; } bool IsCsrRequestForUpdateNoc() const { return mIsCsrRequestForUpdateNoc; } + bool UpdateTermsAndConditionsHasBeenInvoked() { return mUpdateTermsAndConditionsHasBeenInvoked; } FabricIndex GetFabricIndex() const { @@ -109,8 +111,9 @@ class FailSafeContext bool mUpdateNocCommandHasBeenInvoked = false; bool mAddTrustedRootCertHasBeenInvoked = false; // The fact of whether a CSR occurred at all is stored elsewhere. - bool mIsCsrRequestForUpdateNoc = false; - FabricIndex mFabricIndex = kUndefinedFabricIndex; + bool mIsCsrRequestForUpdateNoc = false; + FabricIndex mFabricIndex = kUndefinedFabricIndex; + bool mUpdateTermsAndConditionsHasBeenInvoked = false; /** * @brief @@ -140,11 +143,12 @@ class FailSafeContext { SetFailSafeArmed(false); - mAddNocCommandHasBeenInvoked = false; - mUpdateNocCommandHasBeenInvoked = false; - mAddTrustedRootCertHasBeenInvoked = false; - mFailSafeBusy = false; - mIsCsrRequestForUpdateNoc = false; + mAddNocCommandHasBeenInvoked = false; + mUpdateNocCommandHasBeenInvoked = false; + mAddTrustedRootCertHasBeenInvoked = false; + mFailSafeBusy = false; + mIsCsrRequestForUpdateNoc = false; + mUpdateTermsAndConditionsHasBeenInvoked = false; } void FailSafeTimerExpired(); diff --git a/src/app/chip_data_model.cmake b/src/app/chip_data_model.cmake index 7c5ab0f82608b4..dcafc0055de3e9 100644 --- a/src/app/chip_data_model.cmake +++ b/src/app/chip_data_model.cmake @@ -81,8 +81,9 @@ function(chip_configure_data_model APP_TARGET) ${CHIP_APP_BASE_DIR}/SafeAttributePersistenceProvider.cpp ${CHIP_APP_BASE_DIR}/StorageDelegateWrapper.cpp ${CHIP_APP_BASE_DIR}/server/AclStorage.cpp - ${CHIP_APP_BASE_DIR}/server/DefaultAclStorage.cpp ${CHIP_APP_BASE_DIR}/server/CommissioningWindowManager.cpp + ${CHIP_APP_BASE_DIR}/server/DefaultAclStorage.cpp + ${CHIP_APP_BASE_DIR}/server/DefaultTermsAndConditionsProvider.cpp ${CHIP_APP_BASE_DIR}/server/Dnssd.cpp ${CHIP_APP_BASE_DIR}/server/EchoHandler.cpp ${CHIP_APP_BASE_DIR}/server/OnboardingCodesUtil.cpp diff --git a/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp b/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp index 4bf97face53740..f6fad1d8908243 100644 --- a/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp +++ b/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp @@ -1,6 +1,6 @@ /** * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2021-2024 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,20 +21,29 @@ ******************************************************************************* ******************************************************************************/ +#include "general-commissioning-server.h" + #include #include +#include #include #include #include +#include #include #include -#include -#include +#include #include #include #include #include #include +#include + +#if CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED +#include //nogncheck +#include //nogncheck +#endif using namespace chip; using namespace chip::app; @@ -42,6 +51,7 @@ using namespace chip::app::Clusters; using namespace chip::app::Clusters::GeneralCommissioning; using namespace chip::app::Clusters::GeneralCommissioning::Attributes; using namespace chip::DeviceLayer; +using chip::app::Clusters::GeneralCommissioning::CommissioningErrorEnum; using Transport::SecureSession; using Transport::Session; @@ -95,6 +105,58 @@ CHIP_ERROR GeneralCommissioningAttrAccess::Read(const ConcreteReadAttributePath case SupportsConcurrentConnection::Id: { return ReadSupportsConcurrentConnection(aEncoder); } +#if CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED + case TCAcceptedVersion::Id: { + TermsAndConditionsProvider * tcProvider = TermsAndConditionsManager::GetInstance(); + Optional outTermsAndConditions; + + VerifyOrReturnError(nullptr != tcProvider, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + ReturnErrorOnFailure(tcProvider->GetAcceptance(outTermsAndConditions)); + + return aEncoder.Encode(outTermsAndConditions.ValueOr(TermsAndConditions(0, 0)).GetVersion()); + } + case TCMinRequiredVersion::Id: { + TermsAndConditionsProvider * tcProvider = TermsAndConditionsManager::GetInstance(); + Optional outTermsAndConditions; + + VerifyOrReturnError(nullptr != tcProvider, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + ReturnErrorOnFailure(tcProvider->GetRequirements(outTermsAndConditions)); + + return aEncoder.Encode(outTermsAndConditions.ValueOr(TermsAndConditions(0, 0)).GetVersion()); + } + case TCAcknowledgements::Id: { + TermsAndConditionsProvider * tcProvider = TermsAndConditionsManager::GetInstance(); + Optional outTermsAndConditions; + + VerifyOrReturnError(nullptr != tcProvider, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + ReturnErrorOnFailure(tcProvider->GetAcceptance(outTermsAndConditions)); + + return aEncoder.Encode(outTermsAndConditions.ValueOr(TermsAndConditions(0, 0)).GetValue()); + } + case TCAcknowledgementsRequired::Id: { + TermsAndConditionsProvider * tcProvider = TermsAndConditionsManager::GetInstance(); + bool acknowledgementsRequired; + + VerifyOrReturnError(nullptr != tcProvider, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + ReturnErrorOnFailure(tcProvider->GetAcknowledgementsRequired(acknowledgementsRequired)); + + return aEncoder.Encode(acknowledgementsRequired); + } + case TCUpdateDeadline::Id: { + TermsAndConditionsProvider * tcProvider = TermsAndConditionsManager::GetInstance(); + Optional outUpdateAcceptanceDeadline; + + VerifyOrReturnError(nullptr != tcProvider, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + ReturnErrorOnFailure(tcProvider->GetUpdateAcceptanceDeadline(outUpdateAcceptanceDeadline)); + + if (!outUpdateAcceptanceDeadline.HasValue()) + { + return aEncoder.EncodeNull(); + } + + return aEncoder.Encode(outUpdateAcceptanceDeadline.Value()); + } +#endif // CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED default: { break; } @@ -144,6 +206,73 @@ CHIP_ERROR GeneralCommissioningAttrAccess::ReadSupportsConcurrentConnection(Attr return aEncoder.Encode(supportsConcurrentConnection); } +#if CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED +typedef struct sTermsAndConditionsState +{ + Optional acceptance; + bool acknowledgementsRequired; + Optional requirements; + Optional updateAcceptanceDeadline; +} TermsAndConditionsState; + +CHIP_ERROR GetTermsAndConditionsAttributeState(TermsAndConditionsProvider * tcProvider, + TermsAndConditionsState & outTermsAndConditionsState) +{ + TermsAndConditionsState termsAndConditionsState; + + ReturnErrorOnFailure(tcProvider->GetAcceptance(termsAndConditionsState.acceptance)); + ReturnErrorOnFailure(tcProvider->GetAcknowledgementsRequired(termsAndConditionsState.acknowledgementsRequired)); + ReturnErrorOnFailure(tcProvider->GetRequirements(termsAndConditionsState.requirements)); + ReturnErrorOnFailure(tcProvider->GetUpdateAcceptanceDeadline(termsAndConditionsState.updateAcceptanceDeadline)); + + outTermsAndConditionsState = termsAndConditionsState; + return CHIP_NO_ERROR; +} + +void NotifyTermsAndConditionsAttributeChangeIfRequired(const TermsAndConditionsState & initialState, + const TermsAndConditionsState & updatedState) +{ + // Notify on TCAcknowledgementsRequired change + if (initialState.acknowledgementsRequired != updatedState.acknowledgementsRequired) + { + MatterReportingAttributeChangeCallback(kRootEndpointId, GeneralCommissioning::Id, TCAcknowledgementsRequired::Id); + } + + // Notify on TCAcceptedVersion change + if ((initialState.acceptance.HasValue() != updatedState.acceptance.HasValue()) || + (initialState.acceptance.HasValue() && + (initialState.acceptance.Value().GetVersion() != updatedState.acceptance.Value().GetVersion()))) + { + MatterReportingAttributeChangeCallback(kRootEndpointId, GeneralCommissioning::Id, TCAcceptedVersion::Id); + } + + // Notify on TCAcknowledgements change + if ((initialState.acceptance.HasValue() != updatedState.acceptance.HasValue()) || + (initialState.acceptance.HasValue() && + (initialState.acceptance.Value().GetValue() != updatedState.acceptance.Value().GetValue()))) + { + MatterReportingAttributeChangeCallback(kRootEndpointId, GeneralCommissioning::Id, TCAcknowledgements::Id); + } + + // Notify on TCRequirements change + if ((initialState.requirements.HasValue() != updatedState.requirements.HasValue()) || + (initialState.requirements.HasValue() && + (initialState.requirements.Value().GetVersion() != updatedState.requirements.Value().GetVersion() || + initialState.requirements.Value().GetValue() != updatedState.requirements.Value().GetValue()))) + { + MatterReportingAttributeChangeCallback(kRootEndpointId, GeneralCommissioning::Id, TCMinRequiredVersion::Id); + } + + // Notify on TCUpdateDeadline change + if ((initialState.updateAcceptanceDeadline.HasValue() != updatedState.updateAcceptanceDeadline.HasValue()) || + (initialState.updateAcceptanceDeadline.HasValue() && + (initialState.updateAcceptanceDeadline.Value() != updatedState.updateAcceptanceDeadline.Value()))) + { + MatterReportingAttributeChangeCallback(kRootEndpointId, GeneralCommissioning::Id, TCUpdateDeadline::Id); + } +} +#endif // CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED + } // anonymous namespace bool emberAfGeneralCommissioningClusterArmFailSafeCallback(app::CommandHandler * commandObj, @@ -218,60 +347,115 @@ bool emberAfGeneralCommissioningClusterCommissioningCompleteCallback( auto & failSafe = Server::GetInstance().GetFailSafeContext(); auto & fabricTable = Server::GetInstance().GetFabricTable(); + CHIP_ERROR err = CHIP_NO_ERROR; + ChipLogProgress(FailSafe, "GeneralCommissioning: Received CommissioningComplete"); Commands::CommissioningCompleteResponse::Type response; + + // Fail-safe must be armed if (!failSafe.IsFailSafeArmed()) { response.errorCode = CommissioningErrorEnum::kNoFailSafe; + commandObj->AddResponse(commandPath, response); + return true; } - else + +#if CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED + TermsAndConditionsProvider * tcProvider = TermsAndConditionsManager::GetInstance(); + + // Ensure required terms and conditions have been accepted, then attempt to commit + if (nullptr != tcProvider) { - SessionHandle handle = commandObj->GetExchangeContext()->GetSessionHandle(); - // If not a CASE session, or the fabric does not match the fail-safe, - // error out. - if (handle->GetSessionType() != Session::SessionType::kSecure || - handle->AsSecureSession()->GetSecureSessionType() != SecureSession::Type::kCASE || - !failSafe.MatchesFabricIndex(commandObj->GetAccessingFabricIndex())) + Optional requiredTermsAndConditionsMaybe; + Optional acceptedTermsAndConditionsMaybe; + + CheckSuccess(tcProvider->GetRequirements(requiredTermsAndConditionsMaybe), Failure); + CheckSuccess(tcProvider->GetAcceptance(acceptedTermsAndConditionsMaybe), Failure); + + if (requiredTermsAndConditionsMaybe.HasValue() && !acceptedTermsAndConditionsMaybe.HasValue()) { - response.errorCode = CommissioningErrorEnum::kInvalidAuthentication; - ChipLogError(FailSafe, "GeneralCommissioning: Got commissioning complete in invalid security context"); + response.errorCode = CommissioningErrorEnum::kTCAcknowledgementsNotReceived; + commandObj->AddResponse(commandPath, response); + return true; } - else + + if (requiredTermsAndConditionsMaybe.HasValue() && acceptedTermsAndConditionsMaybe.HasValue()) { - if (failSafe.NocCommandHasBeenInvoked()) + TermsAndConditions requiredTermsAndConditions = requiredTermsAndConditionsMaybe.Value(); + TermsAndConditions acceptedTermsAndConditions = acceptedTermsAndConditionsMaybe.Value(); + + if (!requiredTermsAndConditions.ValidateVersion(acceptedTermsAndConditions)) { - CHIP_ERROR err = fabricTable.CommitPendingFabricData(); - if (err != CHIP_NO_ERROR) - { - // No need to revert on error: CommitPendingFabricData always reverts if not fully successful. - ChipLogError(FailSafe, "GeneralCommissioning: Failed to commit pending fabric data: %" CHIP_ERROR_FORMAT, - err.Format()); - } - else - { - ChipLogProgress(FailSafe, "GeneralCommissioning: Successfully commited pending fabric data"); - } - CheckSuccess(err, Failure); + response.errorCode = CommissioningErrorEnum::kTCMinVersionNotMet; + commandObj->AddResponse(commandPath, response); + return true; } - /* - * Pass fabric of commissioner to DeviceControlSvr. - * This allows device to send messages back to commissioner. - * Once bindings are implemented, this may no longer be needed. - */ - failSafe.DisarmFailSafe(); - CheckSuccess( - devCtrl->PostCommissioningCompleteEvent(handle->AsSecureSession()->GetPeerNodeId(), handle->GetFabricIndex()), - Failure); + if (!requiredTermsAndConditions.ValidateValue(acceptedTermsAndConditions)) + { + response.errorCode = CommissioningErrorEnum::kRequiredTCNotAccepted; + commandObj->AddResponse(commandPath, response); + return true; + } + } - Breadcrumb::Set(commandPath.mEndpointId, 0); - response.errorCode = CommissioningErrorEnum::kOk; + if (failSafe.UpdateTermsAndConditionsHasBeenInvoked()) + { + // Commit terms and conditions acceptance on commissioning complete + err = tcProvider->CommitAcceptance(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(FailSafe, "GeneralCommissioning: Failed to commit terms and conditions: %" CHIP_ERROR_FORMAT, + err.Format()); + } + else + { + ChipLogProgress(FailSafe, "GeneralCommissioning: Successfully committed terms and conditions"); + } + CheckSuccess(err, Failure); } } +#endif // CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED - commandObj->AddResponse(commandPath, response); + SessionHandle handle = commandObj->GetExchangeContext()->GetSessionHandle(); + + // Ensure it's a valid CASE session + if ((handle->GetSessionType() != Session::SessionType::kSecure) || + (handle->AsSecureSession()->GetSecureSessionType() != SecureSession::Type::kCASE) || + (!failSafe.MatchesFabricIndex(commandObj->GetAccessingFabricIndex()))) + { + response.errorCode = CommissioningErrorEnum::kInvalidAuthentication; + ChipLogError(FailSafe, "GeneralCommissioning: Got commissioning complete in invalid security context"); + commandObj->AddResponse(commandPath, response); + return true; + } + + // Handle NOC commands + if (failSafe.NocCommandHasBeenInvoked()) + { + err = fabricTable.CommitPendingFabricData(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(FailSafe, "GeneralCommissioning: Failed to commit pending fabric data: %" CHIP_ERROR_FORMAT, err.Format()); + // CommitPendingFabricData reverts on error, no need to revert explicitly + } + else + { + ChipLogProgress(FailSafe, "GeneralCommissioning: Successfully committed pending fabric data"); + } + CheckSuccess(err, Failure); + } + + // Disarm the fail-safe and notify the DeviceControlServer + failSafe.DisarmFailSafe(); + err = devCtrl->PostCommissioningCompleteEvent(handle->AsSecureSession()->GetPeerNodeId(), handle->GetFabricIndex()); + CheckSuccess(err, Failure); + Breadcrumb::Set(commandPath.mEndpointId, 0); + response.errorCode = CommissioningErrorEnum::kOk; + + commandObj->AddResponse(commandPath, response); return true; } @@ -328,6 +512,77 @@ bool emberAfGeneralCommissioningClusterSetRegulatoryConfigCallback(app::CommandH return true; } +bool emberAfGeneralCommissioningClusterSetTCAcknowledgementsCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const GeneralCommissioning::Commands::SetTCAcknowledgements::DecodableType & commandData) +{ + MATTER_TRACE_SCOPE("SetTCAcknowledgements", "GeneralCommissioning"); + +#if CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED + auto & failSafeContext = Server::GetInstance().GetFailSafeContext(); + TermsAndConditionsProvider * tcProvider = TermsAndConditionsManager::GetInstance(); + + if (nullptr == tcProvider) + { + commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::Failure); + return true; + } + + Optional requiredTermsAndConditionsMaybe; + Optional previousAcceptedTermsAndConditionsMaybe; + CheckSuccess(tcProvider->GetRequirements(requiredTermsAndConditionsMaybe), Failure); + CheckSuccess(tcProvider->GetAcceptance(previousAcceptedTermsAndConditionsMaybe), Failure); + TermsAndConditions acceptedTermsAndConditions = TermsAndConditions(commandData.TCUserResponse, commandData.TCVersion); + Optional acceptedTermsAndConditionsPresent = Optional(acceptedTermsAndConditions); + + Commands::SetTCAcknowledgementsResponse::Type response; + + if (requiredTermsAndConditionsMaybe.HasValue()) + { + TermsAndConditions requiredTermsAndConditions = requiredTermsAndConditionsMaybe.Value(); + + if (!requiredTermsAndConditions.ValidateVersion(acceptedTermsAndConditions)) + { + response.errorCode = CommissioningErrorEnum::kTCMinVersionNotMet; + commandObj->AddResponse(commandPath, response); + return true; + } + + if (!requiredTermsAndConditions.ValidateValue(acceptedTermsAndConditions)) + { + response.errorCode = CommissioningErrorEnum::kRequiredTCNotAccepted; + commandObj->AddResponse(commandPath, response); + return true; + } + } + + if (previousAcceptedTermsAndConditionsMaybe != acceptedTermsAndConditionsPresent) + { + TermsAndConditionsState initialState, updatedState; + CheckSuccess(GetTermsAndConditionsAttributeState(tcProvider, initialState), Failure); + CheckSuccess(tcProvider->SetAcceptance(acceptedTermsAndConditionsPresent), Failure); + CheckSuccess(GetTermsAndConditionsAttributeState(tcProvider, updatedState), Failure); + NotifyTermsAndConditionsAttributeChangeIfRequired(initialState, updatedState); + + // Commit or defer based on fail-safe state + if (!failSafeContext.IsFailSafeArmed()) + { + CheckSuccess(tcProvider->CommitAcceptance(), Failure); + } + else + { + failSafeContext.SetUpdateTermsAndConditionsHasBeenInvoked(); + } + } + + response.errorCode = CommissioningErrorEnum::kOk; + commandObj->AddResponse(commandPath, response); + return true; + +#endif // CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED + return true; +} + namespace { void OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg) { @@ -335,16 +590,59 @@ void OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t { // Spec says to reset Breadcrumb attribute to 0. Breadcrumb::Set(0, 0); + + if (event->FailSafeTimerExpired.updateTermsAndConditionsHasBeenInvoked) + { +#if CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED + // Clear terms and conditions acceptance on failsafe timer expiration + TermsAndConditionsProvider * tcProvider = TermsAndConditionsManager::GetInstance(); + TermsAndConditionsState initialState, updatedState; + VerifyOrReturn(nullptr != tcProvider); + VerifyOrReturn(CHIP_NO_ERROR == GetTermsAndConditionsAttributeState(tcProvider, initialState)); + VerifyOrReturn(CHIP_NO_ERROR == tcProvider->RevertAcceptance()); + VerifyOrReturn(CHIP_NO_ERROR == GetTermsAndConditionsAttributeState(tcProvider, updatedState)); + NotifyTermsAndConditionsAttributeChangeIfRequired(initialState, updatedState); +#endif // CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED + } } } } // anonymous namespace +class GeneralCommissioningFabricTableDelegate : public chip::FabricTable::Delegate +{ +public: + // Gets called when a fabric is deleted + void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) override + { + // If the FabricIndex matches the last remaining entry in the Fabrics list, then the device SHALL delete all Matter + // related data on the node which was created since it was commissioned. + if (Server::GetInstance().GetFabricTable().FabricCount() == 0) + { + ChipLogProgress(Zcl, "general-commissioning-server: Last Fabric index 0x%x was removed", + static_cast(fabricIndex)); + +#if CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED + TermsAndConditionsProvider * tcProvider = TermsAndConditionsManager::GetInstance(); + TermsAndConditionsState initialState, updatedState; + VerifyOrReturn(nullptr != tcProvider); + VerifyOrReturn(CHIP_NO_ERROR == GetTermsAndConditionsAttributeState(tcProvider, initialState)); + VerifyOrReturn(CHIP_NO_ERROR == tcProvider->ResetAcceptance()); + VerifyOrReturn(CHIP_NO_ERROR == GetTermsAndConditionsAttributeState(tcProvider, updatedState)); + NotifyTermsAndConditionsAttributeChangeIfRequired(initialState, updatedState); +#endif // CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED + } + } +}; + void MatterGeneralCommissioningPluginServerInitCallback() { Breadcrumb::Set(0, 0); AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); DeviceLayer::PlatformMgrImpl().AddEventHandler(OnPlatformEventHandler); + + static GeneralCommissioningFabricTableDelegate generalCommissioningFabricTableDelegate; + Server::GetInstance().GetFabricTable().AddFabricDelegate(&generalCommissioningFabricTableDelegate); } namespace chip { diff --git a/src/app/common_flags.gni b/src/app/common_flags.gni index 30678dfe330f2f..7fd111c371b548 100644 --- a/src/app/common_flags.gni +++ b/src/app/common_flags.gni @@ -25,6 +25,10 @@ declare_args() { # communicated to OperationalSessionSetup API consumers. chip_enable_busy_handling_for_operational_session_setup = true + # Controls whether the device commissioning process requires the user to + # acknowledge terms and conditions during commissioning. + chip_terms_and_conditions_required = false + # This controls if more logging is supposed to be enabled into the data models. # This is an optimization for small-flash size devices as extra logging requires # additional flash for messages & code for formatting. diff --git a/src/app/server/BUILD.gn b/src/app/server/BUILD.gn index fb25ae0f38bf6b..040c7b2227ff2a 100644 --- a/src/app/server/BUILD.gn +++ b/src/app/server/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Project CHIP Authors +# Copyright (c) 2020-2024 Project CHIP Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,6 +25,22 @@ config("server_config") { } } +source_set("terms_and_conditions") { + sources = [ + "DefaultTermsAndConditionsProvider.cpp", + "DefaultTermsAndConditionsProvider.h", + "TermsAndConditionsManager.cpp", + "TermsAndConditionsManager.h", + "TermsAndConditionsProvider.h", + ] + + public_deps = [ + "${chip_root}/src/lib/core", + "${chip_root}/src/lib/support", + "${chip_root}/src/protocols", + ] +} + static_library("server") { output_name = "libCHIPAppServer" @@ -69,6 +85,10 @@ static_library("server") { "${chip_root}/src/transport", ] + if (chip_terms_and_conditions_required) { + public_deps += [ ":terms_and_conditions" ] + } + # TODO: Server.cpp uses TestGroupData.h. Unsure why test code would be in such a central place # This dependency is split since it should probably be removed (or naming should # be updated if this is not really "testing" even though headers are Test*.h) diff --git a/src/app/server/DefaultTermsAndConditionsProvider.cpp b/src/app/server/DefaultTermsAndConditionsProvider.cpp new file mode 100644 index 00000000000000..36431aea456128 --- /dev/null +++ b/src/app/server/DefaultTermsAndConditionsProvider.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DefaultTermsAndConditionsProvider.h" +#include "TermsAndConditionsProvider.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { +constexpr chip::TLV::Tag kSerializationVersionTag = chip::TLV::ContextTag(1); +constexpr chip::TLV::Tag kAcceptedAcknowledgementsTag = chip::TLV::ContextTag(2); +constexpr chip::TLV::Tag kAcceptedAcknowledgementsVersionTag = chip::TLV::ContextTag(3); +constexpr uint8_t kSerializationSchemaMinimumVersion = 1; +constexpr uint8_t kSerializationSchemaCurrentVersion = 1; + +constexpr size_t kEstimatedTlvBufferSize = chip::TLV::EstimateStructOverhead(sizeof(uint8_t), // SerializationVersion + sizeof(uint16_t), // AcceptedAcknowledgements + sizeof(uint16_t) // AcceptedAcknowledgementsVersion + ) * + 4; // Extra space for rollback compatibility +} // namespace + +CHIP_ERROR chip::app::DefaultTermsAndConditionsStorageDelegate::Init(PersistentStorageDelegate * inPersistentStorageDelegate) +{ + VerifyOrReturnValue(nullptr != inPersistentStorageDelegate, CHIP_ERROR_INVALID_ARGUMENT); + + mStorageDelegate = inPersistentStorageDelegate; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsStorageDelegate::Delete() +{ + VerifyOrReturnValue(nullptr != mStorageDelegate, CHIP_ERROR_UNINITIALIZED); + + const chip::StorageKeyName kStorageKey = chip::DefaultStorageKeyAllocator::TermsAndConditionsAcceptance(); + ReturnErrorOnFailure(mStorageDelegate->SyncDeleteKeyValue(kStorageKey.KeyName())); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsStorageDelegate::Get(Optional & outTermsAndConditions) +{ + VerifyOrReturnValue(nullptr != mStorageDelegate, CHIP_ERROR_UNINITIALIZED); + + uint8_t serializationVersion = 0; + uint16_t acknowledgements = 0; + uint16_t acknowledgementsVersion = 0; + + chip::TLV::TLVReader tlvReader; + chip::TLV::TLVType tlvContainer; + + uint8_t buffer[kEstimatedTlvBufferSize] = { 0 }; + uint16_t bufferSize = sizeof(buffer); + + const chip::StorageKeyName kStorageKey = chip::DefaultStorageKeyAllocator::TermsAndConditionsAcceptance(); + + CHIP_ERROR err = mStorageDelegate->SyncGetKeyValue(kStorageKey.KeyName(), &buffer, bufferSize); + VerifyOrReturnValue(CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err || CHIP_NO_ERROR == err, err); + + if (CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err) + { + outTermsAndConditions.ClearValue(); + return CHIP_NO_ERROR; + } + + tlvReader.Init(buffer, bufferSize); + ReturnErrorOnFailure(tlvReader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag())); + ReturnErrorOnFailure(tlvReader.EnterContainer(tlvContainer)); + ReturnErrorOnFailure(tlvReader.Next(kSerializationVersionTag)); + ReturnErrorOnFailure(tlvReader.Get(serializationVersion)); + + if (serializationVersion < kSerializationSchemaMinimumVersion) + { + ChipLogError(AppServer, "The terms and conditions datastore schema (%hhu) is newer than oldest compatible schema (%hhu)", + serializationVersion, kSerializationSchemaMinimumVersion); + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + if (serializationVersion != kSerializationSchemaCurrentVersion) + { + ChipLogDetail(AppServer, "The terms and conditions datastore schema (%hhu) differs from current schema (%hhu)", + serializationVersion, kSerializationSchemaCurrentVersion); + } + + ReturnErrorOnFailure(tlvReader.Next(kAcceptedAcknowledgementsTag)); + ReturnErrorOnFailure(tlvReader.Get(acknowledgements)); + ReturnErrorOnFailure(tlvReader.Next(kAcceptedAcknowledgementsVersionTag)); + ReturnErrorOnFailure(tlvReader.Get(acknowledgementsVersion)); + ReturnErrorOnFailure(tlvReader.ExitContainer(tlvContainer)); + + outTermsAndConditions = Optional(TermsAndConditions(acknowledgements, acknowledgementsVersion)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsStorageDelegate::Set(const TermsAndConditions & inTermsAndConditions) +{ + uint8_t buffer[kEstimatedTlvBufferSize] = { 0 }; + chip::TLV::TLVWriter tlvWriter; + chip::TLV::TLVType tlvContainer; + + VerifyOrReturnValue(nullptr != mStorageDelegate, CHIP_ERROR_UNINITIALIZED); + + tlvWriter.Init(buffer); + ReturnErrorOnFailure(tlvWriter.StartContainer(chip::TLV::AnonymousTag(), chip::TLV::kTLVType_Structure, tlvContainer)); + ReturnErrorOnFailure(tlvWriter.Put(kSerializationVersionTag, kSerializationSchemaCurrentVersion)); + ReturnErrorOnFailure(tlvWriter.Put(kAcceptedAcknowledgementsTag, inTermsAndConditions.GetValue())); + ReturnErrorOnFailure(tlvWriter.Put(kAcceptedAcknowledgementsVersionTag, inTermsAndConditions.GetVersion())); + ReturnErrorOnFailure(tlvWriter.EndContainer(tlvContainer)); + ReturnErrorOnFailure(tlvWriter.Finalize()); + + const chip::StorageKeyName kStorageKey = chip::DefaultStorageKeyAllocator::TermsAndConditionsAcceptance(); + ReturnErrorOnFailure( + mStorageDelegate->SyncSetKeyValue(kStorageKey.KeyName(), buffer, static_cast(tlvWriter.GetLengthWritten()))); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::Init( + TermsAndConditionsStorageDelegate * inStorageDelegate, + const chip::Optional & inRequiredTermsAndConditions) +{ + VerifyOrReturnValue(nullptr != inStorageDelegate, CHIP_ERROR_INVALID_ARGUMENT); + + mTermsAndConditionsStorageDelegate = inStorageDelegate; + mRequiredAcknowledgements = inRequiredTermsAndConditions; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::CommitAcceptance() +{ + VerifyOrReturnValue(nullptr != mTermsAndConditionsStorageDelegate, CHIP_ERROR_UNINITIALIZED); + + // No terms and conditions to commit + VerifyOrReturnValue(mTemporalAcceptance.HasValue(), CHIP_NO_ERROR); + + ReturnErrorOnFailure(mTermsAndConditionsStorageDelegate->Set(mTemporalAcceptance.Value())); + ChipLogProgress(AppServer, "Terms and conditions have been committed"); + mTemporalAcceptance.ClearValue(); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::GetAcceptance(Optional & outTermsAndConditions) const +{ + VerifyOrReturnValue(nullptr != mTermsAndConditionsStorageDelegate, CHIP_ERROR_UNINITIALIZED); + + // Return the in-memory acceptance state + if (mTemporalAcceptance.HasValue()) + { + outTermsAndConditions = mTemporalAcceptance; + return CHIP_NO_ERROR; + } + + // Otherwise, try to get the persisted acceptance state + CHIP_ERROR err = mTermsAndConditionsStorageDelegate->Get(outTermsAndConditions); + VerifyOrReturnValue(CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err || CHIP_NO_ERROR == err, err); + + if (CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err) + { + ChipLogError(AppServer, "No terms and conditions have been accepted"); + outTermsAndConditions.ClearValue(); + return CHIP_NO_ERROR; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::GetAcknowledgementsRequired(bool & outAcknowledgementsRequired) const +{ + Optional requiredTermsAndConditionsMaybe; + ReturnErrorOnFailure(GetRequirements(requiredTermsAndConditionsMaybe)); + + if (!requiredTermsAndConditionsMaybe.HasValue()) + { + outAcknowledgementsRequired = false; + return CHIP_NO_ERROR; + } + + Optional acceptedTermsAndConditionsMaybe; + ReturnErrorOnFailure(GetAcceptance(acceptedTermsAndConditionsMaybe)); + + if (!acceptedTermsAndConditionsMaybe.HasValue()) + { + outAcknowledgementsRequired = true; + return CHIP_NO_ERROR; + } + + TermsAndConditions requiredTermsAndConditions = requiredTermsAndConditionsMaybe.Value(); + TermsAndConditions acceptedTermsAndConditions = acceptedTermsAndConditionsMaybe.Value(); + outAcknowledgementsRequired = requiredTermsAndConditions.Validate(acceptedTermsAndConditions); + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::GetRequirements(Optional & outTermsAndConditions) const +{ + outTermsAndConditions = mRequiredAcknowledgements; + return CHIP_NO_ERROR; +} + +CHIP_ERROR +chip::app::DefaultTermsAndConditionsProvider::GetUpdateAcceptanceDeadline(Optional & outUpdateAcceptanceDeadline) const +{ + // No-op stub implementation. This feature is not implemented in this default implementation. + outUpdateAcceptanceDeadline = Optional(); + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::ResetAcceptance() +{ + VerifyOrReturnValue(nullptr != mTermsAndConditionsStorageDelegate, CHIP_ERROR_UNINITIALIZED); + + (void) mTermsAndConditionsStorageDelegate->Delete(); + ReturnErrorOnFailure(RevertAcceptance()); + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::RevertAcceptance() +{ + mTemporalAcceptance.ClearValue(); + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::DefaultTermsAndConditionsProvider::SetAcceptance(const Optional & inTermsAndConditions) +{ + mTemporalAcceptance = inTermsAndConditions; + return CHIP_NO_ERROR; +} diff --git a/src/app/server/DefaultTermsAndConditionsProvider.h b/src/app/server/DefaultTermsAndConditionsProvider.h new file mode 100644 index 00000000000000..8bc3d0761b3e21 --- /dev/null +++ b/src/app/server/DefaultTermsAndConditionsProvider.h @@ -0,0 +1,152 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "TermsAndConditionsProvider.h" + +#include + +#include +#include +#include + +namespace chip { +namespace app { + +/** + * @brief Abstract interface for storing and retrieving terms and conditions acceptance status. + * + * This class defines the methods required to interact with the underlying storage system + * for saving, retrieving, and deleting the user's acceptance of terms and conditions. + */ +class TermsAndConditionsStorageDelegate +{ +public: + virtual ~TermsAndConditionsStorageDelegate() = default; + + /** + * @brief Deletes the persisted terms and conditions acceptance status from storage. + * + * This method deletes the stored record of the user's acceptance of the terms and conditions, + * effectively resetting their acceptance status in the persistent storage. + * + * @retval CHIP_NO_ERROR if the record was successfully deleted. + * @retval CHIP_ERROR_UNINITIALIZED if the storage delegate is not properly initialized. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR Delete() = 0; + + /** + * @brief Retrieves the persisted terms and conditions acceptance status from storage. + * + * This method attempts to retrieve the previously accepted terms and conditions from + * persistent storage. If no such record exists, it returns an empty `Optional`. + * + * @param[out] outTermsAndConditions The retrieved terms and conditions, if any exist. + * + * @retval CHIP_NO_ERROR if the terms were successfully retrieved. + * @retval CHIP_ERROR_UNINITIALIZED if the storage delegate is not properly initialized. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR Get(Optional & outTermsAndConditions) = 0; + + /** + * @brief Persists the user's acceptance of the terms and conditions. + * + * This method stores the provided terms and conditions acceptance status in persistent + * storage, allowing the user's acceptance to be retrieved later. + * + * @param[in] inTermsAndConditions The terms and conditions to be saved. + * + * @retval CHIP_NO_ERROR if the terms were successfully stored. + * @retval CHIP_ERROR_UNINITIALIZED if the storage delegate is not properly initialized. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR Set(const TermsAndConditions & inTermsAndConditions) = 0; +}; + +/** + * @brief Default implementation of the TermsAndConditionsStorageDelegate using a persistent storage backend. + * + * This class provides an implementation of the TermsAndConditionsStorageDelegate interface, storing + * and retrieving the user's terms and conditions acceptance from persistent storage. It requires a + * PersistentStorageDelegate to interface with the storage system. + */ +class DefaultTermsAndConditionsStorageDelegate : public TermsAndConditionsStorageDelegate +{ +public: + /** + * @brief Initializes the storage delegate with a persistent storage backend. + * + * This method initializes the storage delegate with the provided persistent storage delegate. + * The storage delegate must be initialized before performing any operations. + * + * @param[in] inPersistentStorageDelegate The storage backend used for saving and retrieving data. + * + * @retval CHIP_NO_ERROR if the storage delegate was successfully initialized. + * @retval CHIP_ERROR_INVALID_ARGUMENT if the provided storage delegate is null. + */ + CHIP_ERROR Init(PersistentStorageDelegate * inPersistentStorageDelegate); + + CHIP_ERROR Delete() override; + + CHIP_ERROR Get(Optional & inTermsAndConditions) override; + + CHIP_ERROR Set(const TermsAndConditions & inTermsAndConditions) override; + +private: + PersistentStorageDelegate * mStorageDelegate = nullptr; +}; + +class DefaultTermsAndConditionsProvider : public TermsAndConditionsProvider +{ +public: + /** + * @brief Initializes the TermsAndConditionsProvider. + * + * @param[in] inStorageDelegate Storage delegate dependency. + * @param[in] inRequiredTermsAndConditions The required terms and conditions that must be met. + */ + CHIP_ERROR Init(TermsAndConditionsStorageDelegate * inStorageDelegate, + const Optional & inRequiredTermsAndConditions); + + CHIP_ERROR CommitAcceptance() override; + + CHIP_ERROR GetAcceptance(Optional & outTermsAndConditions) const override; + + CHIP_ERROR GetAcknowledgementsRequired(bool & outAcknowledgementsRequired) const override; + + CHIP_ERROR GetRequirements(Optional & outTermsAndConditions) const override; + + CHIP_ERROR GetUpdateAcceptanceDeadline(Optional & outUpdateAcceptanceDeadline) const override; + + CHIP_ERROR ResetAcceptance() override; + + CHIP_ERROR RevertAcceptance() override; + + CHIP_ERROR SetAcceptance(const Optional & inTermsAndConditions) override; + +private: + TermsAndConditionsStorageDelegate * mTermsAndConditionsStorageDelegate; + Optional mTemporalAcceptance; + Optional mRequiredAcknowledgements; +}; + +} // namespace app +} // namespace chip diff --git a/src/app/server/TermsAndConditionsManager.cpp b/src/app/server/TermsAndConditionsManager.cpp new file mode 100644 index 00000000000000..4946bf37d2611f --- /dev/null +++ b/src/app/server/TermsAndConditionsManager.cpp @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TermsAndConditionsManager.h" + +#include "DefaultTermsAndConditionsProvider.h" + +static chip::app::TermsAndConditionsManager sTermsAndConditionsManager; +static chip::app::DefaultTermsAndConditionsProvider sTermsAndConditionsProviderInstance; +static chip::app::DefaultTermsAndConditionsStorageDelegate sTermsAndConditionsStorageDelegateInstance; + +chip::app::TermsAndConditionsManager * chip::app::TermsAndConditionsManager::GetInstance() +{ + return &sTermsAndConditionsManager; +} + +CHIP_ERROR chip::app::TermsAndConditionsManager::Init(chip::PersistentStorageDelegate * inPersistentStorageDelegate, + const Optional & inRequiredTermsAndConditions) +{ + ReturnErrorOnFailure(sTermsAndConditionsStorageDelegateInstance.Init(inPersistentStorageDelegate)); + ReturnErrorOnFailure( + sTermsAndConditionsProviderInstance.Init(&sTermsAndConditionsStorageDelegateInstance, inRequiredTermsAndConditions)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR chip::app::TermsAndConditionsManager::CommitAcceptance() +{ + return sTermsAndConditionsProviderInstance.CommitAcceptance(); +} + +CHIP_ERROR chip::app::TermsAndConditionsManager::GetAcceptance(Optional & outTermsAndConditions) const +{ + return sTermsAndConditionsProviderInstance.GetAcceptance(outTermsAndConditions); +} + +CHIP_ERROR chip::app::TermsAndConditionsManager::GetAcknowledgementsRequired(bool & outAcknowledgementsRequired) const +{ + return sTermsAndConditionsProviderInstance.GetAcknowledgementsRequired(outAcknowledgementsRequired); +} + +CHIP_ERROR chip::app::TermsAndConditionsManager::GetRequirements(Optional & outTermsAndConditions) const +{ + return sTermsAndConditionsProviderInstance.GetRequirements(outTermsAndConditions); +} + +CHIP_ERROR chip::app::TermsAndConditionsManager::GetUpdateAcceptanceDeadline(Optional & outUpdateAcceptanceDeadline) const +{ + return sTermsAndConditionsProviderInstance.GetUpdateAcceptanceDeadline(outUpdateAcceptanceDeadline); +} + +CHIP_ERROR chip::app::TermsAndConditionsManager::ResetAcceptance() +{ + return sTermsAndConditionsProviderInstance.ResetAcceptance(); +} + +CHIP_ERROR chip::app::TermsAndConditionsManager::RevertAcceptance() +{ + return sTermsAndConditionsProviderInstance.RevertAcceptance(); +} + +CHIP_ERROR chip::app::TermsAndConditionsManager::SetAcceptance(const Optional & inTermsAndConditions) +{ + return sTermsAndConditionsProviderInstance.SetAcceptance(inTermsAndConditions); +} diff --git a/src/app/server/TermsAndConditionsManager.h b/src/app/server/TermsAndConditionsManager.h new file mode 100644 index 00000000000000..02101bbec46425 --- /dev/null +++ b/src/app/server/TermsAndConditionsManager.h @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "TermsAndConditionsProvider.h" + +namespace chip { +namespace app { + +class TermsAndConditionsManager : public TermsAndConditionsProvider +{ +public: + static TermsAndConditionsManager * GetInstance(); + CHIP_ERROR Init(PersistentStorageDelegate * inPersistentStorageDelegate, + const Optional & inRequiredTermsAndConditions); + CHIP_ERROR CommitAcceptance(); + CHIP_ERROR GetAcceptance(Optional & outTermsAndConditions) const; + CHIP_ERROR GetAcknowledgementsRequired(bool & outAcknowledgementsRequired) const; + CHIP_ERROR GetRequirements(Optional & outTermsAndConditions) const; + CHIP_ERROR GetUpdateAcceptanceDeadline(Optional & outUpdateAcceptanceDeadline) const; + CHIP_ERROR ResetAcceptance(); + CHIP_ERROR RevertAcceptance(); + CHIP_ERROR SetAcceptance(const Optional & inTermsAndConditions); +}; + +} // namespace app +} // namespace chip diff --git a/src/app/server/TermsAndConditionsProvider.h b/src/app/server/TermsAndConditionsProvider.h new file mode 100644 index 00000000000000..cb0b6f0b8f088a --- /dev/null +++ b/src/app/server/TermsAndConditionsProvider.h @@ -0,0 +1,224 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include + +namespace chip { +namespace app { + +/** + * @brief Represents a pair of terms and conditions value and version. + * + * This class encapsulates terms and conditions with methods to validate a user's accepted value and version against required + * criteria. + */ +class TermsAndConditions +{ +public: + TermsAndConditions(uint16_t inValue, uint16_t inVersion) : value(inValue), version(inVersion) {} + + bool operator==(const TermsAndConditions & other) const { return value == other.value && version == other.version; } + bool operator!=(const TermsAndConditions & other) const { return !(*this == other); } + + /** + * @brief Retrieves the terms and conditions value (accepted bits). + * + * @return The value of the terms and conditions. + */ + uint16_t GetValue() const { return value; } + + /** + * @brief Retrieves the terms and conditions version. + * + * @return The version of the terms and conditions. + */ + uint16_t GetVersion() const { return version; } + + /** + * @brief Validates the terms and conditions value. + * + * Checks whether all required bits are set in the accepted terms and conditions. + * + * @param acceptedTermsAndConditions The user's accepted terms and conditions. + * @return True if all required bits are set, false otherwise. + */ + bool ValidateValue(const TermsAndConditions & acceptedTermsAndConditions) const + { + // Check if all required bits are set in the user-accepted value. + return ((value & acceptedTermsAndConditions.GetValue()) == value); + } + + /** + * @brief Validates the terms and conditions version. + * + * Checks whether the accepted version is greater than or equal to the required version. + * + * @param acceptedTermsAndConditions The user's accepted terms and conditions. + * @return True if the accepted version is valid, false otherwise. + */ + bool ValidateVersion(const TermsAndConditions & acceptedTermsAndConditions) const + { + // Check if the version is below the minimum required version. + return (acceptedTermsAndConditions.GetVersion() >= version); + } + + /** + * @brief Validates the terms and conditions. + * + * Combines validation of both value and version to ensure compliance with requirements. + * + * @param acceptedTermsAndConditions The user's accepted terms and conditions. + * @return True if both value and version validations pass, false otherwise. + */ + bool Validate(const TermsAndConditions & acceptedTermsAndConditions) const + { + return ValidateVersion(acceptedTermsAndConditions) && ValidateValue(acceptedTermsAndConditions); + } + +private: + const uint16_t value; + const uint16_t version; +}; + +/** + * @brief Data access layer for handling the required terms and conditions and managing user acceptance status. + * + * This class provides methods to manage the acceptance of terms and conditions, including storing, retrieving, + * and verifying the acceptance status. It also supports temporary in-memory storage and persistent storage for + * accepted terms and conditions. + */ +class TermsAndConditionsProvider +{ +public: + virtual ~TermsAndConditionsProvider() = default; + + /** + * @brief Persists the acceptance of the terms and conditions. + * + * This method commits the in-memory acceptance status to persistent storage. It stores the acceptance + * status in a permanent location and clears the temporary in-memory acceptance state after committing. + * + * @retval CHIP_NO_ERROR if the terms were successfully persisted. + * @retval CHIP_ERROR_UNINITIALIZED if the module has not been initialized. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR CommitAcceptance() = 0; + + /** + * @brief Retrieves the current acceptance status of the terms and conditions. + * + * This method checks the temporary in-memory acceptance state first. If no in-memory state is found, + * it attempts to retrieve the acceptance status from persistent storage. If no terms have been accepted, + * it returns an empty `Optional`. + * + * @param[out] outTermsAndConditions The current accepted terms and conditions, if any. + * + * @retval CHIP_NO_ERROR if the terms were successfully retrieved or no terms were found. + * @retval CHIP_ERROR_UNINITIALIZED if the module has not been initialized. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR GetAcceptance(Optional & outTermsAndConditions) const = 0; + + /** + * @brief Determines if acknowledgments are required. + * + * @param[out] outAcknowledgementsRequired True if acknowledgments are required, false otherwise. + * + * @retval CHIP_NO_ERROR if successful. + * @retval CHIP_ERROR_UNINITIALIZED if the module has not been initialized. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR GetAcknowledgementsRequired(bool & outAcknowledgementsRequired) const = 0; + + /** + * @brief Retrieves the requirements for the terms and conditions. + * + * This method retrieves the required terms and conditions that must be accepted by the user. These + * requirements are set by the provider and used to validate the acceptance. + * + * @param[out] outTermsAndConditions The required terms and conditions. + * + * @retval CHIP_NO_ERROR if the required terms were successfully retrieved. + * @retval CHIP_ERROR_UNINITIALIZED if the module has not been initialized. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR GetRequirements(Optional & outTermsAndConditions) const = 0; + + /** + * @brief Retrieves the deadline for accepting updated terms and conditions. + * + * This method retrieves the deadline by which the user must accept updated terms and conditions. + * If no deadline is set, it returns an empty `Optional`. + * + * @param[out] outUpdateAcceptanceDeadline The deadline (in seconds) by which updated terms must be accepted. + * Returns empty Optional if no deadline is set. + * + * @retval CHIP_NO_ERROR if the deadline was successfully retrieved or no deadline was found. + * @retval CHIP_ERROR_UNINITIALIZED if the module has not been initialized. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR GetUpdateAcceptanceDeadline(Optional & outUpdateAcceptanceDeadline) const = 0; + + /** + * @brief Resets the persisted acceptance status. + * + * This method deletes the persisted acceptance of the terms and conditions from storage, effectively + * resetting the stored acceptance status. Any in-memory temporary acceptance will also be cleared + * through this method. + * + * @retval CHIP_NO_ERROR if the terms were successfully reset. + * @retval CHIP_ERROR_UNINITIALIZED if the module has not been initialized. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR ResetAcceptance() = 0; + + /** + * @brief Clears the in-memory temporary acceptance status. + * + * This method clears any temporary acceptance of the terms and conditions that is held in-memory. It does + * not affect the persisted state stored in storage. + * + * @retval CHIP_NO_ERROR if the in-memory acceptance state was successfully cleared. + * @retval CHIP_ERROR_UNINITIALIZED if the module has not been initialized. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR RevertAcceptance() = 0; + + /** + * @brief Sets the temporary in-memory acceptance status of the terms and conditions. + * + * This method stores the provided terms and conditions acceptance status in-memory. It does not persist + * the acceptance status to storage. To persist the acceptance, call `CommitAcceptance()` after this method. + * + * @param[in] inTermsAndConditions The terms and conditions to be accepted temporarily. + * + * @retval CHIP_NO_ERROR if the terms were successfully stored in-memory. + * @retval CHIP_ERROR_INVALID_ARGUMENT if the provided terms and conditions are invalid. + * @retval CHIP_ERROR_UNINITIALIZED if the module has not been initialized. + * @retval CHIP_ERROR_* for other errors. + */ + virtual CHIP_ERROR SetAcceptance(const Optional & inTermsAndConditions) = 0; +}; + +} // namespace app +} // namespace chip diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index 912c1e32a0ef5a..1923573765101a 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Project CHIP Authors +# Copyright (c) 2020-2024 Project CHIP Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -211,6 +211,7 @@ chip_test_suite("tests") { "TestDataModelSerialization.cpp", "TestDefaultOTARequestorStorage.cpp", "TestDefaultSafeAttributePersistenceProvider.cpp", + "TestDefaultTermsAndConditionsProvider.cpp", "TestDefaultThreadNetworkDirectoryStorage.cpp", "TestEcosystemInformationCluster.cpp", "TestEventLoggingNoUTCTime.cpp", @@ -252,6 +253,8 @@ chip_test_suite("tests") { "${chip_root}/src/app/data-model-provider/tests:encode-decode", "${chip_root}/src/app/icd/client:handler", "${chip_root}/src/app/icd/client:manager", + "${chip_root}/src/app/server", + "${chip_root}/src/app/server:terms_and_conditions", "${chip_root}/src/app/tests:helpers", "${chip_root}/src/app/util/mock:mock_codegen_data_model", "${chip_root}/src/app/util/mock:mock_ember", diff --git a/src/app/tests/TestDefaultTermsAndConditionsProvider.cpp b/src/app/tests/TestDefaultTermsAndConditionsProvider.cpp new file mode 100644 index 00000000000000..dc2a66278aa5d2 --- /dev/null +++ b/src/app/tests/TestDefaultTermsAndConditionsProvider.cpp @@ -0,0 +1,435 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "app/server/DefaultTermsAndConditionsProvider.h" +#include "app/server/TermsAndConditionsProvider.h" +#include "pw_unit_test/framework.h" + +#include +#include +#include +#include + +class TestTermsAndConditionsStorageDelegate : public chip::app::TermsAndConditionsStorageDelegate +{ +public: + TestTermsAndConditionsStorageDelegate(chip::Optional & initialTermsAndConditions) : + mTermsAndConditions(initialTermsAndConditions) + {} + + CHIP_ERROR Delete() + { + mTermsAndConditions.ClearValue(); + return CHIP_NO_ERROR; + } + + CHIP_ERROR Get(chip::Optional & outTermsAndConditions) + { + outTermsAndConditions = mTermsAndConditions; + return CHIP_NO_ERROR; + } + + CHIP_ERROR Set(const chip::app::TermsAndConditions & inTermsAndConditions) + { + mTermsAndConditions = chip::Optional(inTermsAndConditions); + return CHIP_NO_ERROR; + } + +private: + chip::Optional & mTermsAndConditions; +}; + +TEST(DefaultTermsAndConditionsProvider, TestInitSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate testPersistentStorageDelegate; + chip::app::DefaultTermsAndConditionsStorageDelegate defaultTermsAndConditionsStorageDelegate; + err = defaultTermsAndConditionsStorageDelegate.Init(&testPersistentStorageDelegate); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::app::DefaultTermsAndConditionsProvider defaultTermsAndConditionsProvider; + chip::Optional requiredTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + err = defaultTermsAndConditionsProvider.Init(&defaultTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); +} + +TEST(DefaultTermsAndConditionsProvider, TestNoRequirementsGetRequirementsSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate testPersistentStorageDelegate; + chip::app::DefaultTermsAndConditionsStorageDelegate defaultTermsAndConditionsStorageDelegate; + err = defaultTermsAndConditionsStorageDelegate.Init(&testPersistentStorageDelegate); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::app::DefaultTermsAndConditionsProvider defaultTermsAndConditionsProvider; + chip::Optional requiredTermsAndConditions = chip::Optional(); + err = defaultTermsAndConditionsProvider.Init(&defaultTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional outTermsAndConditions; + err = defaultTermsAndConditionsProvider.GetAcceptance(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_FALSE(outTermsAndConditions.HasValue()); +} + +TEST(DefaultTermsAndConditionsProvider, TestNeverAcceptanceGetAcceptanceSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate testPersistentStorageDelegate; + chip::app::DefaultTermsAndConditionsStorageDelegate defaultTermsAndConditionsStorageDelegate; + err = defaultTermsAndConditionsStorageDelegate.Init(&testPersistentStorageDelegate); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::app::DefaultTermsAndConditionsProvider defaultTermsAndConditionsProvider; + chip::Optional requiredTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(0b1111'1111'1111'1111, 1)); + err = defaultTermsAndConditionsProvider.Init(&defaultTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional outTermsAndConditions; + err = defaultTermsAndConditionsProvider.GetAcceptance(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_FALSE(outTermsAndConditions.HasValue()); +} + +TEST(DefaultTermsAndConditionsProvider, TestTermsAcceptedPersistsSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate testPersistentStorageDelegate; + chip::app::DefaultTermsAndConditionsStorageDelegate defaultTermsAndConditionsStorageDelegate; + err = defaultTermsAndConditionsStorageDelegate.Init(&testPersistentStorageDelegate); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::app::DefaultTermsAndConditionsProvider defaultTermsAndConditionsProvider; + chip::Optional requiredTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + err = defaultTermsAndConditionsProvider.Init(&defaultTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional newTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + + err = defaultTermsAndConditionsProvider.SetAcceptance(newTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional outTermsAndConditions; + err = defaultTermsAndConditionsProvider.GetAcceptance(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_EQ(1, outTermsAndConditions.Value().GetValue()); + EXPECT_EQ(1, outTermsAndConditions.Value().GetVersion()); + + err = defaultTermsAndConditionsProvider.CommitAcceptance(); + err = defaultTermsAndConditionsProvider.GetAcceptance(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_EQ(1, outTermsAndConditions.Value().GetValue()); + EXPECT_EQ(1, outTermsAndConditions.Value().GetVersion()); + + chip::app::DefaultTermsAndConditionsProvider anotherTncProvider; + err = anotherTncProvider.Init(&defaultTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + err = anotherTncProvider.GetAcceptance(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_EQ(1, outTermsAndConditions.Value().GetValue()); + EXPECT_EQ(1, outTermsAndConditions.Value().GetVersion()); +} + +TEST(DefaultTermsAndConditionsProvider, TestTermsRequiredGetRequirementsSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate testPersistentStorageDelegate; + chip::app::DefaultTermsAndConditionsStorageDelegate defaultTermsAndConditionsStorageDelegate; + err = defaultTermsAndConditionsStorageDelegate.Init(&testPersistentStorageDelegate); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::app::DefaultTermsAndConditionsProvider defaultTermsAndConditionsProvider; + chip::Optional requiredTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + err = defaultTermsAndConditionsProvider.Init(&defaultTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional outTermsAndConditions; + err = defaultTermsAndConditionsProvider.GetRequirements(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_EQ(1, outTermsAndConditions.Value().GetValue()); + EXPECT_EQ(1, outTermsAndConditions.Value().GetVersion()); +} + +TEST(DefaultTermsAndConditionsProvider, TestSetAcceptanceGetAcceptanceSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate testPersistentStorageDelegate; + chip::app::DefaultTermsAndConditionsStorageDelegate defaultTermsAndConditionsStorageDelegate; + err = defaultTermsAndConditionsStorageDelegate.Init(&testPersistentStorageDelegate); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::app::DefaultTermsAndConditionsProvider defaultTermsAndConditionsProvider; + chip::Optional requiredTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + err = defaultTermsAndConditionsProvider.Init(&defaultTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional acceptedTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + err = defaultTermsAndConditionsProvider.SetAcceptance(acceptedTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional outTermsAndConditions; + err = defaultTermsAndConditionsProvider.GetRequirements(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_EQ(1, outTermsAndConditions.Value().GetValue()); + EXPECT_EQ(1, outTermsAndConditions.Value().GetVersion()); +} + +TEST(DefaultTermsAndConditionsProvider, TestRevertAcceptanceGetAcceptanceSuccess) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate testPersistentStorageDelegate; + chip::app::DefaultTermsAndConditionsStorageDelegate defaultTermsAndConditionsStorageDelegate; + err = defaultTermsAndConditionsStorageDelegate.Init(&testPersistentStorageDelegate); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::app::DefaultTermsAndConditionsProvider defaultTermsAndConditionsProvider; + chip::Optional requiredTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + err = defaultTermsAndConditionsProvider.Init(&defaultTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional acceptedTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + err = defaultTermsAndConditionsProvider.SetAcceptance(acceptedTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional outTermsAndConditions; + err = defaultTermsAndConditionsProvider.GetRequirements(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_EQ(1, outTermsAndConditions.Value().GetValue()); + EXPECT_EQ(1, outTermsAndConditions.Value().GetVersion()); + + err = defaultTermsAndConditionsProvider.RevertAcceptance(); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional outAcceptance2; + err = defaultTermsAndConditionsProvider.GetAcceptance(outAcceptance2); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_FALSE(outAcceptance2.HasValue()); +} + +TEST(DefaultTermsAndConditionsProvider, TestAcceptanceRequiredTermsMissingFailure) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate testPersistentStorageDelegate; + chip::app::DefaultTermsAndConditionsStorageDelegate defaultTermsAndConditionsStorageDelegate; + err = defaultTermsAndConditionsStorageDelegate.Init(&testPersistentStorageDelegate); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::app::DefaultTermsAndConditionsProvider defaultTermsAndConditionsProvider; + chip::Optional requiredTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + err = defaultTermsAndConditionsProvider.Init(&defaultTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional acceptedTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + err = defaultTermsAndConditionsProvider.SetAcceptance(acceptedTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional outAcknowledgementTermsAndConditions; + err = defaultTermsAndConditionsProvider.GetAcceptance(outAcknowledgementTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_EQ(1, outAcknowledgementTermsAndConditions.Value().GetValue()); + EXPECT_EQ(1, outAcknowledgementTermsAndConditions.Value().GetVersion()); + + err = defaultTermsAndConditionsProvider.RevertAcceptance(); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional outRequiredTermsAndConditions; + err = defaultTermsAndConditionsProvider.GetRequirements(outRequiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_EQ(1, outRequiredTermsAndConditions.Value().GetValue()); + EXPECT_EQ(1, outRequiredTermsAndConditions.Value().GetVersion()); +} + +TEST(DefaultTermsAndConditionsProvider, TestAcceptanceCommitCheckSetRevertCheckExpectCommitValue) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate testPersistentStorageDelegate; + chip::app::DefaultTermsAndConditionsStorageDelegate defaultTermsAndConditionsStorageDelegate; + err = defaultTermsAndConditionsStorageDelegate.Init(&testPersistentStorageDelegate); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // Initialize unit under test + chip::app::DefaultTermsAndConditionsProvider defaultTermsAndConditionsProvider; + chip::Optional requiredTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + err = defaultTermsAndConditionsProvider.Init(&defaultTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // Set acceptance + chip::Optional acceptedTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(0b1, 1)); + err = defaultTermsAndConditionsProvider.SetAcceptance(acceptedTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // Commit value + err = defaultTermsAndConditionsProvider.CommitAcceptance(); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // Check commit value + chip::Optional outTermsAndConditions; + err = defaultTermsAndConditionsProvider.GetAcceptance(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_TRUE(outTermsAndConditions.HasValue()); + EXPECT_EQ(outTermsAndConditions.Value().GetValue(), acceptedTermsAndConditions.Value().GetValue()); + EXPECT_EQ(outTermsAndConditions.Value().GetVersion(), acceptedTermsAndConditions.Value().GetVersion()); + + // Set updated value + chip::Optional updatedTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(0b11, 2)); + err = defaultTermsAndConditionsProvider.SetAcceptance(updatedTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // Check updated value + err = defaultTermsAndConditionsProvider.GetAcceptance(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_TRUE(outTermsAndConditions.HasValue()); + EXPECT_EQ(outTermsAndConditions.Value().GetValue(), updatedTermsAndConditions.Value().GetValue()); + EXPECT_EQ(outTermsAndConditions.Value().GetVersion(), updatedTermsAndConditions.Value().GetVersion()); + + // Revert updated value + err = defaultTermsAndConditionsProvider.RevertAcceptance(); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // Check committed value + err = defaultTermsAndConditionsProvider.GetAcceptance(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_TRUE(outTermsAndConditions.HasValue()); + EXPECT_EQ(outTermsAndConditions.Value().GetValue(), acceptedTermsAndConditions.Value().GetValue()); + EXPECT_EQ(outTermsAndConditions.Value().GetVersion(), acceptedTermsAndConditions.Value().GetVersion()); +} + +TEST(DefaultTermsAndConditionsProvider, TestRevertAcceptanceWhileMissing) +{ + CHIP_ERROR err; + + chip::TestPersistentStorageDelegate testPersistentStorageDelegate; + chip::app::DefaultTermsAndConditionsStorageDelegate defaultTermsAndConditionsStorageDelegate; + chip::app::DefaultTermsAndConditionsProvider defaultTermsAndConditionsProvider; + + chip::Optional requiredTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + + chip::Optional outTermsAndConditions; + + err = defaultTermsAndConditionsStorageDelegate.Init(&testPersistentStorageDelegate); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // Initialize unit under test [No conditions previously accepted] + err = defaultTermsAndConditionsProvider.Init(&defaultTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // [Fail-safe started] No conditions set during the fail-safe. No commit. + err = defaultTermsAndConditionsProvider.GetAcceptance(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_FALSE(outTermsAndConditions.HasValue()); + + // [Fail-safe expires] Revert is called. + err = defaultTermsAndConditionsProvider.RevertAcceptance(); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // [New fail safe started (to retry the commissioning operations)] Confirm acceptance returns previous values (empty) + err = defaultTermsAndConditionsProvider.GetAcceptance(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_FALSE(outTermsAndConditions.HasValue()); +} + +TEST(DefaultTermsAndConditionsProvider, TestRevertAcceptanceWhenPreviouslyAccepted) +{ + CHIP_ERROR err; + + // Initialize unit under test [Conditions previously accepted] + chip::Optional initialTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + chip::Optional requiredTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(0b11, 2)); + TestTermsAndConditionsStorageDelegate testTermsAndConditionsStorageDelegate(initialTermsAndConditions); + chip::app::DefaultTermsAndConditionsProvider defaultTermsAndConditionsProvider; + err = defaultTermsAndConditionsProvider.Init(&testTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // [Fail-safe started] No conditions set during the fail-safe. No commit. + + // [Fail-safe expires] Revert is called. + err = defaultTermsAndConditionsProvider.RevertAcceptance(); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional outTermsAndConditions; + + // [New fail safe started (to retry the commissioning operations)] Confirm acceptance returns previous values (accepted) + err = defaultTermsAndConditionsProvider.GetAcceptance(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_TRUE(outTermsAndConditions.HasValue()); + EXPECT_EQ(outTermsAndConditions.Value().GetValue(), 1); + EXPECT_EQ(outTermsAndConditions.Value().GetVersion(), 1); +} + +TEST(DefaultTermsAndConditionsProvider, TestRevertAcceptanceWhenPreviouslyAcceptedThenUpdatedUnderFailsafe) +{ + CHIP_ERROR err; + + // Initialize unit under test dependency + chip::Optional initiallyAcceptedTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(1, 1)); + TestTermsAndConditionsStorageDelegate testTermsAndConditionsStorageDelegate(initiallyAcceptedTermsAndConditions); + + // Initialize unit under test [Conditions previously accepted] + chip::Optional requiredTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(0b11, 2)); + chip::app::DefaultTermsAndConditionsProvider defaultTermsAndConditionsProvider; + err = defaultTermsAndConditionsProvider.Init(&testTermsAndConditionsStorageDelegate, requiredTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // [Fail-safe started] Acceptance updated. + chip::Optional updatedAcceptedTermsAndConditions = + chip::Optional(chip::app::TermsAndConditions(0b111, 3)); + err = defaultTermsAndConditionsProvider.SetAcceptance(updatedAcceptedTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // [Fail-safe expires] Revert is called. + err = defaultTermsAndConditionsProvider.RevertAcceptance(); + EXPECT_EQ(CHIP_NO_ERROR, err); + + chip::Optional outTermsAndConditions; + + // [New fail safe started (to retry the commissioning operations)] Confirm acceptance returns previous values (accepted) + err = defaultTermsAndConditionsProvider.GetAcceptance(outTermsAndConditions); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_TRUE(outTermsAndConditions.HasValue()); + EXPECT_EQ(outTermsAndConditions.Value().GetValue(), initiallyAcceptedTermsAndConditions.Value().GetValue()); + EXPECT_EQ(outTermsAndConditions.Value().GetVersion(), initiallyAcceptedTermsAndConditions.Value().GetVersion()); +} diff --git a/src/include/platform/CHIPDeviceEvent.h b/src/include/platform/CHIPDeviceEvent.h index 09f4c46b652920..9618d93f5faa05 100644 --- a/src/include/platform/CHIPDeviceEvent.h +++ b/src/include/platform/CHIPDeviceEvent.h @@ -534,6 +534,7 @@ struct ChipDeviceEvent final FabricIndex fabricIndex; bool addNocCommandHasBeenInvoked; bool updateNocCommandHasBeenInvoked; + bool updateTermsAndConditionsHasBeenInvoked; } FailSafeTimerExpired; struct diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index 9ed8a2f56cfd77..b0de78d085e48d 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2021-2024 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -256,6 +256,10 @@ class DefaultStorageKeyAllocator // when new fabric is created, this list needs to be updated, // when client init DefaultICDClientStorage, this table needs to be loaded. static StorageKeyName ICDFabricList() { return StorageKeyName::FromConst("g/icdfl"); } + + // Terms and Conditions Acceptance Key + // Stores the terms and conditions acceptance including terms and conditions revision, TLV encoded + static StorageKeyName TermsAndConditionsAcceptance() { return StorageKeyName::FromConst("g/tc"); } }; } // namespace chip From e394994d39e541379f4b20fa40d8b628f8c271b1 Mon Sep 17 00:00:00 2001 From: Martin Girardot <165289184+Martin-NXP@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:12:01 +0100 Subject: [PATCH 07/19] Custom BLE data at application layer (#36857) * [Zephyr] Add support to custom BLE advertising data at application layer Signed-off-by: Martin Girardot * [NXP][RTs] Add support to custom advertising data at application layer Signed-off-by: Martin Girardot * [NXP][examples[common] Add support to custom advertising data at application layer Signed-off-by: Martin Girardot * [NXP] Update nxp matter support submodule Signed-off-by: Martin Girardot * Restyled by whitespace * Restyled by clang-format * Restyled by gn * [NXP] update BLE include path Signed-off-by: Martin Girardot * Restyled by clang-format --------- Signed-off-by: Martin Girardot Co-authored-by: Restyled.io --- config/zephyr/Kconfig | 7 + .../nxp/common/main/AppTask.cpp | 3 + .../all-clusters-app/nxp/rt/rt1060/BUILD.gn | 4 + .../all-clusters-app/nxp/rt/rt1170/BUILD.gn | 4 + .../all-clusters-app/nxp/rt/rw61x/BUILD.gn | 4 + .../thermostat/nxp/common/main/AppTask.cpp | 11 + .../nxp/common/main/BleZephyrManagerApp.cpp | 100 ++++++ examples/thermostat/nxp/rt/rt1060/BUILD.gn | 16 + examples/thermostat/nxp/rt/rt1060/args.gni | 4 + examples/thermostat/nxp/rt/rt1170/BUILD.gn | 16 + examples/thermostat/nxp/rt/rt1170/args.gni | 4 + examples/thermostat/nxp/rt/rw61x/BUILD.gn | 16 + examples/thermostat/nxp/rt/rw61x/args.gni | 4 + examples/thermostat/nxp/zephyr/CMakeLists.txt | 11 + examples/thermostat/nxp/zephyr/prj.conf | 4 + src/platform/Zephyr/BLEManagerImpl.cpp | 31 +- src/platform/Zephyr/BLEManagerImpl.h | 8 + .../CHIPDeviceNXPPlatformDefaultConfig.h | 3 +- .../ble_zephyr/BLEAdvertisingArbiter.cpp | 31 +- .../common/ble_zephyr/BLEAdvertisingArbiter.h | 18 + .../nxp/common/ble_zephyr/BLEManagerImpl.cpp | 308 ++++++++++++++---- .../nxp/common/ble_zephyr/BLEManagerImpl.h | 18 +- third_party/nxp/nxp_matter_support | 2 +- 23 files changed, 545 insertions(+), 82 deletions(-) create mode 100644 examples/thermostat/nxp/common/main/BleZephyrManagerApp.cpp diff --git a/config/zephyr/Kconfig b/config/zephyr/Kconfig index d8717a625d3dd3..7b0ee1d15062d5 100644 --- a/config/zephyr/Kconfig +++ b/config/zephyr/Kconfig @@ -582,3 +582,10 @@ config CHIP_BLE_ADVERTISING_DURATION else the maximum duration time can be extended to 2880 minutes (48h). endif + +if BT +config CHIP_CUSTOM_BLE_ADV_DATA + bool "Use custom BLE advertising data" + help + Customization of BLE advertising data at the application layer +endif diff --git a/examples/all-clusters-app/nxp/common/main/AppTask.cpp b/examples/all-clusters-app/nxp/common/main/AppTask.cpp index 0b945d49561e43..702a63e89b5c8d 100644 --- a/examples/all-clusters-app/nxp/common/main/AppTask.cpp +++ b/examples/all-clusters-app/nxp/common/main/AppTask.cpp @@ -40,6 +40,9 @@ void AllClustersApp::AppTask::PostInitMatterStack() void AllClustersApp::AppTask::PostInitMatterServerInstance() { +#ifdef APP_BT_DEVICE_NAME + chip::DeviceLayer::ConnectivityMgr().SetBLEDeviceName(APP_BT_DEVICE_NAME); +#endif // Disable last fixed endpoint, which is used as a placeholder for all of the // supported clusters so that ZAP will generated the requisite code. emberAfEndpointEnableDisable(emberAfEndpointFromIndex(static_cast(emberAfFixedEndpointCount() - 1)), false); diff --git a/examples/all-clusters-app/nxp/rt/rt1060/BUILD.gn b/examples/all-clusters-app/nxp/rt/rt1060/BUILD.gn index beca71ac1002d8..d5a4936a48f5a0 100644 --- a/examples/all-clusters-app/nxp/rt/rt1060/BUILD.gn +++ b/examples/all-clusters-app/nxp/rt/rt1060/BUILD.gn @@ -223,6 +223,10 @@ rt_executable("all_cluster_app") { ] } + if (chip_enable_ble) { + defines += [ "APP_BT_DEVICE_NAME=\"NXP-AllClustersApp\"" ] + } + # In case a dedicated assert function needs to be supported the flag sdk_fsl_assert_support should be set to false # The would add to the build a dedicated application assert implementation. if (!sdk_fsl_assert_support) { diff --git a/examples/all-clusters-app/nxp/rt/rt1170/BUILD.gn b/examples/all-clusters-app/nxp/rt/rt1170/BUILD.gn index 70a0a4d640738c..edbd208506b824 100644 --- a/examples/all-clusters-app/nxp/rt/rt1170/BUILD.gn +++ b/examples/all-clusters-app/nxp/rt/rt1170/BUILD.gn @@ -188,6 +188,10 @@ rt_executable("all_cluster_app") { sources += [ "${common_example_dir}/wifi_connect/source/WifiConnect.cpp" ] } + if (chip_enable_ble) { + defines += [ "APP_BT_DEVICE_NAME=\"NXP-AllClustersApp\"" ] + } + # In case a dedicated assert function needs to be supported the flag sdk_fsl_assert_support should be set to false # The would add to the build a dedicated application assert implementation. if (!sdk_fsl_assert_support) { diff --git a/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn b/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn index 5b73da4bc92080..cb4e017b9b45bf 100644 --- a/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn +++ b/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn @@ -210,6 +210,10 @@ rt_executable("all_cluster_app") { sources += [ "${common_example_dir}/wifi_connect/source/WifiConnect.cpp" ] } + if (chip_enable_ble) { + defines += [ "APP_BT_DEVICE_NAME=\"NXP-AllClustersApp\"" ] + } + # In case a dedicated assert function needs to be supported the flag sdk_fsl_assert_support should be set to false # The would add to the build a dedicated application assert implementation. if (!sdk_fsl_assert_support) { diff --git a/examples/thermostat/nxp/common/main/AppTask.cpp b/examples/thermostat/nxp/common/main/AppTask.cpp index 8e3f8f1036a2e4..583e3c3dc1bbd4 100644 --- a/examples/thermostat/nxp/common/main/AppTask.cpp +++ b/examples/thermostat/nxp/common/main/AppTask.cpp @@ -24,6 +24,10 @@ #include #include +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#include "BLEApplicationManager.h" +#endif + using namespace chip; void ThermostatApp::AppTask::PreInitMatterStack() @@ -33,6 +37,13 @@ void ThermostatApp::AppTask::PreInitMatterStack() void ThermostatApp::AppTask::PostInitMatterStack() { +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE +#ifdef APP_BT_DEVICE_NAME + chip::DeviceLayer::ConnectivityMgr().SetBLEDeviceName(APP_BT_DEVICE_NAME); +#endif + /* BLEApplicationManager implemented per platform or left blank */ + chip::NXP::App::BleAppMgr().Init(); +#endif chip::app::InteractionModelEngine::GetInstance()->RegisterReadHandlerAppCallback(&chip::NXP::App::GetICDUtil()); } diff --git a/examples/thermostat/nxp/common/main/BleZephyrManagerApp.cpp b/examples/thermostat/nxp/common/main/BleZephyrManagerApp.cpp new file mode 100644 index 00000000000000..170ef3c4cc45ab --- /dev/null +++ b/examples/thermostat/nxp/common/main/BleZephyrManagerApp.cpp @@ -0,0 +1,100 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * Copyright 2024 NXP + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BLEApplicationManager.h" + +#include + +#include "BLEManagerImpl.h" +#include +#include +#include + +#define ADV_LEN 2 + +using namespace ::chip::DeviceLayer; +using namespace ::chip::DeviceLayer::Internal; +using namespace ::chip::NXP::App; + +BLEApplicationManager BLEApplicationManager::sInstance; + +struct ServiceData +{ + uint8_t uuid[2]; + chip::Ble::ChipBLEDeviceIdentificationInfo deviceIdInfo; +} __attribute__((packed)); + +ServiceData serviceData; +std::array advertisingData; +std::array scanResponseData; + +constexpr uint8_t kAdvertisingFlags = BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR; + +uint8_t manuf_data[ADV_LEN] = { + 0x25, + 0x00, +}; + +bt_uuid_16 UUID16_CHIPoBLEService = BT_UUID_INIT_16(0xFFF6); + +/** + * @brief Init BLE application manager + * + * In this example, the application manager is used to customize BLE advertising + * parameters. This example is provided for platforms with Zephyr BLE manager support. + * + * @note This example set custom Zephyr BLE manager Matter advertising parameters ( + * CONFIG_CHIP_CUSTOM_BLE_ADV_DATA for kconfig or ble_adv_data_custom for GN is set). + * To keep the advertising support for commissining, it is needed to register the whole + * adv data (adv flags + Matter adv data + custom adv data) and register scan + * response data as default adv and response data will be skipped. + * kAdvertisingFlags and manuf_data are given for examples, size of advertisingData and + * scanResponseData have to be set according to custom requirements. + * + * For custom Gatt services, APIs bt_gatt_service_register and bt_gatt_service_unregister + * could be called at application layer. It will not override Matter Gatt services but + * add new one. + * + * @note At the end of the commissioning advertising will be stopped. + * + * To start new advertising process, APIs : + * chip::DeviceLayer::BLEAdvertisingArbiter::InsertRequest + * chip::DeviceLayer::BLEAdvertisingArbiter::CancelRequest + * could be called. If InsertRequest API is called several time, only the request with the + * higher priority will be advertise. + * + */ +void BLEApplicationManager::Init(void) +{ + /* Register Matter adv data + custom adv data */ + static_assert(sizeof(serviceData) == 10, "Unexpected size of BLE advertising data!"); + const char * name = bt_get_name(); + const uint8_t nameSize = static_cast(strlen(name)); + Encoding::LittleEndian::Put16(serviceData.uuid, UUID16_CHIPoBLEService.val); + chip::DeviceLayer::ConfigurationMgr().GetBLEDeviceIdentificationInfo(serviceData.deviceIdInfo); + + advertisingData[0] = BT_DATA(BT_DATA_FLAGS, &kAdvertisingFlags, sizeof(kAdvertisingFlags)); + /* Matter adv data for commissining */ + advertisingData[1] = BT_DATA(BT_DATA_SVC_DATA16, &serviceData, sizeof(serviceData)); + /* Example of custom BLE adv data */ + advertisingData[2] = BT_DATA(BT_DATA_MANUFACTURER_DATA, manuf_data, ADV_LEN); + scanResponseData[0] = BT_DATA(BT_DATA_NAME_COMPLETE, name, nameSize); + chip::DeviceLayer::Internal::BLEMgrImpl().SetCustomAdvertising(Span(advertisingData)); + chip::DeviceLayer::Internal::BLEMgrImpl().SetCustomScanResponse(Span(scanResponseData)); +} diff --git a/examples/thermostat/nxp/rt/rt1060/BUILD.gn b/examples/thermostat/nxp/rt/rt1060/BUILD.gn index e57cc01b92b47b..c365ee9d47b4ca 100644 --- a/examples/thermostat/nxp/rt/rt1060/BUILD.gn +++ b/examples/thermostat/nxp/rt/rt1060/BUILD.gn @@ -147,6 +147,22 @@ rt_executable("thermostat") { "../../common/main/main.cpp", ] + if (chip_enable_ble) { + defines += [ "APP_BT_DEVICE_NAME=\"NXP-ThermostatApp\"" ] + include_dirs += [ "${common_example_dir}/app_ble/include" ] + if (ble_adv_data_custom) { + # to customize BLE advertising data + defines += [ "CONFIG_CHIP_CUSTOM_BLE_ADV_DATA=1" ] + include_dirs += [ "${chip_root}/src/platform/nxp/common/ble_zephyr" ] + sources += [ "../../common/main/BleZephyrManagerApp.cpp" ] + } else { + # Empty implementation, default matter advertising data + sources += [ + "${common_example_dir}/app_ble/source/BLEApplicationManagerEmpty.cpp", + ] + } + } + if (chip_with_diag_logs_demo) { include_dirs += [ "${common_example_dir}/diagnostic_logs/include", diff --git a/examples/thermostat/nxp/rt/rt1060/args.gni b/examples/thermostat/nxp/rt/rt1060/args.gni index c2d91a5db7bae7..d3fc29a80c4920 100644 --- a/examples/thermostat/nxp/rt/rt1060/args.gni +++ b/examples/thermostat/nxp/rt/rt1060/args.gni @@ -14,6 +14,10 @@ import("//build_overrides/chip.gni") +# Set to true to customized BLE advertising data at application layer, +# instead of default Zephyr BLE manager implementation advertising data +ble_adv_data_custom = true + # SDK target definitions nxp_sdk_target = get_label_info(":sdk", "label_no_toolchain") nxp_sdk_driver_target = get_label_info(":sdk_driver", "label_no_toolchain") diff --git a/examples/thermostat/nxp/rt/rt1170/BUILD.gn b/examples/thermostat/nxp/rt/rt1170/BUILD.gn index abb7090f962559..3e03df43488247 100644 --- a/examples/thermostat/nxp/rt/rt1170/BUILD.gn +++ b/examples/thermostat/nxp/rt/rt1170/BUILD.gn @@ -135,6 +135,22 @@ rt_executable("thermostat") { "../../common/main/main.cpp", ] + if (chip_enable_ble) { + defines += [ "APP_BT_DEVICE_NAME=\"NXP-ThermostatApp\"" ] + include_dirs += [ "${common_example_dir}/app_ble/include" ] + if (ble_adv_data_custom) { + # to customize BLE advertising data + defines += [ "CONFIG_CHIP_CUSTOM_BLE_ADV_DATA=1" ] + include_dirs += [ "${chip_root}/src/platform/nxp/common/ble_zephyr" ] + sources += [ "../../common/main/BleZephyrManagerApp.cpp" ] + } else { + # Empty implementation, default matter advertising data + sources += [ + "${common_example_dir}/app_ble/source/BLEApplicationManagerEmpty.cpp", + ] + } + } + if (chip_with_diag_logs_demo) { include_dirs += [ "${common_example_dir}/diagnostic_logs/include", diff --git a/examples/thermostat/nxp/rt/rt1170/args.gni b/examples/thermostat/nxp/rt/rt1170/args.gni index c2d91a5db7bae7..d3fc29a80c4920 100644 --- a/examples/thermostat/nxp/rt/rt1170/args.gni +++ b/examples/thermostat/nxp/rt/rt1170/args.gni @@ -14,6 +14,10 @@ import("//build_overrides/chip.gni") +# Set to true to customized BLE advertising data at application layer, +# instead of default Zephyr BLE manager implementation advertising data +ble_adv_data_custom = true + # SDK target definitions nxp_sdk_target = get_label_info(":sdk", "label_no_toolchain") nxp_sdk_driver_target = get_label_info(":sdk_driver", "label_no_toolchain") diff --git a/examples/thermostat/nxp/rt/rw61x/BUILD.gn b/examples/thermostat/nxp/rt/rw61x/BUILD.gn index 07a58e947756c6..6dd71061c010c5 100644 --- a/examples/thermostat/nxp/rt/rw61x/BUILD.gn +++ b/examples/thermostat/nxp/rt/rw61x/BUILD.gn @@ -145,6 +145,22 @@ rt_executable("thermostat") { "../../common/main/main.cpp", ] + if (chip_enable_ble) { + defines += [ "APP_BT_DEVICE_NAME=\"NXP-ThermostatApp\"" ] + include_dirs += [ "${common_example_dir}/app_ble/include" ] + if (ble_adv_data_custom) { + # to customize BLE advertising data + defines += [ "CONFIG_CHIP_CUSTOM_BLE_ADV_DATA=1" ] + include_dirs += [ "${chip_root}/src/platform/nxp/common/ble_zephyr" ] + sources += [ "../../common/main/BleZephyrManagerApp.cpp" ] + } else { + # Empty implementation, default matter advertising data + sources += [ + "${common_example_dir}/app_ble/source/BLEApplicationManagerEmpty.cpp", + ] + } + } + if (chip_with_diag_logs_demo) { include_dirs += [ "${common_example_dir}/diagnostic_logs/include", diff --git a/examples/thermostat/nxp/rt/rw61x/args.gni b/examples/thermostat/nxp/rt/rw61x/args.gni index c2d91a5db7bae7..d3fc29a80c4920 100644 --- a/examples/thermostat/nxp/rt/rw61x/args.gni +++ b/examples/thermostat/nxp/rt/rw61x/args.gni @@ -14,6 +14,10 @@ import("//build_overrides/chip.gni") +# Set to true to customized BLE advertising data at application layer, +# instead of default Zephyr BLE manager implementation advertising data +ble_adv_data_custom = true + # SDK target definitions nxp_sdk_target = get_label_info(":sdk", "label_no_toolchain") nxp_sdk_driver_target = get_label_info(":sdk_driver", "label_no_toolchain") diff --git a/examples/thermostat/nxp/zephyr/CMakeLists.txt b/examples/thermostat/nxp/zephyr/CMakeLists.txt index b478cfff9f2566..221e66e2451162 100644 --- a/examples/thermostat/nxp/zephyr/CMakeLists.txt +++ b/examples/thermostat/nxp/zephyr/CMakeLists.txt @@ -52,6 +52,7 @@ target_include_directories(app ${EXAMPLE_PLATFORM_NXP_COMMON_DIR}/device_callbacks/include ${EXAMPLE_PLATFORM_NXP_COMMON_DIR}/factory_data/include ${EXAMPLE_PLATFORM_NXP_COMMON_DIR}/app_task/include + ${EXAMPLE_PLATFORM_NXP_COMMON_DIR}/app_ble/include ) target_sources(app @@ -73,6 +74,16 @@ target_compile_definitions(app PUBLIC "EXTERNAL_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/zephyr/FactoryDataProviderImpl.h\"" ) +if(CONFIG_CHIP_CUSTOM_BLE_ADV_DATA) + target_sources(app PRIVATE + ${THERMOSTAT_NXP_COMMON_DIR}/main/BleZephyrManagerApp.cpp + ) +else() + target_sources(app PRIVATE + ${EXAMPLE_PLATFORM_NXP_COMMON_DIR}/app_ble/source/BLEApplicationManagerEmpty.cpp + ) +endif() + if(CONFIG_CHIP_OTA_REQUESTOR) target_sources(app PRIVATE ${EXAMPLE_PLATFORM_NXP_COMMON_DIR}/ota_requestor/source/OTARequestorInitiatorCommon.cpp diff --git a/examples/thermostat/nxp/zephyr/prj.conf b/examples/thermostat/nxp/zephyr/prj.conf index a2fa69056d517e..6e1ad43097242d 100644 --- a/examples/thermostat/nxp/zephyr/prj.conf +++ b/examples/thermostat/nxp/zephyr/prj.conf @@ -56,3 +56,7 @@ CONFIG_CHIP_LIB_SHELL=y # enable NET commands if desired # CONFIG_NET_SHELL=y CONFIG_CHIP_STATISTICS=y + +# To customized BLE advertising data at application layer, +# instead of default Zephyr BLE manager implementation advertising data +CONFIG_CHIP_CUSTOM_BLE_ADV_DATA=y diff --git a/src/platform/Zephyr/BLEManagerImpl.cpp b/src/platform/Zephyr/BLEManagerImpl.cpp index 49751da62479e3..6b8ba4b6989ce6 100644 --- a/src/platform/Zephyr/BLEManagerImpl.cpp +++ b/src/platform/Zephyr/BLEManagerImpl.cpp @@ -284,6 +284,13 @@ struct BLEManagerImpl::ServiceData inline CHIP_ERROR BLEManagerImpl::PrepareAdvertisingRequest() { +#ifdef CONFIG_CHIP_CUSTOM_BLE_ADV_DATA + if (mCustomAdvertising.empty()) + { + ChipLogError(DeviceLayer, "mCustomAdvertising should be set when CONFIG_CHIP_CUSTOM_BLE_ADV_DATA is define"); + return CHIP_ERROR_INTERNAL; + } +#else static ServiceData serviceData; static std::array advertisingData; static std::array scanResponseData; @@ -304,9 +311,10 @@ inline CHIP_ERROR BLEManagerImpl::PrepareAdvertisingRequest() } #endif - advertisingData[0] = BT_DATA(BT_DATA_FLAGS, &kAdvertisingFlags, sizeof(kAdvertisingFlags)); - advertisingData[1] = BT_DATA(BT_DATA_SVC_DATA16, &serviceData, sizeof(serviceData)); - scanResponseData[0] = BT_DATA(BT_DATA_NAME_COMPLETE, name, nameSize); + advertisingData[0] = BT_DATA(BT_DATA_FLAGS, &kAdvertisingFlags, sizeof(kAdvertisingFlags)); + advertisingData[1] = BT_DATA(BT_DATA_SVC_DATA16, &serviceData, sizeof(serviceData)); + scanResponseData[0] = BT_DATA(BT_DATA_NAME_COMPLETE, name, nameSize); +#endif // CONFIG_CHIP_CUSTOM_BLE_ADV_DATA mAdvertisingRequest.priority = CHIP_DEVICE_BLE_ADVERTISING_PRIORITY; mAdvertisingRequest.options = kAdvertisingOptions; @@ -328,9 +336,13 @@ inline CHIP_ERROR BLEManagerImpl::PrepareAdvertisingRequest() mAdvertisingRequest.minInterval = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; mAdvertisingRequest.maxInterval = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; } +#ifdef CONFIG_CHIP_CUSTOM_BLE_ADV_DATA + mAdvertisingRequest.advertisingData = mCustomAdvertising; + mAdvertisingRequest.scanResponseData = mCustomScanResponse; +#else mAdvertisingRequest.advertisingData = Span(advertisingData); mAdvertisingRequest.scanResponseData = nameSize ? Span(scanResponseData) : Span{}; - +#endif mAdvertisingRequest.onStarted = [](int rc) { if (rc == 0) { @@ -967,6 +979,17 @@ ssize_t BLEManagerImpl::HandleC3Read(struct bt_conn * conId, const struct bt_gat } #endif +#ifdef CONFIG_CHIP_CUSTOM_BLE_ADV_DATA +void BLEManagerImpl::SetCustomAdvertising(Span CustomAdvertising) +{ + mCustomAdvertising = CustomAdvertising; +} +void BLEManagerImpl::SetCustomScanResponse(Span CustomScanResponse) +{ + mCustomScanResponse = CustomScanResponse; +} +#endif + } // namespace Internal } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/Zephyr/BLEManagerImpl.h b/src/platform/Zephyr/BLEManagerImpl.h index 8c09ed457f94b2..9e83dc47ed6ae6 100644 --- a/src/platform/Zephyr/BLEManagerImpl.h +++ b/src/platform/Zephyr/BLEManagerImpl.h @@ -105,6 +105,10 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla #endif // The summarized number of Bluetooth LE connections related to the device (including these not related to Matter service). uint16_t mTotalConnNum; +#ifdef CONFIG_CHIP_CUSTOM_BLE_ADV_DATA + Span mCustomAdvertising = {}; + Span mCustomScanResponse = {}; +#endif void DriveBLEState(void); CHIP_ERROR PrepareAdvertisingRequest(); @@ -150,6 +154,10 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING static ssize_t HandleC3Read(struct bt_conn * conn, const struct bt_gatt_attr * attr, void * buf, uint16_t len, uint16_t offset); #endif +#ifdef CONFIG_CHIP_CUSTOM_BLE_ADV_DATA + void SetCustomAdvertising(Span CustomAdvertising); + void SetCustomScanResponse(Span CustomScanResponse); +#endif }; /** diff --git a/src/platform/nxp/common/CHIPDeviceNXPPlatformDefaultConfig.h b/src/platform/nxp/common/CHIPDeviceNXPPlatformDefaultConfig.h index 5e5fd2b14d5fea..79ceb200dbe1c5 100644 --- a/src/platform/nxp/common/CHIPDeviceNXPPlatformDefaultConfig.h +++ b/src/platform/nxp/common/CHIPDeviceNXPPlatformDefaultConfig.h @@ -85,7 +85,8 @@ #ifndef CHIP_DEVICE_BLE_ADVERTISING_PRIORITY /// Priority of the Matter BLE advertising when there are multiple application /// components that compete for the BLE advertising. -#define CHIP_DEVICE_BLE_ADVERTISING_PRIORITY 0 +/// Increase priority to 1 to allow user to insert custom advertising data with higher priority (0) +#define CHIP_DEVICE_BLE_ADVERTISING_PRIORITY 1 #endif // CHIP_DEVICE_BLE_ADVERTISING_PRIORITY // ========== Platform-specific Configuration ========= diff --git a/src/platform/nxp/common/ble_zephyr/BLEAdvertisingArbiter.cpp b/src/platform/nxp/common/ble_zephyr/BLEAdvertisingArbiter.cpp index ee6b91da3f9c7e..f66b98317e27e3 100644 --- a/src/platform/nxp/common/ble_zephyr/BLEAdvertisingArbiter.cpp +++ b/src/platform/nxp/common/ble_zephyr/BLEAdvertisingArbiter.cpp @@ -29,6 +29,9 @@ namespace { // List of advertising requests ordered by priority sys_slist_t sRequests; +bool sIsInitialized = false; +uint8_t sBtId = 0; + // Cast an intrusive list node to the containing request object const BLEAdvertisingArbiter::Request & ToRequest(const sys_snode_t * node) { @@ -55,8 +58,9 @@ CHIP_ERROR RestartAdvertising() ReturnErrorOnFailure(MapErrorZephyr(bt_le_adv_stop())); VerifyOrReturnError(!sys_slist_is_empty(&sRequests), CHIP_NO_ERROR); - const Request & top = ToRequest(sys_slist_peek_head(&sRequests)); - const bt_le_adv_param params = BT_LE_ADV_PARAM_INIT(top.options, top.minInterval, top.maxInterval, nullptr); + const Request & top = ToRequest(sys_slist_peek_head(&sRequests)); + bt_le_adv_param params = BT_LE_ADV_PARAM_INIT(top.options, top.minInterval, top.maxInterval, nullptr); + params.id = sBtId; const int result = bt_le_adv_start(¶ms, top.advertisingData.data(), top.advertisingData.size(), top.scanResponseData.data(), top.scanResponseData.size()); @@ -70,8 +74,26 @@ CHIP_ERROR RestartAdvertising() } // namespace +CHIP_ERROR Init(uint8_t btId) +{ + if (sIsInitialized) + { + return CHIP_ERROR_INCORRECT_STATE; + } + + sBtId = btId; + sIsInitialized = true; + + return CHIP_NO_ERROR; +} + CHIP_ERROR InsertRequest(Request & request) { + if (!sIsInitialized) + { + return CHIP_ERROR_INCORRECT_STATE; + } + CancelRequest(request); sys_snode_t * prev = nullptr; @@ -109,6 +131,11 @@ CHIP_ERROR InsertRequest(Request & request) void CancelRequest(Request & request) { + if (!sIsInitialized) + { + return; + } + const bool isTopPriority = (sys_slist_peek_head(&sRequests) == &request); VerifyOrReturn(sys_slist_find_and_remove(&sRequests, &request)); diff --git a/src/platform/nxp/common/ble_zephyr/BLEAdvertisingArbiter.h b/src/platform/nxp/common/ble_zephyr/BLEAdvertisingArbiter.h index 11a90c7070cd0a..0204a406244eab 100644 --- a/src/platform/nxp/common/ble_zephyr/BLEAdvertisingArbiter.h +++ b/src/platform/nxp/common/ble_zephyr/BLEAdvertisingArbiter.h @@ -62,6 +62,18 @@ struct Request : public sys_snode_t OnAdvertisingStopped onStopped; ///< (Optional) Callback invoked when the request stops being top-priority. }; +/** + * @brief Initialize BLE advertising arbiter + * + * @note This method must be called before trying to insert or cancel any requests. + * + * @param btId Local Bluetooth LE identifier to be used for the advertising parameters. Currently Bluetooth LE identifier used in + * this method will be used for all advertising requests and changing it dynamically is not supported. + * @return error If the module is already initialized. + * @return success Otherwise. + */ +CHIP_ERROR Init(uint8_t btId); + /** * @brief Request BLE advertising * @@ -75,6 +87,9 @@ struct Request : public sys_snode_t * @note This method does not take ownership of the request object so the object * must not get destroyed before it is cancelled. * + * @note The arbiter module has to be initialized using Init() method before + * invoking this method. + * * @param request Reference to advertising request that contains priority and * other advertising parameters. * @return error If the request is top-priority and failed to restart the @@ -95,6 +110,9 @@ CHIP_ERROR InsertRequest(Request & request); * An attempt to cancel a request that has not been registered at the * advertising arbiter is a no-op. That is, it returns immediately. * + * @note The arbiter module has to be initialized using Init() method before + * invoking this method. + * * @param request Reference to advertising request that contains priority and * other advertising parameters. */ diff --git a/src/platform/nxp/common/ble_zephyr/BLEManagerImpl.cpp b/src/platform/nxp/common/ble_zephyr/BLEManagerImpl.cpp index 0d1c4c0dcb8932..aca08a9339b243 100644 --- a/src/platform/nxp/common/ble_zephyr/BLEManagerImpl.cpp +++ b/src/platform/nxp/common/ble_zephyr/BLEManagerImpl.cpp @@ -27,9 +27,10 @@ #include "BLEManagerImpl.h" -#include +#include #include #include +#include #include #include #include @@ -44,6 +45,10 @@ #include #include +#ifdef CONFIG_BT_BONDABLE +#include +#endif // CONFIG_BT_BONDABLE + #include using namespace ::chip; @@ -70,12 +75,6 @@ const bt_uuid_128 UUID128_CHIPoBLEChar_C3 = bt_uuid_16 UUID16_CHIPoBLEService = BT_UUID_INIT_16(0xFFF6); -const ChipBleUUID chipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, - 0x9D, 0x11 } }; - -const ChipBleUUID chipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, - 0x9D, 0x12 } }; - _bt_gatt_ccc CHIPoBLEChar_TX_CCC = BT_GATT_CCC_INITIALIZER(nullptr, BLEManagerImpl::HandleTXCCCWrite, nullptr); // clang-format off @@ -107,7 +106,13 @@ bt_gatt_service sChipoBleService = BT_GATT_SERVICE(sChipoBleAttributes); // This value should be adjusted accordingly if the service declaration changes. constexpr int kCHIPoBLE_CCC_AttributeIndex = 3; -CHIP_ERROR InitRandomStaticAddress() +#ifdef CONFIG_BT_BONDABLE +constexpr uint8_t kMatterBleIdentity = 1; +#else +constexpr uint8_t kMatterBleIdentity = 0; +#endif // CONFIG_BT_BONDABLE + +int InitRandomStaticAddress(bool idPresent, int & id) { // Generate a random static address for the default identity. // This must be done before bt_enable() as after that updating the default identity is not possible. @@ -122,20 +127,29 @@ CHIP_ERROR InitRandomStaticAddress() if (error) { ChipLogError(DeviceLayer, "Failed to create BLE address: %d", error); - return MapErrorZephyr(error); + return error; } - error = bt_id_create(&addr, nullptr); + if (!idPresent) + { + id = bt_id_create(&addr, nullptr); + } +#if CONFIG_BT_ID_MAX == 2 + else + { + id = bt_id_reset(1, &addr, nullptr); + } +#endif // CONFIG_BT_BONDABLE - if (error < 0) + if (id < 0) { ChipLogError(DeviceLayer, "Failed to create BLE identity: %d", error); - return MapErrorZephyr(error); + return id; } ChipLogProgress(DeviceLayer, "BLE address: %02X:%02X:%02X:%02X:%02X:%02X", addr.a.val[5], addr.a.val[4], addr.a.val[3], addr.a.val[2], addr.a.val[1], addr.a.val[0]); - return CHIP_NO_ERROR; + return 0; } } // unnamed namespace @@ -144,16 +158,41 @@ BLEManagerImpl BLEManagerImpl::sInstance; CHIP_ERROR BLEManagerImpl::_Init() { + int err = 0; + int id = 0; + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART); mFlags.Set(Flags::kFastAdvertisingEnabled, true); - mGAPConns = 0; + mMatterConnNum = 0; + mTotalConnNum = 0; memset(mSubscribedConns, 0, sizeof(mSubscribedConns)); - ReturnErrorOnFailure(InitRandomStaticAddress()); - int err = bt_enable(NULL); +#ifdef CONFIG_BT_BONDABLE + bt_addr_le_t idsAddr[CONFIG_BT_ID_MAX]; + size_t idsCount = CONFIG_BT_ID_MAX; + + err = bt_enable(nullptr); + + VerifyOrReturnError(err == 0, MapErrorZephyr(err)); + + settings_load(); + + bt_id_get(idsAddr, &idsCount); + + err = InitRandomStaticAddress(idsCount > 1, id); + + VerifyOrReturnError(err == 0 && id == kMatterBleIdentity, MapErrorZephyr(err)); + +#else + err = InitRandomStaticAddress(false, id); + VerifyOrReturnError(err == 0 && id == kMatterBleIdentity, MapErrorZephyr(err)); + err = bt_enable(nullptr); VerifyOrReturnError(err == 0, MapErrorZephyr(err)); +#endif // CONFIG_BT_BONDABLE + + BLEAdvertisingArbiter::Init(static_cast(id)); memset(&mConnCallbacks, 0, sizeof(mConnCallbacks)); mConnCallbacks.connected = HandleConnect; @@ -199,7 +238,13 @@ void BLEManagerImpl::DriveBLEState() { mFlags.Clear(Flags::kAdvertisingRefreshNeeded); err = StartAdvertising(); - SuccessOrExit(err); + if (err != CHIP_NO_ERROR) + { + // Return prematurely but keep the CHIPoBLE service mode enabled to allow advertising retries + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; + ChipLogError(DeviceLayer, "Could not start CHIPoBLE service due to error: %" CHIP_ERROR_FORMAT, err.Format()); + return; + } } } else @@ -207,7 +252,12 @@ void BLEManagerImpl::DriveBLEState() if (mFlags.Has(Flags::kAdvertising)) { err = StopAdvertising(); - SuccessOrExit(err); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %" CHIP_ERROR_FORMAT, err.Format()); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + return; + } } // If no connections are active unregister also CHIPoBLE GATT service @@ -224,13 +274,6 @@ void BLEManagerImpl::DriveBLEState() } } } - -exit: - if (err != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %" CHIP_ERROR_FORMAT, err.Format()); - mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; - } } struct BLEManagerImpl::ServiceData @@ -241,6 +284,13 @@ struct BLEManagerImpl::ServiceData inline CHIP_ERROR BLEManagerImpl::PrepareAdvertisingRequest() { +#ifdef CONFIG_CHIP_CUSTOM_BLE_ADV_DATA + if (mCustomAdvertising.empty()) + { + ChipLogError(DeviceLayer, "mCustomAdvertising should be set when CONFIG_CHIP_CUSTOM_BLE_ADV_DATA is define"); + return CHIP_ERROR_INTERNAL; + } +#else static ServiceData serviceData; static std::array advertisingData; static std::array scanResponseData; @@ -252,21 +302,47 @@ inline CHIP_ERROR BLEManagerImpl::PrepareAdvertisingRequest() Encoding::LittleEndian::Put16(serviceData.uuid, UUID16_CHIPoBLEService.val); ReturnErrorOnFailure(ConfigurationMgr().GetBLEDeviceIdentificationInfo(serviceData.deviceIdInfo)); - advertisingData[0] = BT_DATA(BT_DATA_FLAGS, &kAdvertisingFlags, sizeof(kAdvertisingFlags)); - advertisingData[1] = BT_DATA(BT_DATA_SVC_DATA16, &serviceData, sizeof(serviceData)); - scanResponseData[0] = BT_DATA(BT_DATA_NAME_COMPLETE, name, nameSize); - - mAdvertisingRequest.priority = CHIP_DEVICE_BLE_ADVERTISING_PRIORITY; - mAdvertisingRequest.options = kAdvertisingOptions; - mAdvertisingRequest.minInterval = mFlags.Has(Flags::kFastAdvertisingEnabled) - ? CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN - : CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; - mAdvertisingRequest.maxInterval = mFlags.Has(Flags::kFastAdvertisingEnabled) - ? CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX - : CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; +#if CHIP_DEVICE_CONFIG_EXT_ADVERTISING + if (mFlags.Has(Flags::kExtendedAdvertisingEnabled)) + { + serviceData.deviceIdInfo.SetVendorId(DEVICE_HANDLE_NULL); + serviceData.deviceIdInfo.SetProductId(DEVICE_HANDLE_NULL); + serviceData.deviceIdInfo.SetExtendedAnnouncementFlag(true); + } +#endif + + advertisingData[0] = BT_DATA(BT_DATA_FLAGS, &kAdvertisingFlags, sizeof(kAdvertisingFlags)); + advertisingData[1] = BT_DATA(BT_DATA_SVC_DATA16, &serviceData, sizeof(serviceData)); + scanResponseData[0] = BT_DATA(BT_DATA_NAME_COMPLETE, name, nameSize); +#endif + + mAdvertisingRequest.priority = CHIP_DEVICE_BLE_ADVERTISING_PRIORITY; + mAdvertisingRequest.options = kAdvertisingOptions; + + if (mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + mAdvertisingRequest.minInterval = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN; + mAdvertisingRequest.maxInterval = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX; + } +#if CHIP_DEVICE_CONFIG_EXT_ADVERTISING + else if (mFlags.Has(Flags::kExtendedAdvertisingEnabled)) + { + mAdvertisingRequest.minInterval = CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MIN; + mAdvertisingRequest.maxInterval = CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MAX; + } +#endif + else + { + mAdvertisingRequest.minInterval = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; + mAdvertisingRequest.maxInterval = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; + } +#ifdef CONFIG_CHIP_CUSTOM_BLE_ADV_DATA + mAdvertisingRequest.advertisingData = mCustomAdvertising; + mAdvertisingRequest.scanResponseData = mCustomScanResponse; +#else mAdvertisingRequest.advertisingData = Span(advertisingData); mAdvertisingRequest.scanResponseData = nameSize ? Span(scanResponseData) : Span{}; - +#endif mAdvertisingRequest.onStarted = [](int rc) { if (rc == 0) { @@ -275,29 +351,53 @@ inline CHIP_ERROR BLEManagerImpl::PrepareAdvertisingRequest() else { ChipLogError(DeviceLayer, "Failed to start CHIPoBLE advertising: %d", rc); + BLEManagerImpl().StopAdvertising(); } }; return CHIP_NO_ERROR; } -CHIP_ERROR BLEManagerImpl::StartAdvertising() +CHIP_ERROR BLEManagerImpl::RegisterGattService() { - // Prepare advertising request - ReturnErrorOnFailure(PrepareAdvertisingRequest()); - - // Register dynamically CHIPoBLE GATT service + // Register CHIPoBLE GATT service if (!mFlags.Has(Flags::kChipoBleGattServiceRegister)) { int err = bt_gatt_service_register(&sChipoBleService); - if (err != 0) - ChipLogError(DeviceLayer, "Failed to register CHIPoBLE GATT service"); + { + ChipLogError(DeviceLayer, "Failed to register CHIPoBLE GATT service: %d", err); + } VerifyOrReturnError(err == 0, MapErrorZephyr(err)); - mFlags.Set(Flags::kChipoBleGattServiceRegister); } + return CHIP_NO_ERROR; +} + +CHIP_ERROR BLEManagerImpl::UnregisterGattService() +{ + // Unregister CHIPoBLE GATT service + if (mFlags.Has(Flags::kChipoBleGattServiceRegister)) + { + int err = bt_gatt_service_unregister(&sChipoBleService); + if (err != 0) + { + ChipLogError(DeviceLayer, "Failed to unregister CHIPoBLE GATT service: %d", err); + } + + VerifyOrReturnError(err == 0, MapErrorZephyr(err)); + mFlags.Clear(Flags::kChipoBleGattServiceRegister); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR BLEManagerImpl::StartAdvertising() +{ + // Prepare advertising request + ReturnErrorOnFailure(PrepareAdvertisingRequest()); + // We need to register GATT service before issuing the advertising to start + ReturnErrorOnFailure(RegisterGattService()); // Initialize C3 characteristic data #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING @@ -305,7 +405,13 @@ CHIP_ERROR BLEManagerImpl::StartAdvertising() #endif // Request advertising - ReturnErrorOnFailure(BLEAdvertisingArbiter::InsertRequest(mAdvertisingRequest)); + CHIP_ERROR err = BLEAdvertisingArbiter::InsertRequest(mAdvertisingRequest); + if (CHIP_NO_ERROR != err) + { + // It makes not sense to keep GATT services registered after the advertising request failed + (void) UnregisterGattService(); + return err; + } // Transition to the Advertising state... if (!mFlags.Has(Flags::kAdvertising)) @@ -322,10 +428,17 @@ CHIP_ERROR BLEManagerImpl::StartAdvertising() if (mFlags.Has(Flags::kFastAdvertisingEnabled)) { - // Start timer to change advertising interval. + // Start timer to change advertising interval from fast to slow. DeviceLayer::SystemLayer().StartTimer( System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME), - HandleBLEAdvertisementIntervalChange, this); + HandleSlowBLEAdvertisementInterval, this); + +#if CHIP_DEVICE_CONFIG_EXT_ADVERTISING + // Start timer to schedule start of the extended advertising + DeviceLayer::SystemLayer().StartTimer( + System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS), + HandleExtendedBLEAdvertisementInterval, this); +#endif } } @@ -342,6 +455,10 @@ CHIP_ERROR BLEManagerImpl::StopAdvertising() mFlags.Clear(Flags::kAdvertising); mFlags.Set(Flags::kFastAdvertisingEnabled, true); +#if CHIP_DEVICE_CONFIG_EXT_ADVERTISING + mFlags.Clear(Flags::kExtendedAdvertisingEnabled); +#endif + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped"); // Post a CHIPoBLEAdvertisingChange(Stopped) event. @@ -353,7 +470,12 @@ CHIP_ERROR BLEManagerImpl::StopAdvertising() } // Cancel timer event changing CHIPoBLE advertisement interval - DeviceLayer::SystemLayer().CancelTimer(HandleBLEAdvertisementIntervalChange, this); + DeviceLayer::SystemLayer().CancelTimer(HandleSlowBLEAdvertisementInterval, this); + DeviceLayer::SystemLayer().CancelTimer(HandleExtendedBLEAdvertisementInterval, this); + } + else + { + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising already stopped"); } return CHIP_NO_ERROR; @@ -361,13 +483,13 @@ CHIP_ERROR BLEManagerImpl::StopAdvertising() CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) { - if (mFlags.Has(Flags::kAdvertisingEnabled) != val) - { - ChipLogDetail(DeviceLayer, "CHIPoBLE advertising set to %s", val ? "on" : "off"); + ChipLogDetail(DeviceLayer, "CHIPoBLE advertising set to %s", val ? "on" : "off"); - mFlags.Set(Flags::kAdvertisingEnabled, val); - PlatformMgr().ScheduleWork(DriveBLEState, 0); - } + mFlags.Set(Flags::kAdvertisingEnabled, val); + // Ensure that each enabling/disabling of the general advertising clears + // the extended mode, to make sure we always start fresh in the regular mode + mFlags.Set(Flags::kExtendedAdvertisingEnabled, false); + PlatformMgr().ScheduleWork(DriveBLEState, 0); return CHIP_NO_ERROR; } @@ -378,8 +500,14 @@ CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode) { case BLEAdvertisingMode::kFastAdvertising: mFlags.Set(Flags::kFastAdvertisingEnabled, true); + mFlags.Set(Flags::kExtendedAdvertisingEnabled, false); break; case BLEAdvertisingMode::kSlowAdvertising: + mFlags.Set(Flags::kFastAdvertisingEnabled, false); + mFlags.Set(Flags::kExtendedAdvertisingEnabled, false); + break; + case BLEAdvertisingMode::kExtendedAdvertising: + mFlags.Set(Flags::kExtendedAdvertisingEnabled, true); mFlags.Set(Flags::kFastAdvertisingEnabled, false); break; default: @@ -410,15 +538,13 @@ CHIP_ERROR BLEManagerImpl::HandleGAPConnect(const ChipDeviceEvent * event) if (connEvent->HciResult == BT_HCI_ERR_SUCCESS) { ChipLogProgress(DeviceLayer, "BLE connection established (ConnId: 0x%02x)", bt_conn_index(connEvent->BtConn)); - mGAPConns++; + mMatterConnNum++; } else { ChipLogError(DeviceLayer, "BLE connection failed (reason: 0x%02x)", connEvent->HciResult); } - ChipLogProgress(DeviceLayer, "Current number of connections: %u/%u", NumConnections(), CONFIG_BT_MAX_CONN); - mFlags.Set(Flags::kAdvertisingRefreshNeeded); PlatformMgr().ScheduleWork(DriveBLEState, 0); @@ -433,7 +559,10 @@ CHIP_ERROR BLEManagerImpl::HandleGAPDisconnect(const ChipDeviceEvent * event) ChipLogProgress(DeviceLayer, "BLE GAP connection terminated (reason 0x%02x)", connEvent->HciResult); - mGAPConns--; + if (mMatterConnNum > 0) + { + mMatterConnNum--; + } // If indications were enabled for this connection, record that they are now disabled and // notify the BLE Layer of a disconnect. @@ -461,8 +590,6 @@ CHIP_ERROR BLEManagerImpl::HandleGAPDisconnect(const ChipDeviceEvent * event) // Unref bt_conn before scheduling DriveBLEState. bt_conn_unref(connEvent->BtConn); - ChipLogProgress(DeviceLayer, "Current number of connections: %u/%u", NumConnections(), CONFIG_BT_MAX_CONN); - ChipDeviceEvent disconnectEvent; disconnectEvent.Type = DeviceEventType::kCHIPoBLEConnectionClosed; ReturnErrorOnFailure(PlatformMgr().PostEvent(&disconnectEvent)); @@ -485,7 +612,7 @@ CHIP_ERROR BLEManagerImpl::HandleTXCharCCCDWrite(const ChipDeviceEvent * event) if (writeEvent->Value == BT_GATT_CCC_INDICATE && SetSubscribed(writeEvent->BtConn)) { // Alert the BLE layer that CHIPoBLE "subscribe" has been received and increment the bt_conn reference counter. - HandleSubscribeReceived(writeEvent->BtConn, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); + HandleSubscribeReceived(writeEvent->BtConn, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); ChipLogProgress(DeviceLayer, "CHIPoBLE connection established (ConnId: 0x%02x, GATT MTU: %u)", bt_conn_index(writeEvent->BtConn), GetMTU(writeEvent->BtConn)); @@ -501,7 +628,7 @@ CHIP_ERROR BLEManagerImpl::HandleTXCharCCCDWrite(const ChipDeviceEvent * event) { if (UnsetSubscribed(writeEvent->BtConn)) { - HandleUnsubscribeReceived(writeEvent->BtConn, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); + HandleUnsubscribeReceived(writeEvent->BtConn, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); } } @@ -517,7 +644,7 @@ CHIP_ERROR BLEManagerImpl::HandleRXCharWrite(const ChipDeviceEvent * event) ChipLogDetail(DeviceLayer, "Write request received for CHIPoBLE RX characteristic (ConnId 0x%02x)", bt_conn_index(c1WriteEvent->BtConn)); - HandleWriteReceived(c1WriteEvent->BtConn, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_RX, + HandleWriteReceived(c1WriteEvent->BtConn, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_1_UUID, PacketBufferHandle::Adopt(c1WriteEvent->Data)); bt_conn_unref(c1WriteEvent->BtConn); @@ -532,7 +659,7 @@ CHIP_ERROR BLEManagerImpl::HandleTXCharComplete(const ChipDeviceEvent * event) bt_conn_index(c2IndDoneEvent->BtConn), c2IndDoneEvent->Result); // Signal the BLE Layer that the outstanding indication is complete. - HandleIndicationConfirmation(c2IndDoneEvent->BtConn, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); + HandleIndicationConfirmation(c2IndDoneEvent->BtConn, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); bt_conn_unref(c2IndDoneEvent->BtConn); return CHIP_NO_ERROR; @@ -570,12 +697,18 @@ CHIP_ERROR BLEManagerImpl::PrepareC3CharData() } #endif -void BLEManagerImpl::HandleBLEAdvertisementIntervalChange(System::Layer * layer, void * param) +void BLEManagerImpl::HandleSlowBLEAdvertisementInterval(System::Layer * layer, void * param) { BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising); ChipLogProgress(DeviceLayer, "CHIPoBLE advertising mode changed to slow"); } +void BLEManagerImpl::HandleExtendedBLEAdvertisementInterval(System::Layer * layer, void * param) +{ + BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kExtendedAdvertising); + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising mode changed to extended"); +} + void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -616,14 +749,13 @@ void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) uint16_t BLEManagerImpl::_NumConnections(void) { - return mGAPConns; + return mMatterConnNum; } CHIP_ERROR BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId) { ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (ConnId %02x)", bt_conn_index(conId)); - int status = bt_conn_disconnect(conId, BT_HCI_ERR_REMOTE_USER_TERM_CONN); - return (status == 0) ? CHIP_NO_ERROR : MapErrorZephyr(status); + return MapErrorZephyr(bt_conn_disconnect(conId, BT_HCI_ERR_REMOTE_USER_TERM_CONN)); } uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const @@ -662,7 +794,8 @@ CHIP_ERROR BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const Chi params->attr = &sChipoBleAttributes[kCHIPoBLE_CCC_AttributeIndex]; params->func = HandleTXIndicated; params->data = pBuf->Start(); - params->len = pBuf->DataLength(); + VerifyOrExit(CanCastTo(pBuf->DataLength()), err = CHIP_ERROR_MESSAGE_TOO_LONG); + params->len = static_cast(pBuf->DataLength()); status = bt_gatt_indicate(conId, params); VerifyOrExit(status == 0, err = MapErrorZephyr(status)); @@ -775,9 +908,16 @@ void BLEManagerImpl::HandleTXIndicated(struct bt_conn * conId, bt_gatt_indicate_ void BLEManagerImpl::HandleConnect(struct bt_conn * conId, uint8_t err) { ChipDeviceEvent event; + bt_conn_info bt_info; PlatformMgr().LockChipStack(); + sInstance.mTotalConnNum++; + ChipLogProgress(DeviceLayer, "Current number of connections: %u/%u", sInstance.mTotalConnNum, CONFIG_BT_MAX_CONN); + + VerifyOrExit(bt_conn_get_info(conId, &bt_info) == 0, ); + // Drop all callbacks incoming for the role other than peripheral, required by the Matter accessory + VerifyOrExit(bt_info.role == BT_CONN_ROLE_PERIPHERAL, ); // Don't handle BLE connecting events when it is not related to CHIPoBLE VerifyOrExit(sInstance.mFlags.Has(Flags::kChipoBleGattServiceRegister), ); @@ -794,9 +934,20 @@ void BLEManagerImpl::HandleConnect(struct bt_conn * conId, uint8_t err) void BLEManagerImpl::HandleDisconnect(struct bt_conn * conId, uint8_t reason) { ChipDeviceEvent event; + bt_conn_info bt_info; PlatformMgr().LockChipStack(); + if (sInstance.mTotalConnNum > 0) + { + sInstance.mTotalConnNum--; + } + + ChipLogProgress(DeviceLayer, "Current number of connections: %u/%u", sInstance.mTotalConnNum, CONFIG_BT_MAX_CONN); + + VerifyOrExit(bt_conn_get_info(conId, &bt_info) == 0, ); + // Drop all callbacks incoming for the role other than peripheral, required by the Matter accessory + VerifyOrExit(bt_info.role == BT_CONN_ROLE_PERIPHERAL, ); // Don't handle BLE disconnecting events when it is not related to CHIPoBLE VerifyOrExit(sInstance.mFlags.Has(Flags::kChipoBleGattServiceRegister), ); @@ -821,8 +972,21 @@ ssize_t BLEManagerImpl::HandleC3Read(struct bt_conn * conId, const struct bt_gat return 0; } + // For BLE, the max payload size is limited to UINT16_MAX since the length + // field is 2 bytes long. So, the cast to uint16_t should be fine. return bt_gatt_attr_read(conId, attr, buf, len, offset, sInstance.c3CharDataBufferHandle->Start(), - sInstance.c3CharDataBufferHandle->DataLength()); + static_cast(sInstance.c3CharDataBufferHandle->DataLength())); +} +#endif + +#ifdef CONFIG_CHIP_CUSTOM_BLE_ADV_DATA +void BLEManagerImpl::SetCustomAdvertising(Span CustomAdvertising) +{ + mCustomAdvertising = CustomAdvertising; +} +void BLEManagerImpl::SetCustomScanResponse(Span CustomScanResponse) +{ + mCustomScanResponse = CustomScanResponse; } #endif diff --git a/src/platform/nxp/common/ble_zephyr/BLEManagerImpl.h b/src/platform/nxp/common/ble_zephyr/BLEManagerImpl.h index 4ae142b65cb6c0..db00009a938cea 100644 --- a/src/platform/nxp/common/ble_zephyr/BLEManagerImpl.h +++ b/src/platform/nxp/common/ble_zephyr/BLEManagerImpl.h @@ -92,12 +92,13 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla kAdvertisingRefreshNeeded = 0x0010, /**< The advertising state/configuration has changed, but the SoftDevice has yet to be updated. */ kChipoBleGattServiceRegister = 0x0020, /**< The system has currently CHIPoBLE GATT service registered. */ + kExtendedAdvertisingEnabled = 0x0040, /**< The application has enabled extended advertising. */ }; struct ServiceData; BitFlags mFlags; - uint16_t mGAPConns; + uint16_t mMatterConnNum; CHIPoBLEServiceMode mServiceMode; bool mSubscribedConns[CONFIG_BT_MAX_CONN]; bt_gatt_indicate_params mIndicateParams[CONFIG_BT_MAX_CONN]; @@ -106,6 +107,12 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING PacketBufferHandle c3CharDataBufferHandle; #endif + // The summarized number of Bluetooth LE connections related to the device (including these not related to Matter service). + uint16_t mTotalConnNum; +#ifdef CONFIG_CHIP_CUSTOM_BLE_ADV_DATA + Span mCustomAdvertising = {}; + Span mCustomScanResponse = {}; +#endif void DriveBLEState(void); CHIP_ERROR PrepareAdvertisingRequest(); @@ -123,6 +130,8 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla bool SetSubscribed(bt_conn * conn); bool UnsetSubscribed(bt_conn * conn); uint32_t GetAdvertisingInterval(); + CHIP_ERROR RegisterGattService(); + CHIP_ERROR UnregisterGattService(); static void DriveBLEState(intptr_t arg); @@ -130,7 +139,8 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla static void HandleTXIndicated(bt_conn * conn, bt_gatt_indicate_params * attr, uint8_t err); static void HandleConnect(bt_conn * conn, uint8_t err); static void HandleDisconnect(bt_conn * conn, uint8_t reason); - static void HandleBLEAdvertisementIntervalChange(System::Layer * layer, void * param); + static void HandleSlowBLEAdvertisementInterval(System::Layer * layer, void * param); + static void HandleExtendedBLEAdvertisementInterval(System::Layer * layer, void * param); // ===== Members for internal use by the following friends. @@ -148,6 +158,10 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING static ssize_t HandleC3Read(struct bt_conn * conn, const struct bt_gatt_attr * attr, void * buf, uint16_t len, uint16_t offset); #endif +#ifdef CONFIG_CHIP_CUSTOM_BLE_ADV_DATA + void SetCustomAdvertising(Span CustomAdvertising); + void SetCustomScanResponse(Span CustomScanResponse); +#endif }; /** diff --git a/third_party/nxp/nxp_matter_support b/third_party/nxp/nxp_matter_support index 7323d61dfc746a..2fff7067131f13 160000 --- a/third_party/nxp/nxp_matter_support +++ b/third_party/nxp/nxp_matter_support @@ -1 +1 @@ -Subproject commit 7323d61dfc746aff677cb40c17cfed9d43dd9c1d +Subproject commit 2fff7067131f130c560de9fa49f247022270ca55 From 293f65eb6bfcf7c8fd9ca1e52f38d99ce3fb9200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Tue, 17 Dec 2024 15:21:22 +0100 Subject: [PATCH 08/19] [Chef] Add heat pump device type (#36457) * Create rootnode_heatpump_87ivjRAECh.zap * Create rootnode_heatpump_87ivjRAECh.matter * Update matter_device_types.json Add HeatPump device type * Update rootnode_heatpump_87ivjRAECh.zap Add new lines * Update rootnode_heatpump_87ivjRAECh.matter Add new lines * Update rootnode_heatpump_87ivjRAECh.zap PowerSource Feature = WIRED * Update rootnode_heatpump_87ivjRAECh.matter * Update rootnode_heatpump_87ivjRAECh.zap Add Device Energy Management in EP1 * Add Device Energy Management in EP1 * Add Diagnostic Logs to fix CI error * Update rootnode_heatpump_87ivjRAECh.matter cluster DiagnosticLogs * Enable TagList in EP1 * Add tagList in EP1 --- .../rootnode_heatpump_87ivjRAECh.matter | 2759 +++++++++++ .../devices/rootnode_heatpump_87ivjRAECh.zap | 4387 +++++++++++++++++ .../sample_app_util/matter_device_types.json | 3 +- 3 files changed, 7148 insertions(+), 1 deletion(-) create mode 100644 examples/chef/devices/rootnode_heatpump_87ivjRAECh.matter create mode 100644 examples/chef/devices/rootnode_heatpump_87ivjRAECh.zap diff --git a/examples/chef/devices/rootnode_heatpump_87ivjRAECh.matter b/examples/chef/devices/rootnode_heatpump_87ivjRAECh.matter new file mode 100644 index 00000000000000..87ff9a38821291 --- /dev/null +++ b/examples/chef/devices/rootnode_heatpump_87ivjRAECh.matter @@ -0,0 +1,2759 @@ +// This IDL was generated automatically by ZAP. +// It is for view/code review purposes only. + +enum AreaTypeTag : enum8 { + kAisle = 0; + kAttic = 1; + kBackDoor = 2; + kBackYard = 3; + kBalcony = 4; + kBallroom = 5; + kBathroom = 6; + kBedroom = 7; + kBorder = 8; + kBoxroom = 9; + kBreakfastRoom = 10; + kCarport = 11; + kCellar = 12; + kCloakroom = 13; + kCloset = 14; + kConservatory = 15; + kCorridor = 16; + kCraftRoom = 17; + kCupboard = 18; + kDeck = 19; + kDen = 20; + kDining = 21; + kDrawingRoom = 22; + kDressingRoom = 23; + kDriveway = 24; + kElevator = 25; + kEnsuite = 26; + kEntrance = 27; + kEntryway = 28; + kFamilyRoom = 29; + kFoyer = 30; + kFrontDoor = 31; + kFrontYard = 32; + kGameRoom = 33; + kGarage = 34; + kGarageDoor = 35; + kGarden = 36; + kGardenDoor = 37; + kGuestBathroom = 38; + kGuestBedroom = 39; + kGuestRestroom = 40; + kGuestRoom = 41; + kGym = 42; + kHallway = 43; + kHearthRoom = 44; + kKidsRoom = 45; + kKidsBedroom = 46; + kKitchen = 47; + kLarder = 48; + kLaundryRoom = 49; + kLawn = 50; + kLibrary = 51; + kLivingRoom = 52; + kLounge = 53; + kMediaTVRoom = 54; + kMudRoom = 55; + kMusicRoom = 56; + kNursery = 57; + kOffice = 58; + kOutdoorKitchen = 59; + kOutside = 60; + kPantry = 61; + kParkingLot = 62; + kParlor = 63; + kPatio = 64; + kPlayRoom = 65; + kPoolRoom = 66; + kPorch = 67; + kPrimaryBathroom = 68; + kPrimaryBedroom = 69; + kRamp = 70; + kReceptionRoom = 71; + kRecreationRoom = 72; + kRestroom = 73; + kRoof = 74; + kSauna = 75; + kScullery = 76; + kSewingRoom = 77; + kShed = 78; + kSideDoor = 79; + kSideYard = 80; + kSittingRoom = 81; + kSnug = 82; + kSpa = 83; + kStaircase = 84; + kSteamRoom = 85; + kStorageRoom = 86; + kStudio = 87; + kStudy = 88; + kSunRoom = 89; + kSwimmingPool = 90; + kTerrace = 91; + kUtilityRoom = 92; + kWard = 93; + kWorkshop = 94; +} + +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + +enum FloorSurfaceTag : enum8 { + kCarpet = 0; + kCeramic = 1; + kConcrete = 2; + kCork = 3; + kDeepCarpet = 4; + kDirt = 5; + kEngineeredWood = 6; + kGlass = 7; + kGrass = 8; + kHardwood = 9; + kLaminate = 10; + kLinoleum = 11; + kMat = 12; + kMetal = 13; + kPlastic = 14; + kPolishedConcrete = 15; + kRubber = 16; + kRug = 17; + kSand = 18; + kStone = 19; + kTatami = 20; + kTerrazzo = 21; + kTile = 22; + kVinyl = 23; +} + +enum LandmarkTag : enum8 { + kAirConditioner = 0; + kAirPurifier = 1; + kBackDoor = 2; + kBarStool = 3; + kBathMat = 4; + kBathtub = 5; + kBed = 6; + kBookshelf = 7; + kChair = 8; + kChristmasTree = 9; + kCoatRack = 10; + kCoffeeTable = 11; + kCookingRange = 12; + kCouch = 13; + kCountertop = 14; + kCradle = 15; + kCrib = 16; + kDesk = 17; + kDiningTable = 18; + kDishwasher = 19; + kDoor = 20; + kDresser = 21; + kLaundryDryer = 22; + kFan = 23; + kFireplace = 24; + kFreezer = 25; + kFrontDoor = 26; + kHighChair = 27; + kKitchenIsland = 28; + kLamp = 29; + kLitterBox = 30; + kMirror = 31; + kNightstand = 32; + kOven = 33; + kPetBed = 34; + kPetBowl = 35; + kPetCrate = 36; + kRefrigerator = 37; + kScratchingPost = 38; + kShoeRack = 39; + kShower = 40; + kSideDoor = 41; + kSink = 42; + kSofa = 43; + kStove = 44; + kTable = 45; + kToilet = 46; + kTrashCan = 47; + kLaundryWasher = 48; + kWindow = 49; + kWineCooler = 50; +} + +enum PositionTag : enum8 { + kLeft = 0; + kRight = 1; + kTop = 2; + kBottom = 3; + kMiddle = 4; + kRow = 5; + kColumn = 6; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; +} + +enum TestGlobalEnum : enum8 { + kSomeValue = 0; + kSomeOtherValue = 1; + kFinalValue = 2; +} + +enum ThreeLevelAutoEnum : enum8 { + kLow = 0; + kMedium = 1; + kHigh = 2; + kAutomatic = 3; +} + +bitmap TestGlobalBitmap : bitmap32 { + kFirstBit = 0x1; + kSecondBit = 0x2; +} + +struct TestGlobalStruct { + char_string<128> name = 0; + nullable TestGlobalBitmap myBitmap = 1; + optional nullable TestGlobalEnum myEnum = 2; +} + +struct LocationDescriptorStruct { + char_string<128> locationName = 0; + nullable int16s floorNumber = 1; + nullable AreaTypeTag areaType = 2; +} + +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + +/** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ +cluster Identify = 3 { + revision 4; + + enum EffectIdentifierEnum : enum8 { + kBlink = 0; + kBreathe = 1; + kOkay = 2; + kChannelChange = 11; + kFinishEffect = 254; + kStopEffect = 255; + } + + enum EffectVariantEnum : enum8 { + kDefault = 0; + } + + enum IdentifyTypeEnum : enum8 { + kNone = 0; + kLightOutput = 1; + kVisibleIndicator = 2; + kAudibleBeep = 3; + kDisplay = 4; + kActuator = 5; + } + + attribute int16u identifyTime = 0; + readonly attribute IdentifyTypeEnum identifyType = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct IdentifyRequest { + int16u identifyTime = 0; + } + + request struct TriggerEffectRequest { + EffectIdentifierEnum effectIdentifier = 0; + EffectVariantEnum effectVariant = 1; + } + + /** Command description for Identify */ + command access(invoke: manage) Identify(IdentifyRequest): DefaultSuccess = 0; + /** Command description for TriggerEffect */ + command access(invoke: manage) TriggerEffect(TriggerEffectRequest): DefaultSuccess = 64; +} + +/** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */ +cluster Descriptor = 29 { + revision 2; + + bitmap Feature : bitmap32 { + kTagList = 0x1; + } + + struct DeviceTypeStruct { + devtype_id deviceType = 0; + int16u revision = 1; + } + + struct SemanticTagStruct { + nullable vendor_id mfgCode = 0; + enum8 namespaceID = 1; + enum8 tag = 2; + optional nullable char_string label = 3; + } + + readonly attribute DeviceTypeStruct deviceTypeList[] = 0; + readonly attribute cluster_id serverList[] = 1; + readonly attribute cluster_id clientList[] = 2; + readonly attribute endpoint_no partsList[] = 3; + readonly attribute optional SemanticTagStruct tagList[] = 4; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** The Access Control Cluster exposes a data model view of a + Node's Access Control List (ACL), which codifies the rules used to manage + and enforce Access Control for the Node's endpoints and their associated + cluster instances. */ +cluster AccessControl = 31 { + revision 2; + + enum AccessControlEntryAuthModeEnum : enum8 { + kPASE = 1; + kCASE = 2; + kGroup = 3; + } + + enum AccessControlEntryPrivilegeEnum : enum8 { + kView = 1; + kProxyView = 2; + kOperate = 3; + kManage = 4; + kAdminister = 5; + } + + enum AccessRestrictionTypeEnum : enum8 { + kAttributeAccessForbidden = 0; + kAttributeWriteForbidden = 1; + kCommandForbidden = 2; + kEventForbidden = 3; + } + + enum ChangeTypeEnum : enum8 { + kChanged = 0; + kAdded = 1; + kRemoved = 2; + } + + bitmap Feature : bitmap32 { + kExtension = 0x1; + kManagedDevice = 0x2; + } + + struct AccessRestrictionStruct { + AccessRestrictionTypeEnum type = 0; + nullable int32u id = 1; + } + + struct CommissioningAccessRestrictionEntryStruct { + endpoint_no endpoint = 0; + cluster_id cluster = 1; + AccessRestrictionStruct restrictions[] = 2; + } + + fabric_scoped struct AccessRestrictionEntryStruct { + fabric_sensitive endpoint_no endpoint = 0; + fabric_sensitive cluster_id cluster = 1; + fabric_sensitive AccessRestrictionStruct restrictions[] = 2; + fabric_idx fabricIndex = 254; + } + + struct AccessControlTargetStruct { + nullable cluster_id cluster = 0; + nullable endpoint_no endpoint = 1; + nullable devtype_id deviceType = 2; + } + + fabric_scoped struct AccessControlEntryStruct { + fabric_sensitive AccessControlEntryPrivilegeEnum privilege = 1; + fabric_sensitive AccessControlEntryAuthModeEnum authMode = 2; + nullable fabric_sensitive int64u subjects[] = 3; + nullable fabric_sensitive AccessControlTargetStruct targets[] = 4; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct AccessControlExtensionStruct { + fabric_sensitive octet_string<128> data = 1; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) AccessControlEntryChanged = 0 { + nullable node_id adminNodeID = 1; + nullable int16u adminPasscodeID = 2; + ChangeTypeEnum changeType = 3; + nullable AccessControlEntryStruct latestValue = 4; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) AccessControlExtensionChanged = 1 { + nullable node_id adminNodeID = 1; + nullable int16u adminPasscodeID = 2; + ChangeTypeEnum changeType = 3; + nullable AccessControlExtensionStruct latestValue = 4; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) FabricRestrictionReviewUpdate = 2 { + int64u token = 0; + optional long_char_string instruction = 1; + optional long_char_string ARLRequestFlowUrl = 2; + fabric_idx fabricIndex = 254; + } + + attribute access(read: administer, write: administer) AccessControlEntryStruct acl[] = 0; + attribute access(read: administer, write: administer) optional AccessControlExtensionStruct extension[] = 1; + readonly attribute int16u subjectsPerAccessControlEntry = 2; + readonly attribute int16u targetsPerAccessControlEntry = 3; + readonly attribute int16u accessControlEntriesPerFabric = 4; + readonly attribute optional CommissioningAccessRestrictionEntryStruct commissioningARL[] = 5; + readonly attribute optional AccessRestrictionEntryStruct arl[] = 6; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ReviewFabricRestrictionsRequest { + CommissioningAccessRestrictionEntryStruct arl[] = 0; + } + + response struct ReviewFabricRestrictionsResponse = 1 { + int64u token = 0; + } + + /** This command signals to the service associated with the device vendor that the fabric administrator would like a review of the current restrictions on the accessing fabric. */ + fabric command access(invoke: administer) ReviewFabricRestrictions(ReviewFabricRestrictionsRequest): ReviewFabricRestrictionsResponse = 0; +} + +/** This cluster provides attributes and events for determining basic information about Nodes, which supports both + Commissioning and operational determination of Node characteristics, such as Vendor ID, Product ID and serial number, + which apply to the whole Node. Also allows setting user device information such as location. */ +cluster BasicInformation = 40 { + revision 3; + + enum ColorEnum : enum8 { + kBlack = 0; + kNavy = 1; + kGreen = 2; + kTeal = 3; + kMaroon = 4; + kPurple = 5; + kOlive = 6; + kGray = 7; + kBlue = 8; + kLime = 9; + kAqua = 10; + kRed = 11; + kFuchsia = 12; + kYellow = 13; + kWhite = 14; + kNickel = 15; + kChrome = 16; + kBrass = 17; + kCopper = 18; + kSilver = 19; + kGold = 20; + } + + enum ProductFinishEnum : enum8 { + kOther = 0; + kMatte = 1; + kSatin = 2; + kPolished = 3; + kRugged = 4; + kFabric = 5; + } + + struct CapabilityMinimaStruct { + int16u caseSessionsPerFabric = 0; + int16u subscriptionsPerFabric = 1; + } + + struct ProductAppearanceStruct { + ProductFinishEnum finish = 0; + nullable ColorEnum primaryColor = 1; + } + + critical event StartUp = 0 { + int32u softwareVersion = 0; + } + + critical event ShutDown = 1 { + } + + info event Leave = 2 { + fabric_idx fabricIndex = 0; + } + + info event ReachableChanged = 3 { + boolean reachableNewValue = 0; + } + + readonly attribute int16u dataModelRevision = 0; + readonly attribute char_string<32> vendorName = 1; + readonly attribute vendor_id vendorID = 2; + readonly attribute char_string<32> productName = 3; + readonly attribute int16u productID = 4; + attribute access(write: manage) char_string<32> nodeLabel = 5; + attribute access(write: administer) char_string<2> location = 6; + readonly attribute int16u hardwareVersion = 7; + readonly attribute char_string<64> hardwareVersionString = 8; + readonly attribute int32u softwareVersion = 9; + readonly attribute char_string<64> softwareVersionString = 10; + readonly attribute optional char_string<16> manufacturingDate = 11; + readonly attribute optional char_string<32> partNumber = 12; + readonly attribute optional long_char_string<256> productURL = 13; + readonly attribute optional char_string<64> productLabel = 14; + readonly attribute optional char_string<32> serialNumber = 15; + attribute access(write: manage) optional boolean localConfigDisabled = 16; + readonly attribute optional boolean reachable = 17; + readonly attribute char_string<32> uniqueID = 18; + readonly attribute CapabilityMinimaStruct capabilityMinima = 19; + readonly attribute optional ProductAppearanceStruct productAppearance = 20; + readonly attribute int32u specificationVersion = 21; + readonly attribute int16u maxPathsPerInvoke = 22; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + command MfgSpecificPing(): DefaultSuccess = 0; +} + +/** Nodes should be expected to be deployed to any and all regions of the world. These global regions + may have differing common languages, units of measurements, and numerical formatting + standards. As such, Nodes that visually or audibly convey information need a mechanism by which + they can be configured to use a user’s preferred language, units, etc */ +cluster LocalizationConfiguration = 43 { + revision 1; // NOTE: Default/not specifically set + + attribute access(write: manage) char_string<35> activeLocale = 0; + readonly attribute char_string supportedLocales[] = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** This cluster is used to describe the configuration and capabilities of a physical power source that provides power to the Node. */ +cluster PowerSource = 47 { + revision 1; // NOTE: Default/not specifically set + + enum BatApprovedChemistryEnum : enum16 { + kUnspecified = 0; + kAlkaline = 1; + kLithiumCarbonFluoride = 2; + kLithiumChromiumOxide = 3; + kLithiumCopperOxide = 4; + kLithiumIronDisulfide = 5; + kLithiumManganeseDioxide = 6; + kLithiumThionylChloride = 7; + kMagnesium = 8; + kMercuryOxide = 9; + kNickelOxyhydride = 10; + kSilverOxide = 11; + kZincAir = 12; + kZincCarbon = 13; + kZincChloride = 14; + kZincManganeseDioxide = 15; + kLeadAcid = 16; + kLithiumCobaltOxide = 17; + kLithiumIon = 18; + kLithiumIonPolymer = 19; + kLithiumIronPhosphate = 20; + kLithiumSulfur = 21; + kLithiumTitanate = 22; + kNickelCadmium = 23; + kNickelHydrogen = 24; + kNickelIron = 25; + kNickelMetalHydride = 26; + kNickelZinc = 27; + kSilverZinc = 28; + kSodiumIon = 29; + kSodiumSulfur = 30; + kZincBromide = 31; + kZincCerium = 32; + } + + enum BatChargeFaultEnum : enum8 { + kUnspecified = 0; + kAmbientTooHot = 1; + kAmbientTooCold = 2; + kBatteryTooHot = 3; + kBatteryTooCold = 4; + kBatteryAbsent = 5; + kBatteryOverVoltage = 6; + kBatteryUnderVoltage = 7; + kChargerOverVoltage = 8; + kChargerUnderVoltage = 9; + kSafetyTimeout = 10; + } + + enum BatChargeLevelEnum : enum8 { + kOK = 0; + kWarning = 1; + kCritical = 2; + } + + enum BatChargeStateEnum : enum8 { + kUnknown = 0; + kIsCharging = 1; + kIsAtFullCharge = 2; + kIsNotCharging = 3; + } + + enum BatCommonDesignationEnum : enum16 { + kUnspecified = 0; + kAAA = 1; + kAA = 2; + kC = 3; + kD = 4; + k4v5 = 5; + k6v0 = 6; + k9v0 = 7; + k12AA = 8; + kAAAA = 9; + kA = 10; + kB = 11; + kF = 12; + kN = 13; + kNo6 = 14; + kSubC = 15; + kA23 = 16; + kA27 = 17; + kBA5800 = 18; + kDuplex = 19; + k4SR44 = 20; + k523 = 21; + k531 = 22; + k15v0 = 23; + k22v5 = 24; + k30v0 = 25; + k45v0 = 26; + k67v5 = 27; + kJ = 28; + kCR123A = 29; + kCR2 = 30; + k2CR5 = 31; + kCRP2 = 32; + kCRV3 = 33; + kSR41 = 34; + kSR43 = 35; + kSR44 = 36; + kSR45 = 37; + kSR48 = 38; + kSR54 = 39; + kSR55 = 40; + kSR57 = 41; + kSR58 = 42; + kSR59 = 43; + kSR60 = 44; + kSR63 = 45; + kSR64 = 46; + kSR65 = 47; + kSR66 = 48; + kSR67 = 49; + kSR68 = 50; + kSR69 = 51; + kSR516 = 52; + kSR731 = 53; + kSR712 = 54; + kLR932 = 55; + kA5 = 56; + kA10 = 57; + kA13 = 58; + kA312 = 59; + kA675 = 60; + kAC41E = 61; + k10180 = 62; + k10280 = 63; + k10440 = 64; + k14250 = 65; + k14430 = 66; + k14500 = 67; + k14650 = 68; + k15270 = 69; + k16340 = 70; + kRCR123A = 71; + k17500 = 72; + k17670 = 73; + k18350 = 74; + k18500 = 75; + k18650 = 76; + k19670 = 77; + k25500 = 78; + k26650 = 79; + k32600 = 80; + } + + enum BatFaultEnum : enum8 { + kUnspecified = 0; + kOverTemp = 1; + kUnderTemp = 2; + } + + enum BatReplaceabilityEnum : enum8 { + kUnspecified = 0; + kNotReplaceable = 1; + kUserReplaceable = 2; + kFactoryReplaceable = 3; + } + + enum PowerSourceStatusEnum : enum8 { + kUnspecified = 0; + kActive = 1; + kStandby = 2; + kUnavailable = 3; + } + + enum WiredCurrentTypeEnum : enum8 { + kAC = 0; + kDC = 1; + } + + enum WiredFaultEnum : enum8 { + kUnspecified = 0; + kOverVoltage = 1; + kUnderVoltage = 2; + } + + bitmap Feature : bitmap32 { + kWired = 0x1; + kBattery = 0x2; + kRechargeable = 0x4; + kReplaceable = 0x8; + } + + struct BatChargeFaultChangeType { + BatChargeFaultEnum current[] = 0; + BatChargeFaultEnum previous[] = 1; + } + + struct BatFaultChangeType { + BatFaultEnum current[] = 0; + BatFaultEnum previous[] = 1; + } + + struct WiredFaultChangeType { + WiredFaultEnum current[] = 0; + WiredFaultEnum previous[] = 1; + } + + info event WiredFaultChange = 0 { + WiredFaultEnum current[] = 0; + WiredFaultEnum previous[] = 1; + } + + info event BatFaultChange = 1 { + BatFaultEnum current[] = 0; + BatFaultEnum previous[] = 1; + } + + info event BatChargeFaultChange = 2 { + BatChargeFaultEnum current[] = 0; + BatChargeFaultEnum previous[] = 1; + } + + readonly attribute PowerSourceStatusEnum status = 0; + readonly attribute int8u order = 1; + readonly attribute char_string<60> description = 2; + readonly attribute optional nullable int32u wiredAssessedInputVoltage = 3; + readonly attribute optional nullable int16u wiredAssessedInputFrequency = 4; + readonly attribute optional WiredCurrentTypeEnum wiredCurrentType = 5; + readonly attribute optional nullable int32u wiredAssessedCurrent = 6; + readonly attribute optional int32u wiredNominalVoltage = 7; + readonly attribute optional int32u wiredMaximumCurrent = 8; + readonly attribute optional boolean wiredPresent = 9; + readonly attribute optional WiredFaultEnum activeWiredFaults[] = 10; + readonly attribute optional nullable int32u batVoltage = 11; + readonly attribute optional nullable int8u batPercentRemaining = 12; + readonly attribute optional nullable int32u batTimeRemaining = 13; + readonly attribute optional BatChargeLevelEnum batChargeLevel = 14; + readonly attribute optional boolean batReplacementNeeded = 15; + readonly attribute optional BatReplaceabilityEnum batReplaceability = 16; + readonly attribute optional boolean batPresent = 17; + readonly attribute optional BatFaultEnum activeBatFaults[] = 18; + readonly attribute optional char_string<60> batReplacementDescription = 19; + readonly attribute optional BatCommonDesignationEnum batCommonDesignation = 20; + readonly attribute optional char_string<20> batANSIDesignation = 21; + readonly attribute optional char_string<20> batIECDesignation = 22; + readonly attribute optional BatApprovedChemistryEnum batApprovedChemistry = 23; + readonly attribute optional int32u batCapacity = 24; + readonly attribute optional int8u batQuantity = 25; + readonly attribute optional BatChargeStateEnum batChargeState = 26; + readonly attribute optional nullable int32u batTimeToFullCharge = 27; + readonly attribute optional boolean batFunctionalWhileCharging = 28; + readonly attribute optional nullable int32u batChargingCurrent = 29; + readonly attribute optional BatChargeFaultEnum activeBatChargeFaults[] = 30; + readonly attribute endpoint_no endpointList[] = 31; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** This cluster is used to manage global aspects of the Commissioning flow. */ +cluster GeneralCommissioning = 48 { + revision 1; // NOTE: Default/not specifically set + + enum CommissioningErrorEnum : enum8 { + kOK = 0; + kValueOutsideRange = 1; + kInvalidAuthentication = 2; + kNoFailSafe = 3; + kBusyWithOtherAdmin = 4; + kRequiredTCNotAccepted = 5; + kTCAcknowledgementsNotReceived = 6; + kTCMinVersionNotMet = 7; + } + + enum RegulatoryLocationTypeEnum : enum8 { + kIndoor = 0; + kOutdoor = 1; + kIndoorOutdoor = 2; + } + + bitmap Feature : bitmap32 { + kTermsAndConditions = 0x1; + } + + struct BasicCommissioningInfo { + int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; + } + + attribute access(write: administer) int64u breadcrumb = 0; + readonly attribute BasicCommissioningInfo basicCommissioningInfo = 1; + readonly attribute RegulatoryLocationTypeEnum regulatoryConfig = 2; + readonly attribute RegulatoryLocationTypeEnum locationCapability = 3; + readonly attribute boolean supportsConcurrentConnection = 4; + provisional readonly attribute access(read: administer) optional int16u TCAcceptedVersion = 5; + provisional readonly attribute access(read: administer) optional int16u TCMinRequiredVersion = 6; + provisional readonly attribute access(read: administer) optional bitmap16 TCAcknowledgements = 7; + provisional readonly attribute access(read: administer) optional boolean TCAcknowledgementsRequired = 8; + provisional readonly attribute access(read: administer) optional int32u TCUpdateDeadline = 9; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ArmFailSafeRequest { + int16u expiryLengthSeconds = 0; + int64u breadcrumb = 1; + } + + response struct ArmFailSafeResponse = 1 { + CommissioningErrorEnum errorCode = 0; + char_string<128> debugText = 1; + } + + request struct SetRegulatoryConfigRequest { + RegulatoryLocationTypeEnum newRegulatoryConfig = 0; + char_string<2> countryCode = 1; + int64u breadcrumb = 2; + } + + response struct SetRegulatoryConfigResponse = 3 { + CommissioningErrorEnum errorCode = 0; + char_string debugText = 1; + } + + response struct CommissioningCompleteResponse = 5 { + CommissioningErrorEnum errorCode = 0; + char_string debugText = 1; + } + + request struct SetTCAcknowledgementsRequest { + int16u TCVersion = 0; + bitmap16 TCUserResponse = 1; + } + + response struct SetTCAcknowledgementsResponse = 7 { + CommissioningErrorEnum errorCode = 0; + } + + /** Arm the persistent fail-safe timer with an expiry time of now + ExpiryLengthSeconds using device clock */ + command access(invoke: administer) ArmFailSafe(ArmFailSafeRequest): ArmFailSafeResponse = 0; + /** Set the regulatory configuration to be used during commissioning */ + command access(invoke: administer) SetRegulatoryConfig(SetRegulatoryConfigRequest): SetRegulatoryConfigResponse = 2; + /** Signals the Server that the Client has successfully completed all steps of Commissioning/Recofiguration needed during fail-safe period. */ + fabric command access(invoke: administer) CommissioningComplete(): CommissioningCompleteResponse = 4; + /** This command sets the user acknowledgements received in the Enhanced Setup Flow Terms and Conditions into the node. */ + command access(invoke: administer) SetTCAcknowledgements(SetTCAcknowledgementsRequest): SetTCAcknowledgementsResponse = 6; +} + +/** Functionality to configure, enable, disable network credentials and access on a Matter device. */ +cluster NetworkCommissioning = 49 { + revision 1; // NOTE: Default/not specifically set + + enum NetworkCommissioningStatusEnum : enum8 { + kSuccess = 0; + kOutOfRange = 1; + kBoundsExceeded = 2; + kNetworkIDNotFound = 3; + kDuplicateNetworkID = 4; + kNetworkNotFound = 5; + kRegulatoryError = 6; + kAuthFailure = 7; + kUnsupportedSecurity = 8; + kOtherConnectionFailure = 9; + kIPV6Failed = 10; + kIPBindFailed = 11; + kUnknownError = 12; + } + + enum WiFiBandEnum : enum8 { + k2G4 = 0; + k3G65 = 1; + k5G = 2; + k6G = 3; + k60G = 4; + k1G = 5; + } + + bitmap Feature : bitmap32 { + kWiFiNetworkInterface = 0x1; + kThreadNetworkInterface = 0x2; + kEthernetNetworkInterface = 0x4; + kPerDeviceCredentials = 0x8; + } + + bitmap ThreadCapabilitiesBitmap : bitmap16 { + kIsBorderRouterCapable = 0x1; + kIsRouterCapable = 0x2; + kIsSleepyEndDeviceCapable = 0x4; + kIsFullThreadDevice = 0x8; + kIsSynchronizedSleepyEndDeviceCapable = 0x10; + } + + bitmap WiFiSecurityBitmap : bitmap8 { + kUnencrypted = 0x1; + kWEP = 0x2; + kWPAPersonal = 0x4; + kWPA2Personal = 0x8; + kWPA3Personal = 0x10; + kWPA3MatterPDC = 0x20; + } + + struct NetworkInfoStruct { + octet_string<32> networkID = 0; + boolean connected = 1; + optional nullable octet_string<20> networkIdentifier = 2; + optional nullable octet_string<20> clientIdentifier = 3; + } + + struct ThreadInterfaceScanResultStruct { + int16u panId = 0; + int64u extendedPanId = 1; + char_string<16> networkName = 2; + int16u channel = 3; + int8u version = 4; + octet_string<8> extendedAddress = 5; + int8s rssi = 6; + int8u lqi = 7; + } + + struct WiFiInterfaceScanResultStruct { + WiFiSecurityBitmap security = 0; + octet_string<32> ssid = 1; + octet_string<6> bssid = 2; + int16u channel = 3; + WiFiBandEnum wiFiBand = 4; + int8s rssi = 5; + } + + readonly attribute access(read: administer) int8u maxNetworks = 0; + readonly attribute access(read: administer) NetworkInfoStruct networks[] = 1; + readonly attribute optional int8u scanMaxTimeSeconds = 2; + readonly attribute optional int8u connectMaxTimeSeconds = 3; + attribute access(write: administer) boolean interfaceEnabled = 4; + readonly attribute access(read: administer) nullable NetworkCommissioningStatusEnum lastNetworkingStatus = 5; + readonly attribute access(read: administer) nullable octet_string<32> lastNetworkID = 6; + readonly attribute access(read: administer) nullable int32s lastConnectErrorValue = 7; + provisional readonly attribute optional WiFiBandEnum supportedWiFiBands[] = 8; + provisional readonly attribute optional ThreadCapabilitiesBitmap supportedThreadFeatures = 9; + provisional readonly attribute optional int16u threadVersion = 10; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ScanNetworksRequest { + optional nullable octet_string<32> ssid = 0; + optional int64u breadcrumb = 1; + } + + response struct ScanNetworksResponse = 1 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string debugText = 1; + optional WiFiInterfaceScanResultStruct wiFiScanResults[] = 2; + optional ThreadInterfaceScanResultStruct threadScanResults[] = 3; + } + + request struct AddOrUpdateWiFiNetworkRequest { + octet_string<32> ssid = 0; + octet_string<64> credentials = 1; + optional int64u breadcrumb = 2; + optional octet_string<140> networkIdentity = 3; + optional octet_string<20> clientIdentifier = 4; + optional octet_string<32> possessionNonce = 5; + } + + request struct AddOrUpdateThreadNetworkRequest { + octet_string<254> operationalDataset = 0; + optional int64u breadcrumb = 1; + } + + request struct RemoveNetworkRequest { + octet_string<32> networkID = 0; + optional int64u breadcrumb = 1; + } + + response struct NetworkConfigResponse = 5 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string<512> debugText = 1; + optional int8u networkIndex = 2; + optional octet_string<140> clientIdentity = 3; + optional octet_string<64> possessionSignature = 4; + } + + request struct ConnectNetworkRequest { + octet_string<32> networkID = 0; + optional int64u breadcrumb = 1; + } + + response struct ConnectNetworkResponse = 7 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string debugText = 1; + nullable int32s errorValue = 2; + } + + request struct ReorderNetworkRequest { + octet_string<32> networkID = 0; + int8u networkIndex = 1; + optional int64u breadcrumb = 2; + } + + request struct QueryIdentityRequest { + octet_string<20> keyIdentifier = 0; + optional octet_string<32> possessionNonce = 1; + } + + response struct QueryIdentityResponse = 10 { + octet_string<140> identity = 0; + optional octet_string<64> possessionSignature = 1; + } + + /** Detemine the set of networks the device sees as available. */ + command access(invoke: administer) ScanNetworks(ScanNetworksRequest): ScanNetworksResponse = 0; + /** Add or update the credentials for a given Wi-Fi network. */ + command access(invoke: administer) AddOrUpdateWiFiNetwork(AddOrUpdateWiFiNetworkRequest): NetworkConfigResponse = 2; + /** Add or update the credentials for a given Thread network. */ + command access(invoke: administer) AddOrUpdateThreadNetwork(AddOrUpdateThreadNetworkRequest): NetworkConfigResponse = 3; + /** Remove the definition of a given network (including its credentials). */ + command access(invoke: administer) RemoveNetwork(RemoveNetworkRequest): NetworkConfigResponse = 4; + /** Connect to the specified network, using previously-defined credentials. */ + command access(invoke: administer) ConnectNetwork(ConnectNetworkRequest): ConnectNetworkResponse = 6; + /** Modify the order in which networks will be presented in the Networks attribute. */ + command access(invoke: administer) ReorderNetwork(ReorderNetworkRequest): NetworkConfigResponse = 8; + /** Retrieve details about and optionally proof of possession of a network client identity. */ + command access(invoke: administer) QueryIdentity(QueryIdentityRequest): QueryIdentityResponse = 9; +} + +/** The cluster provides commands for retrieving unstructured diagnostic logs from a Node that may be used to aid in diagnostics. */ +cluster DiagnosticLogs = 50 { + revision 1; // NOTE: Default/not specifically set + + enum IntentEnum : enum8 { + kEndUserSupport = 0; + kNetworkDiag = 1; + kCrashLogs = 2; + } + + enum StatusEnum : enum8 { + kSuccess = 0; + kExhausted = 1; + kNoLogs = 2; + kBusy = 3; + kDenied = 4; + } + + enum TransferProtocolEnum : enum8 { + kResponsePayload = 0; + kBDX = 1; + } + + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct RetrieveLogsRequestRequest { + IntentEnum intent = 0; + TransferProtocolEnum requestedProtocol = 1; + optional char_string<32> transferFileDesignator = 2; + } + + response struct RetrieveLogsResponse = 1 { + StatusEnum status = 0; + long_octet_string logContent = 1; + optional epoch_us UTCTimeStamp = 2; + optional systime_us timeSinceBoot = 3; + } + + /** Retrieving diagnostic logs from a Node */ + command RetrieveLogsRequest(RetrieveLogsRequestRequest): RetrieveLogsResponse = 0; +} + +/** The General Diagnostics Cluster, along with other diagnostics clusters, provide a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ +cluster GeneralDiagnostics = 51 { + revision 2; + + enum BootReasonEnum : enum8 { + kUnspecified = 0; + kPowerOnReboot = 1; + kBrownOutReset = 2; + kSoftwareWatchdogReset = 3; + kHardwareWatchdogReset = 4; + kSoftwareUpdateCompleted = 5; + kSoftwareReset = 6; + } + + enum HardwareFaultEnum : enum8 { + kUnspecified = 0; + kRadio = 1; + kSensor = 2; + kResettableOverTemp = 3; + kNonResettableOverTemp = 4; + kPowerSource = 5; + kVisualDisplayFault = 6; + kAudioOutputFault = 7; + kUserInterfaceFault = 8; + kNonVolatileMemoryError = 9; + kTamperDetected = 10; + } + + enum InterfaceTypeEnum : enum8 { + kUnspecified = 0; + kWiFi = 1; + kEthernet = 2; + kCellular = 3; + kThread = 4; + } + + enum NetworkFaultEnum : enum8 { + kUnspecified = 0; + kHardwareFailure = 1; + kNetworkJammed = 2; + kConnectionFailed = 3; + } + + enum RadioFaultEnum : enum8 { + kUnspecified = 0; + kWiFiFault = 1; + kCellularFault = 2; + kThreadFault = 3; + kNFCFault = 4; + kBLEFault = 5; + kEthernetFault = 6; + } + + bitmap Feature : bitmap32 { + kDataModelTest = 0x1; + } + + struct NetworkInterface { + char_string<32> name = 0; + boolean isOperational = 1; + nullable boolean offPremiseServicesReachableIPv4 = 2; + nullable boolean offPremiseServicesReachableIPv6 = 3; + octet_string<8> hardwareAddress = 4; + octet_string IPv4Addresses[] = 5; + octet_string IPv6Addresses[] = 6; + InterfaceTypeEnum type = 7; + } + + critical event HardwareFaultChange = 0 { + HardwareFaultEnum current[] = 0; + HardwareFaultEnum previous[] = 1; + } + + critical event RadioFaultChange = 1 { + RadioFaultEnum current[] = 0; + RadioFaultEnum previous[] = 1; + } + + critical event NetworkFaultChange = 2 { + NetworkFaultEnum current[] = 0; + NetworkFaultEnum previous[] = 1; + } + + critical event BootReason = 3 { + BootReasonEnum bootReason = 0; + } + + readonly attribute NetworkInterface networkInterfaces[] = 0; + readonly attribute int16u rebootCount = 1; + readonly attribute optional int64u upTime = 2; + readonly attribute optional int32u totalOperationalHours = 3; + readonly attribute optional BootReasonEnum bootReason = 4; + readonly attribute optional HardwareFaultEnum activeHardwareFaults[] = 5; + readonly attribute optional RadioFaultEnum activeRadioFaults[] = 6; + readonly attribute optional NetworkFaultEnum activeNetworkFaults[] = 7; + readonly attribute boolean testEventTriggersEnabled = 8; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct TestEventTriggerRequest { + octet_string<16> enableKey = 0; + int64u eventTrigger = 1; + } + + response struct TimeSnapshotResponse = 2 { + systime_ms systemTimeMs = 0; + nullable posix_ms posixTimeMs = 1; + } + + request struct PayloadTestRequestRequest { + octet_string<16> enableKey = 0; + int8u value = 1; + int16u count = 2; + } + + response struct PayloadTestResponse = 4 { + octet_string payload = 0; + } + + /** Provide a means for certification tests to trigger some test-plan-specific events */ + command access(invoke: manage) TestEventTrigger(TestEventTriggerRequest): DefaultSuccess = 0; + /** Take a snapshot of system time and epoch time. */ + command TimeSnapshot(): TimeSnapshotResponse = 1; + /** Request a variable length payload response. */ + command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; +} + +/** Commands to trigger a Node to allow a new Administrator to commission it. */ +cluster AdministratorCommissioning = 60 { + revision 1; // NOTE: Default/not specifically set + + enum CommissioningWindowStatusEnum : enum8 { + kWindowNotOpen = 0; + kEnhancedWindowOpen = 1; + kBasicWindowOpen = 2; + } + + enum StatusCode : enum8 { + kBusy = 2; + kPAKEParameterError = 3; + kWindowNotOpen = 4; + } + + bitmap Feature : bitmap32 { + kBasic = 0x1; + } + + readonly attribute CommissioningWindowStatusEnum windowStatus = 0; + readonly attribute nullable fabric_idx adminFabricIndex = 1; + readonly attribute nullable vendor_id adminVendorId = 2; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct OpenCommissioningWindowRequest { + int16u commissioningTimeout = 0; + octet_string PAKEPasscodeVerifier = 1; + int16u discriminator = 2; + int32u iterations = 3; + octet_string<32> salt = 4; + } + + request struct OpenBasicCommissioningWindowRequest { + int16u commissioningTimeout = 0; + } + + /** This command is used by a current Administrator to instruct a Node to go into commissioning mode using enhanced commissioning method. */ + timed command access(invoke: administer) OpenCommissioningWindow(OpenCommissioningWindowRequest): DefaultSuccess = 0; + /** This command is used by a current Administrator to instruct a Node to go into commissioning mode using basic commissioning method, if the node supports it. */ + timed command access(invoke: administer) OpenBasicCommissioningWindow(OpenBasicCommissioningWindowRequest): DefaultSuccess = 1; + /** This command is used by a current Administrator to instruct a Node to revoke any active Open Commissioning Window or Open Basic Commissioning Window command. */ + timed command access(invoke: administer) RevokeCommissioning(): DefaultSuccess = 2; +} + +/** This cluster is used to add or remove Operational Credentials on a Commissionee or Node, as well as manage the associated Fabrics. */ +cluster OperationalCredentials = 62 { + revision 1; // NOTE: Default/not specifically set + + enum CertificateChainTypeEnum : enum8 { + kDACCertificate = 1; + kPAICertificate = 2; + } + + enum NodeOperationalCertStatusEnum : enum8 { + kOK = 0; + kInvalidPublicKey = 1; + kInvalidNodeOpId = 2; + kInvalidNOC = 3; + kMissingCsr = 4; + kTableFull = 5; + kInvalidAdminSubject = 6; + kFabricConflict = 9; + kLabelConflict = 10; + kInvalidFabricIndex = 11; + } + + fabric_scoped struct FabricDescriptorStruct { + octet_string<65> rootPublicKey = 1; + vendor_id vendorID = 2; + fabric_id fabricID = 3; + node_id nodeID = 4; + char_string<32> label = 5; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct NOCStruct { + fabric_sensitive octet_string noc = 1; + nullable fabric_sensitive octet_string icac = 2; + fabric_idx fabricIndex = 254; + } + + readonly attribute access(read: administer) NOCStruct NOCs[] = 0; + readonly attribute FabricDescriptorStruct fabrics[] = 1; + readonly attribute int8u supportedFabrics = 2; + readonly attribute int8u commissionedFabrics = 3; + readonly attribute octet_string trustedRootCertificates[] = 4; + readonly attribute int8u currentFabricIndex = 5; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AttestationRequestRequest { + octet_string<32> attestationNonce = 0; + } + + response struct AttestationResponse = 1 { + octet_string<900> attestationElements = 0; + octet_string<64> attestationSignature = 1; + } + + request struct CertificateChainRequestRequest { + CertificateChainTypeEnum certificateType = 0; + } + + response struct CertificateChainResponse = 3 { + octet_string<600> certificate = 0; + } + + request struct CSRRequestRequest { + octet_string<32> CSRNonce = 0; + optional boolean isForUpdateNOC = 1; + } + + response struct CSRResponse = 5 { + octet_string NOCSRElements = 0; + octet_string attestationSignature = 1; + } + + request struct AddNOCRequest { + octet_string<400> NOCValue = 0; + optional octet_string<400> ICACValue = 1; + octet_string<16> IPKValue = 2; + int64u caseAdminSubject = 3; + vendor_id adminVendorId = 4; + } + + request struct UpdateNOCRequest { + octet_string NOCValue = 0; + optional octet_string ICACValue = 1; + } + + response struct NOCResponse = 8 { + NodeOperationalCertStatusEnum statusCode = 0; + optional fabric_idx fabricIndex = 1; + optional char_string<128> debugText = 2; + } + + request struct UpdateFabricLabelRequest { + char_string<32> label = 0; + } + + request struct RemoveFabricRequest { + fabric_idx fabricIndex = 0; + } + + request struct AddTrustedRootCertificateRequest { + octet_string rootCACertificate = 0; + } + + /** Sender is requesting attestation information from the receiver. */ + command access(invoke: administer) AttestationRequest(AttestationRequestRequest): AttestationResponse = 0; + /** Sender is requesting a device attestation certificate from the receiver. */ + command access(invoke: administer) CertificateChainRequest(CertificateChainRequestRequest): CertificateChainResponse = 2; + /** Sender is requesting a certificate signing request (CSR) from the receiver. */ + command access(invoke: administer) CSRRequest(CSRRequestRequest): CSRResponse = 4; + /** Sender is requesting to add the new node operational certificates. */ + command access(invoke: administer) AddNOC(AddNOCRequest): NOCResponse = 6; + /** Sender is requesting to update the node operational certificates. */ + fabric command access(invoke: administer) UpdateNOC(UpdateNOCRequest): NOCResponse = 7; + /** This command SHALL be used by an Administrative Node to set the user-visible Label field for a given Fabric, as reflected by entries in the Fabrics attribute. */ + fabric command access(invoke: administer) UpdateFabricLabel(UpdateFabricLabelRequest): NOCResponse = 9; + /** This command is used by Administrative Nodes to remove a given fabric index and delete all associated fabric-scoped data. */ + command access(invoke: administer) RemoveFabric(RemoveFabricRequest): NOCResponse = 10; + /** This command SHALL add a Trusted Root CA Certificate, provided as its CHIP Certificate representation. */ + command access(invoke: administer) AddTrustedRootCertificate(AddTrustedRootCertificateRequest): DefaultSuccess = 11; +} + +/** The Group Key Management Cluster is the mechanism by which group keys are managed. */ +cluster GroupKeyManagement = 63 { + revision 1; // NOTE: Default/not specifically set + + enum GroupKeySecurityPolicyEnum : enum8 { + kTrustFirst = 0; + kCacheAndSync = 1; + } + + bitmap Feature : bitmap32 { + kCacheAndSync = 0x1; + } + + fabric_scoped struct GroupInfoMapStruct { + group_id groupId = 1; + endpoint_no endpoints[] = 2; + optional char_string<16> groupName = 3; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct GroupKeyMapStruct { + group_id groupId = 1; + int16u groupKeySetID = 2; + fabric_idx fabricIndex = 254; + } + + struct GroupKeySetStruct { + int16u groupKeySetID = 0; + GroupKeySecurityPolicyEnum groupKeySecurityPolicy = 1; + nullable octet_string<16> epochKey0 = 2; + nullable epoch_us epochStartTime0 = 3; + nullable octet_string<16> epochKey1 = 4; + nullable epoch_us epochStartTime1 = 5; + nullable octet_string<16> epochKey2 = 6; + nullable epoch_us epochStartTime2 = 7; + } + + attribute access(write: manage) GroupKeyMapStruct groupKeyMap[] = 0; + readonly attribute GroupInfoMapStruct groupTable[] = 1; + readonly attribute int16u maxGroupsPerFabric = 2; + readonly attribute int16u maxGroupKeysPerFabric = 3; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct KeySetWriteRequest { + GroupKeySetStruct groupKeySet = 0; + } + + request struct KeySetReadRequest { + int16u groupKeySetID = 0; + } + + response struct KeySetReadResponse = 2 { + GroupKeySetStruct groupKeySet = 0; + } + + request struct KeySetRemoveRequest { + int16u groupKeySetID = 0; + } + + response struct KeySetReadAllIndicesResponse = 5 { + int16u groupKeySetIDs[] = 0; + } + + /** Write a new set of keys for the given key set id. */ + fabric command access(invoke: administer) KeySetWrite(KeySetWriteRequest): DefaultSuccess = 0; + /** Read the keys for a given key set id. */ + fabric command access(invoke: administer) KeySetRead(KeySetReadRequest): KeySetReadResponse = 1; + /** Revoke a Root Key from a Group */ + fabric command access(invoke: administer) KeySetRemove(KeySetRemoveRequest): DefaultSuccess = 3; + /** Return the list of Group Key Sets associated with the accessing fabric */ + fabric command access(invoke: administer) KeySetReadAllIndices(): KeySetReadAllIndicesResponse = 4; +} + +/** This cluster provides a mechanism for querying data about electrical power as measured by the server. */ +cluster ElectricalPowerMeasurement = 144 { + revision 1; + + enum MeasurementTypeEnum : enum16 { + kUnspecified = 0; + kVoltage = 1; + kActiveCurrent = 2; + kReactiveCurrent = 3; + kApparentCurrent = 4; + kActivePower = 5; + kReactivePower = 6; + kApparentPower = 7; + kRMSVoltage = 8; + kRMSCurrent = 9; + kRMSPower = 10; + kFrequency = 11; + kPowerFactor = 12; + kNeutralCurrent = 13; + kElectricalEnergy = 14; + } + + enum PowerModeEnum : enum8 { + kUnknown = 0; + kDC = 1; + kAC = 2; + } + + bitmap Feature : bitmap32 { + kDirectCurrent = 0x1; + kAlternatingCurrent = 0x2; + kPolyphasePower = 0x4; + kHarmonics = 0x8; + kPowerQuality = 0x10; + } + + struct MeasurementAccuracyRangeStruct { + int64s rangeMin = 0; + int64s rangeMax = 1; + optional percent100ths percentMax = 2; + optional percent100ths percentMin = 3; + optional percent100ths percentTypical = 4; + optional int64u fixedMax = 5; + optional int64u fixedMin = 6; + optional int64u fixedTypical = 7; + } + + struct MeasurementAccuracyStruct { + MeasurementTypeEnum measurementType = 0; + boolean measured = 1; + int64s minMeasuredValue = 2; + int64s maxMeasuredValue = 3; + MeasurementAccuracyRangeStruct accuracyRanges[] = 4; + } + + struct HarmonicMeasurementStruct { + int8u order = 0; + nullable int64s measurement = 1; + } + + struct MeasurementRangeStruct { + MeasurementTypeEnum measurementType = 0; + int64s min = 1; + int64s max = 2; + optional epoch_s startTimestamp = 3; + optional epoch_s endTimestamp = 4; + optional epoch_s minTimestamp = 5; + optional epoch_s maxTimestamp = 6; + optional systime_ms startSystime = 7; + optional systime_ms endSystime = 8; + optional systime_ms minSystime = 9; + optional systime_ms maxSystime = 10; + } + + info event MeasurementPeriodRanges = 0 { + MeasurementRangeStruct ranges[] = 0; + } + + readonly attribute PowerModeEnum powerMode = 0; + readonly attribute int8u numberOfMeasurementTypes = 1; + readonly attribute MeasurementAccuracyStruct accuracy[] = 2; + readonly attribute optional MeasurementRangeStruct ranges[] = 3; + readonly attribute optional nullable voltage_mv voltage = 4; + readonly attribute optional nullable amperage_ma activeCurrent = 5; + readonly attribute optional nullable amperage_ma reactiveCurrent = 6; + readonly attribute optional nullable amperage_ma apparentCurrent = 7; + readonly attribute nullable power_mw activePower = 8; + readonly attribute optional nullable power_mw reactivePower = 9; + readonly attribute optional nullable power_mw apparentPower = 10; + readonly attribute optional nullable voltage_mv RMSVoltage = 11; + readonly attribute optional nullable amperage_ma RMSCurrent = 12; + readonly attribute optional nullable power_mw RMSPower = 13; + readonly attribute optional nullable int64s frequency = 14; + readonly attribute optional nullable HarmonicMeasurementStruct harmonicCurrents[] = 15; + readonly attribute optional nullable HarmonicMeasurementStruct harmonicPhases[] = 16; + readonly attribute optional nullable int64s powerFactor = 17; + readonly attribute optional nullable amperage_ma neutralCurrent = 18; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** This cluster provides a mechanism for querying data about the electrical energy imported or provided by the server. */ +cluster ElectricalEnergyMeasurement = 145 { + revision 1; + + enum MeasurementTypeEnum : enum16 { + kUnspecified = 0; + kVoltage = 1; + kActiveCurrent = 2; + kReactiveCurrent = 3; + kApparentCurrent = 4; + kActivePower = 5; + kReactivePower = 6; + kApparentPower = 7; + kRMSVoltage = 8; + kRMSCurrent = 9; + kRMSPower = 10; + kFrequency = 11; + kPowerFactor = 12; + kNeutralCurrent = 13; + kElectricalEnergy = 14; + } + + bitmap Feature : bitmap32 { + kImportedEnergy = 0x1; + kExportedEnergy = 0x2; + kCumulativeEnergy = 0x4; + kPeriodicEnergy = 0x8; + } + + struct MeasurementAccuracyRangeStruct { + int64s rangeMin = 0; + int64s rangeMax = 1; + optional percent100ths percentMax = 2; + optional percent100ths percentMin = 3; + optional percent100ths percentTypical = 4; + optional int64u fixedMax = 5; + optional int64u fixedMin = 6; + optional int64u fixedTypical = 7; + } + + struct MeasurementAccuracyStruct { + MeasurementTypeEnum measurementType = 0; + boolean measured = 1; + int64s minMeasuredValue = 2; + int64s maxMeasuredValue = 3; + MeasurementAccuracyRangeStruct accuracyRanges[] = 4; + } + + struct CumulativeEnergyResetStruct { + optional nullable epoch_s importedResetTimestamp = 0; + optional nullable epoch_s exportedResetTimestamp = 1; + optional nullable systime_ms importedResetSystime = 2; + optional nullable systime_ms exportedResetSystime = 3; + } + + struct EnergyMeasurementStruct { + energy_mwh energy = 0; + optional epoch_s startTimestamp = 1; + optional epoch_s endTimestamp = 2; + optional systime_ms startSystime = 3; + optional systime_ms endSystime = 4; + } + + info event CumulativeEnergyMeasured = 0 { + optional EnergyMeasurementStruct energyImported = 0; + optional EnergyMeasurementStruct energyExported = 1; + } + + info event PeriodicEnergyMeasured = 1 { + optional EnergyMeasurementStruct energyImported = 0; + optional EnergyMeasurementStruct energyExported = 1; + } + + readonly attribute MeasurementAccuracyStruct accuracy = 0; + readonly attribute optional nullable EnergyMeasurementStruct cumulativeEnergyImported = 1; + readonly attribute optional nullable EnergyMeasurementStruct cumulativeEnergyExported = 2; + readonly attribute optional nullable EnergyMeasurementStruct periodicEnergyImported = 3; + readonly attribute optional nullable EnergyMeasurementStruct periodicEnergyExported = 4; + readonly attribute optional nullable CumulativeEnergyResetStruct cumulativeEnergyReset = 5; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** This cluster allows a client to manage the power draw of a device. An example of such a client could be an Energy Management System (EMS) which controls an Energy Smart Appliance (ESA). */ +provisional cluster DeviceEnergyManagement = 152 { + revision 4; + + enum AdjustmentCauseEnum : enum8 { + kLocalOptimization = 0; + kGridOptimization = 1; + } + + enum CauseEnum : enum8 { + kNormalCompletion = 0; + kOffline = 1; + kFault = 2; + kUserOptOut = 3; + kCancelled = 4; + } + + enum CostTypeEnum : enum8 { + kFinancial = 0; + kGHGEmissions = 1; + kComfort = 2; + kTemperature = 3; + } + + enum ESAStateEnum : enum8 { + kOffline = 0; + kOnline = 1; + kFault = 2; + kPowerAdjustActive = 3; + kPaused = 4; + } + + enum ESATypeEnum : enum8 { + kEVSE = 0; + kSpaceHeating = 1; + kWaterHeating = 2; + kSpaceCooling = 3; + kSpaceHeatingCooling = 4; + kBatteryStorage = 5; + kSolarPV = 6; + kFridgeFreezer = 7; + kWashingMachine = 8; + kDishwasher = 9; + kCooking = 10; + kHomeWaterPump = 11; + kIrrigationWaterPump = 12; + kPoolPump = 13; + kOther = 255; + } + + enum ForecastUpdateReasonEnum : enum8 { + kInternalOptimization = 0; + kLocalOptimization = 1; + kGridOptimization = 2; + } + + enum OptOutStateEnum : enum8 { + kNoOptOut = 0; + kLocalOptOut = 1; + kGridOptOut = 2; + kOptOut = 3; + } + + enum PowerAdjustReasonEnum : enum8 { + kNoAdjustment = 0; + kLocalOptimizationAdjustment = 1; + kGridOptimizationAdjustment = 2; + } + + bitmap Feature : bitmap32 { + kPowerAdjustment = 0x1; + kPowerForecastReporting = 0x2; + kStateForecastReporting = 0x4; + kStartTimeAdjustment = 0x8; + kPausable = 0x10; + kForecastAdjustment = 0x20; + kConstraintBasedAdjustment = 0x40; + } + + struct CostStruct { + CostTypeEnum costType = 0; + int32s value = 1; + int8u decimalPoints = 2; + optional int16u currency = 3; + } + + struct PowerAdjustStruct { + power_mw minPower = 0; + power_mw maxPower = 1; + elapsed_s minDuration = 2; + elapsed_s maxDuration = 3; + } + + struct PowerAdjustCapabilityStruct { + nullable PowerAdjustStruct powerAdjustCapability[] = 0; + PowerAdjustReasonEnum cause = 1; + } + + struct SlotStruct { + elapsed_s minDuration = 0; + elapsed_s maxDuration = 1; + elapsed_s defaultDuration = 2; + elapsed_s elapsedSlotTime = 3; + elapsed_s remainingSlotTime = 4; + optional boolean slotIsPausable = 5; + optional elapsed_s minPauseDuration = 6; + optional elapsed_s maxPauseDuration = 7; + optional int16u manufacturerESAState = 8; + optional power_mw nominalPower = 9; + optional power_mw minPower = 10; + optional power_mw maxPower = 11; + optional energy_mwh nominalEnergy = 12; + optional CostStruct costs[] = 13; + optional power_mw minPowerAdjustment = 14; + optional power_mw maxPowerAdjustment = 15; + optional elapsed_s minDurationAdjustment = 16; + optional elapsed_s maxDurationAdjustment = 17; + } + + struct ForecastStruct { + int32u forecastID = 0; + nullable int16u activeSlotNumber = 1; + epoch_s startTime = 2; + epoch_s endTime = 3; + optional nullable epoch_s earliestStartTime = 4; + optional epoch_s latestEndTime = 5; + boolean isPausable = 6; + SlotStruct slots[] = 7; + ForecastUpdateReasonEnum forecastUpdateReason = 8; + } + + struct ConstraintsStruct { + epoch_s startTime = 0; + elapsed_s duration = 1; + optional power_mw nominalPower = 2; + optional energy_mwh maximumEnergy = 3; + optional int8s loadControl = 4; + } + + struct SlotAdjustmentStruct { + int8u slotIndex = 0; + optional power_mw nominalPower = 1; + elapsed_s duration = 2; + } + + info event PowerAdjustStart = 0 { + } + + info event PowerAdjustEnd = 1 { + CauseEnum cause = 0; + elapsed_s duration = 1; + energy_mwh energyUse = 2; + } + + info event Paused = 2 { + } + + info event Resumed = 3 { + CauseEnum cause = 0; + } + + readonly attribute ESATypeEnum ESAType = 0; + readonly attribute boolean ESACanGenerate = 1; + readonly attribute ESAStateEnum ESAState = 2; + readonly attribute power_mw absMinPower = 3; + readonly attribute power_mw absMaxPower = 4; + readonly attribute optional nullable PowerAdjustCapabilityStruct powerAdjustmentCapability = 5; + readonly attribute optional nullable ForecastStruct forecast = 6; + readonly attribute optional OptOutStateEnum optOutState = 7; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct PowerAdjustRequestRequest { + power_mw power = 0; + elapsed_s duration = 1; + AdjustmentCauseEnum cause = 2; + } + + request struct StartTimeAdjustRequestRequest { + epoch_s requestedStartTime = 0; + AdjustmentCauseEnum cause = 1; + } + + request struct PauseRequestRequest { + elapsed_s duration = 0; + AdjustmentCauseEnum cause = 1; + } + + request struct ModifyForecastRequestRequest { + int32u forecastID = 0; + SlotAdjustmentStruct slotAdjustments[] = 1; + AdjustmentCauseEnum cause = 2; + } + + request struct RequestConstraintBasedForecastRequest { + ConstraintsStruct constraints[] = 0; + AdjustmentCauseEnum cause = 1; + } + + /** Allows a client to request an adjustment in the power consumption of an ESA for a specified duration. */ + command PowerAdjustRequest(PowerAdjustRequestRequest): DefaultSuccess = 0; + /** Allows a client to cancel an ongoing PowerAdjustmentRequest operation. */ + command CancelPowerAdjustRequest(): DefaultSuccess = 1; + /** Allows a client to adjust the start time of a Forecast sequence that has not yet started operation (i.e. where the current Forecast StartTime is in the future). */ + command StartTimeAdjustRequest(StartTimeAdjustRequestRequest): DefaultSuccess = 2; + /** Allows a client to temporarily pause an operation and reduce the ESAs energy demand. */ + command PauseRequest(PauseRequestRequest): DefaultSuccess = 3; + /** Allows a client to cancel the PauseRequest command and enable earlier resumption of operation. */ + command ResumeRequest(): DefaultSuccess = 4; + /** Allows a client to modify a Forecast within the limits allowed by the ESA. */ + command ModifyForecastRequest(ModifyForecastRequestRequest): DefaultSuccess = 5; + /** Allows a client to ask the ESA to recompute its Forecast based on power and time constraints. */ + command RequestConstraintBasedForecast(RequestConstraintBasedForecastRequest): DefaultSuccess = 6; + /** Allows a client to request cancellation of a previous adjustment request in a StartTimeAdjustRequest, ModifyForecastRequest or RequestConstraintBasedForecast command. */ + command CancelRequest(): DefaultSuccess = 7; +} + +/** The Power Topology Cluster provides a mechanism for expressing how power is flowing between endpoints. */ +cluster PowerTopology = 156 { + revision 1; + + bitmap Feature : bitmap32 { + kNodeTopology = 0x1; + kTreeTopology = 0x2; + kSetTopology = 0x4; + kDynamicPowerFlow = 0x8; + } + + readonly attribute optional endpoint_no availableEndpoints[] = 0; + readonly attribute optional endpoint_no activeEndpoints[] = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** Attributes and commands for selecting a mode from a list of supported options. */ +provisional cluster DeviceEnergyManagementMode = 159 { + revision 2; + + enum ModeTag : enum16 { + kAuto = 0; + kQuick = 1; + kQuiet = 2; + kLowNoise = 3; + kLowEnergy = 4; + kVacation = 5; + kMin = 6; + kMax = 7; + kNight = 8; + kDay = 9; + kNoOptimization = 16384; + kDeviceOptimization = 16385; + kLocalOptimization = 16386; + kGridOptimization = 16387; + } + + bitmap Feature : bitmap32 { + kOnOff = 0x1; + } + + struct ModeTagStruct { + optional vendor_id mfgCode = 0; + enum16 value = 1; + } + + struct ModeOptionStruct { + char_string<64> label = 0; + int8u mode = 1; + ModeTagStruct modeTags[] = 2; + } + + readonly attribute ModeOptionStruct supportedModes[] = 0; + readonly attribute int8u currentMode = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ChangeToModeRequest { + int8u newMode = 0; + } + + response struct ChangeToModeResponse = 1 { + enum8 status = 0; + optional char_string<64> statusText = 1; + } + + /** This command is used to change device modes. */ + command ChangeToMode(ChangeToModeRequest): ChangeToModeResponse = 0; +} + +/** An interface for configuring and controlling the functionality of a thermostat. */ +cluster Thermostat = 513 { + revision 7; + + enum ACCapacityFormatEnum : enum8 { + kBTUh = 0; + } + + enum ACCompressorTypeEnum : enum8 { + kUnknown = 0; + kT1 = 1; + kT2 = 2; + kT3 = 3; + } + + enum ACLouverPositionEnum : enum8 { + kClosed = 1; + kOpen = 2; + kQuarter = 3; + kHalf = 4; + kThreeQuarters = 5; + } + + enum ACRefrigerantTypeEnum : enum8 { + kUnknown = 0; + kR22 = 1; + kR410a = 2; + kR407c = 3; + } + + enum ACTypeEnum : enum8 { + kUnknown = 0; + kCoolingFixed = 1; + kHeatPumpFixed = 2; + kCoolingInverter = 3; + kHeatPumpInverter = 4; + } + + enum ControlSequenceOfOperationEnum : enum8 { + kCoolingOnly = 0; + kCoolingWithReheat = 1; + kHeatingOnly = 2; + kHeatingWithReheat = 3; + kCoolingAndHeating = 4; + kCoolingAndHeatingWithReheat = 5; + } + + enum PresetScenarioEnum : enum8 { + kOccupied = 1; + kUnoccupied = 2; + kSleep = 3; + kWake = 4; + kVacation = 5; + kGoingToSleep = 6; + kUserDefined = 254; + } + + enum SetpointChangeSourceEnum : enum8 { + kManual = 0; + kSchedule = 1; + kExternal = 2; + } + + enum SetpointRaiseLowerModeEnum : enum8 { + kHeat = 0; + kCool = 1; + kBoth = 2; + } + + enum StartOfWeekEnum : enum8 { + kSunday = 0; + kMonday = 1; + kTuesday = 2; + kWednesday = 3; + kThursday = 4; + kFriday = 5; + kSaturday = 6; + } + + enum SystemModeEnum : enum8 { + kOff = 0; + kAuto = 1; + kCool = 3; + kHeat = 4; + kEmergencyHeat = 5; + kPrecooling = 6; + kFanOnly = 7; + kDry = 8; + kSleep = 9; + } + + enum TemperatureSetpointHoldEnum : enum8 { + kSetpointHoldOff = 0; + kSetpointHoldOn = 1; + } + + enum ThermostatRunningModeEnum : enum8 { + kOff = 0; + kCool = 3; + kHeat = 4; + } + + bitmap ACErrorCodeBitmap : bitmap32 { + kCompressorFail = 0x1; + kRoomSensorFail = 0x2; + kOutdoorSensorFail = 0x4; + kCoilSensorFail = 0x8; + kFanFail = 0x10; + } + + bitmap Feature : bitmap32 { + kHeating = 0x1; + kCooling = 0x2; + kOccupancy = 0x4; + kScheduleConfiguration = 0x8; + kSetback = 0x10; + kAutoMode = 0x20; + kLocalTemperatureNotExposed = 0x40; + kMatterScheduleConfiguration = 0x80; + kPresets = 0x100; + } + + bitmap HVACSystemTypeBitmap : bitmap8 { + kCoolingStage = 0x3; + kHeatingStage = 0xC; + kHeatingIsHeatPump = 0x10; + kHeatingUsesFuel = 0x20; + } + + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + + bitmap PresetTypeFeaturesBitmap : bitmap16 { + kAutomatic = 0x1; + kSupportsNames = 0x2; + } + + bitmap ProgrammingOperationModeBitmap : bitmap8 { + kScheduleActive = 0x1; + kAutoRecovery = 0x2; + kEconomy = 0x4; + } + + bitmap RelayStateBitmap : bitmap16 { + kHeat = 0x1; + kCool = 0x2; + kFan = 0x4; + kHeatStage2 = 0x8; + kCoolStage2 = 0x10; + kFanStage2 = 0x20; + kFanStage3 = 0x40; + } + + bitmap RemoteSensingBitmap : bitmap8 { + kLocalTemperature = 0x1; + kOutdoorTemperature = 0x2; + kOccupancy = 0x4; + } + + bitmap ScheduleDayOfWeekBitmap : bitmap8 { + kSunday = 0x1; + kMonday = 0x2; + kTuesday = 0x4; + kWednesday = 0x8; + kThursday = 0x10; + kFriday = 0x20; + kSaturday = 0x40; + kAway = 0x80; + } + + bitmap ScheduleModeBitmap : bitmap8 { + kHeatSetpointPresent = 0x1; + kCoolSetpointPresent = 0x2; + } + + bitmap ScheduleTypeFeaturesBitmap : bitmap16 { + kSupportsPresets = 0x1; + kSupportsSetpoints = 0x2; + kSupportsNames = 0x4; + kSupportsOff = 0x8; + } + + struct ScheduleTransitionStruct { + ScheduleDayOfWeekBitmap dayOfWeek = 0; + int16u transitionTime = 1; + optional octet_string<16> presetHandle = 2; + optional SystemModeEnum systemMode = 3; + optional temperature coolingSetpoint = 4; + optional temperature heatingSetpoint = 5; + } + + struct ScheduleStruct { + nullable octet_string<16> scheduleHandle = 0; + SystemModeEnum systemMode = 1; + optional char_string<64> name = 2; + optional octet_string<16> presetHandle = 3; + ScheduleTransitionStruct transitions[] = 4; + nullable boolean builtIn = 5; + } + + struct PresetStruct { + nullable octet_string<16> presetHandle = 0; + PresetScenarioEnum presetScenario = 1; + optional nullable char_string<64> name = 2; + optional temperature coolingSetpoint = 3; + optional temperature heatingSetpoint = 4; + nullable boolean builtIn = 5; + } + + struct PresetTypeStruct { + PresetScenarioEnum presetScenario = 0; + int8u numberOfPresets = 1; + PresetTypeFeaturesBitmap presetTypeFeatures = 2; + } + + struct ScheduleTypeStruct { + SystemModeEnum systemMode = 0; + int8u numberOfSchedules = 1; + ScheduleTypeFeaturesBitmap scheduleTypeFeatures = 2; + } + + struct WeeklyScheduleTransitionStruct { + int16u transitionTime = 0; + nullable temperature heatSetpoint = 1; + nullable temperature coolSetpoint = 2; + } + + readonly attribute nullable temperature localTemperature = 0; + readonly attribute optional nullable temperature outdoorTemperature = 1; + readonly attribute optional OccupancyBitmap occupancy = 2; + readonly attribute optional temperature absMinHeatSetpointLimit = 3; + readonly attribute optional temperature absMaxHeatSetpointLimit = 4; + readonly attribute optional temperature absMinCoolSetpointLimit = 5; + readonly attribute optional temperature absMaxCoolSetpointLimit = 6; + readonly attribute optional int8u PICoolingDemand = 7; + readonly attribute optional int8u PIHeatingDemand = 8; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional int8s localTemperatureCalibration = 16; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; + attribute access(write: manage) optional int8s minSetpointDeadBand = 25; + attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; + attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; + attribute access(write: manage) SystemModeEnum systemMode = 28; + readonly attribute optional ThermostatRunningModeEnum thermostatRunningMode = 30; + readonly attribute optional StartOfWeekEnum startOfWeek = 32; + readonly attribute optional int8u numberOfWeeklyTransitions = 33; + readonly attribute optional int8u numberOfDailyTransitions = 34; + attribute access(write: manage) optional TemperatureSetpointHoldEnum temperatureSetpointHold = 35; + attribute access(write: manage) optional nullable int16u temperatureSetpointHoldDuration = 36; + attribute access(write: manage) optional ProgrammingOperationModeBitmap thermostatProgrammingOperationMode = 37; + readonly attribute optional RelayStateBitmap thermostatRunningState = 41; + readonly attribute optional SetpointChangeSourceEnum setpointChangeSource = 48; + readonly attribute optional nullable int16s setpointChangeAmount = 49; + readonly attribute optional epoch_s setpointChangeSourceTimestamp = 50; + attribute access(write: manage) optional nullable int8u occupiedSetback = 52; + readonly attribute optional nullable int8u occupiedSetbackMin = 53; + readonly attribute optional nullable int8u occupiedSetbackMax = 54; + attribute access(write: manage) optional nullable int8u unoccupiedSetback = 55; + readonly attribute optional nullable int8u unoccupiedSetbackMin = 56; + readonly attribute optional nullable int8u unoccupiedSetbackMax = 57; + attribute access(write: manage) optional int8u emergencyHeatDelta = 58; + attribute access(write: manage) optional ACTypeEnum ACType = 64; + attribute access(write: manage) optional int16u ACCapacity = 65; + attribute access(write: manage) optional ACRefrigerantTypeEnum ACRefrigerantType = 66; + attribute access(write: manage) optional ACCompressorTypeEnum ACCompressorType = 67; + attribute access(write: manage) optional ACErrorCodeBitmap ACErrorCode = 68; + attribute access(write: manage) optional ACLouverPositionEnum ACLouverPosition = 69; + readonly attribute optional nullable temperature ACCoilTemperature = 70; + attribute access(write: manage) optional ACCapacityFormatEnum ACCapacityformat = 71; + readonly attribute optional PresetTypeStruct presetTypes[] = 72; + readonly attribute optional ScheduleTypeStruct scheduleTypes[] = 73; + readonly attribute optional int8u numberOfPresets = 74; + readonly attribute optional int8u numberOfSchedules = 75; + readonly attribute optional int8u numberOfScheduleTransitions = 76; + readonly attribute optional nullable int8u numberOfScheduleTransitionPerDay = 77; + readonly attribute optional nullable octet_string<16> activePresetHandle = 78; + readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; + attribute access(write: manage) optional PresetStruct presets[] = 80; + attribute access(write: manage) optional ScheduleStruct schedules[] = 81; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct SetpointRaiseLowerRequest { + SetpointRaiseLowerModeEnum mode = 0; + int8s amount = 1; + } + + response struct GetWeeklyScheduleResponse = 0 { + int8u numberOfTransitionsForSequence = 0; + ScheduleDayOfWeekBitmap dayOfWeekForSequence = 1; + ScheduleModeBitmap modeForSequence = 2; + WeeklyScheduleTransitionStruct transitions[] = 3; + } + + request struct SetWeeklyScheduleRequest { + int8u numberOfTransitionsForSequence = 0; + ScheduleDayOfWeekBitmap dayOfWeekForSequence = 1; + ScheduleModeBitmap modeForSequence = 2; + WeeklyScheduleTransitionStruct transitions[] = 3; + } + + request struct GetWeeklyScheduleRequest { + ScheduleDayOfWeekBitmap daysToReturn = 0; + ScheduleModeBitmap modeToReturn = 1; + } + + request struct SetActiveScheduleRequestRequest { + octet_string<16> scheduleHandle = 0; + } + + request struct SetActivePresetRequestRequest { + nullable octet_string<16> presetHandle = 0; + } + + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; + } + + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ + command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ + command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ + command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; + /** This command is used to clear the weekly schedule. */ + command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ + command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; + /** ID */ + command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; +} + +/** Attributes and commands for configuring the measurement of temperature, and reporting temperature measurements. */ +cluster TemperatureMeasurement = 1026 { + revision 1; // NOTE: Default/not specifically set + + readonly attribute nullable temperature measuredValue = 0; + readonly attribute nullable temperature minMeasuredValue = 1; + readonly attribute nullable temperature maxMeasuredValue = 2; + readonly attribute optional int16u tolerance = 3; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +endpoint 0 { + device type ma_rootdevice = 22, version 1; + + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster AccessControl { + callback attribute acl; + callback attribute extension; + callback attribute subjectsPerAccessControlEntry; + callback attribute targetsPerAccessControlEntry; + callback attribute accessControlEntriesPerFabric; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + callback attribute clusterRevision; + } + + server cluster BasicInformation { + callback attribute dataModelRevision; + callback attribute vendorName; + callback attribute vendorID; + callback attribute productName; + callback attribute productID; + ram attribute nodeLabel; + callback attribute location; + callback attribute hardwareVersion; + callback attribute hardwareVersionString; + callback attribute softwareVersion; + callback attribute softwareVersionString; + callback attribute uniqueID; + callback attribute capabilityMinima; + callback attribute specificationVersion; + callback attribute maxPathsPerInvoke; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 3; + } + + server cluster LocalizationConfiguration { + ram attribute activeLocale; + callback attribute supportedLocales; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster GeneralCommissioning { + ram attribute breadcrumb default = 0x0000000000000000; + callback attribute basicCommissioningInfo; + callback attribute regulatoryConfig; + callback attribute locationCapability; + callback attribute supportsConcurrentConnection; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command ArmFailSafe; + handle command ArmFailSafeResponse; + handle command SetRegulatoryConfig; + handle command SetRegulatoryConfigResponse; + handle command CommissioningComplete; + handle command CommissioningCompleteResponse; + } + + server cluster NetworkCommissioning { + ram attribute maxNetworks; + callback attribute networks; + ram attribute interfaceEnabled; + ram attribute lastNetworkingStatus; + ram attribute lastNetworkID; + ram attribute lastConnectErrorValue; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster DiagnosticLogs { + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command RetrieveLogsRequest; + handle command RetrieveLogsResponse; + } + + server cluster GeneralDiagnostics { + callback attribute networkInterfaces; + callback attribute rebootCount; + callback attribute upTime; + ram attribute testEventTriggersEnabled; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command TestEventTrigger; + handle command TimeSnapshot; + handle command TimeSnapshotResponse; + } + + server cluster AdministratorCommissioning { + callback attribute windowStatus; + callback attribute adminFabricIndex; + callback attribute adminVendorId; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command OpenCommissioningWindow; + handle command RevokeCommissioning; + } + + server cluster OperationalCredentials { + callback attribute NOCs; + callback attribute fabrics; + callback attribute supportedFabrics; + callback attribute commissionedFabrics; + callback attribute trustedRootCertificates; + callback attribute currentFabricIndex; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command AttestationRequest; + handle command AttestationResponse; + handle command CertificateChainRequest; + handle command CertificateChainResponse; + handle command CSRRequest; + handle command CSRResponse; + handle command AddNOC; + handle command UpdateNOC; + handle command NOCResponse; + handle command UpdateFabricLabel; + handle command RemoveFabric; + handle command AddTrustedRootCertificate; + } + + server cluster GroupKeyManagement { + callback attribute groupKeyMap; + callback attribute groupTable; + callback attribute maxGroupsPerFabric; + callback attribute maxGroupKeysPerFabric; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command KeySetWrite; + handle command KeySetRead; + handle command KeySetReadResponse; + handle command KeySetRemove; + handle command KeySetReadAllIndices; + handle command KeySetReadAllIndicesResponse; + } +} +endpoint 1 { + device type ma_powersource = 17, version 1; + device type ma_electricalsensor = 1296, version 1; + device type device_energy_management = 1293, version 1; + device type ma_heatpump = 777, version 1; + + binding cluster Thermostat; + + server cluster Identify { + ram attribute identifyTime default = 0x0; + ram attribute identifyType default = 0x00; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 4; + + handle command Identify; + } + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute tagList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster PowerSource { + ram attribute status; + ram attribute order; + ram attribute description; + callback attribute endpointList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 1; + ram attribute clusterRevision default = 1; + } + + server cluster ElectricalPowerMeasurement { + callback attribute powerMode; + callback attribute numberOfMeasurementTypes; + callback attribute accuracy; + callback attribute voltage; + callback attribute activeCurrent; + callback attribute activePower; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 1; + } + + server cluster ElectricalEnergyMeasurement { + callback attribute accuracy; + callback attribute cumulativeEnergyImported; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 1; + } + + server cluster DeviceEnergyManagement { + callback attribute ESAType; + callback attribute ESACanGenerate; + callback attribute ESAState; + callback attribute absMinPower; + callback attribute absMaxPower; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 4; + } + + server cluster PowerTopology { + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 1; + } + + server cluster DeviceEnergyManagementMode { + callback attribute supportedModes; + callback attribute currentMode; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 2; + + handle command ChangeToMode; + handle command ChangeToModeResponse; + } +} +endpoint 2 { + device type ma_tempsensor = 770, version 1; + + + server cluster Identify { + ram attribute identifyTime default = 0x0; + ram attribute identifyType default = 0x00; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 4; + + handle command Identify; + handle command TriggerEffect; + } + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster TemperatureMeasurement { + ram attribute measuredValue default = 6000; + ram attribute minMeasuredValue default = 0; + ram attribute maxMeasuredValue default = 90; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } +} +endpoint 3 { + device type ma_tempsensor = 770, version 1; + + + server cluster Identify { + ram attribute identifyTime default = 0x0; + ram attribute identifyType default = 0x00; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 4; + + handle command Identify; + handle command TriggerEffect; + } + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster TemperatureMeasurement { + ram attribute measuredValue default = 4000; + ram attribute minMeasuredValue default = 0; + ram attribute maxMeasuredValue default = 90; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } +} + + diff --git a/examples/chef/devices/rootnode_heatpump_87ivjRAECh.zap b/examples/chef/devices/rootnode_heatpump_87ivjRAECh.zap new file mode 100644 index 00000000000000..e05f413a910b46 --- /dev/null +++ b/examples/chef/devices/rootnode_heatpump_87ivjRAECh.zap @@ -0,0 +1,4387 @@ +{ + "fileFormat": 2, + "featureLevel": 104, + "creator": "zap", + "keyValuePairs": [ + { + "key": "commandDiscovery", + "value": "1" + }, + { + "key": "defaultResponsePolicy", + "value": "always" + }, + { + "key": "manufacturerCodes", + "value": "0x1002" + } + ], + "package": [ + { + "pathRelativity": "relativeToZap", + "path": "../../../src/app/zap-templates/zcl/zcl.json", + "type": "zcl-properties", + "category": "matter", + "version": 1, + "description": "Matter SDK ZCL data" + }, + { + "pathRelativity": "relativeToZap", + "path": "../../../src/app/zap-templates/app-templates.json", + "type": "gen-templates-json", + "category": "matter", + "version": "chip-v1" + } + ], + "endpointTypes": [ + { + "id": 1, + "name": "MA-rootdevice", + "deviceTypeRef": { + "code": 22, + "profileId": 259, + "label": "MA-rootdevice", + "name": "MA-rootdevice", + "deviceTypeOrder": 0 + }, + "deviceTypes": [ + { + "code": 22, + "profileId": 259, + "label": "MA-rootdevice", + "name": "MA-rootdevice", + "deviceTypeOrder": 0 + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 22 + ], + "deviceTypeName": "MA-rootdevice", + "deviceTypeCode": 22, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Access Control", + "code": 31, + "mfgCode": null, + "define": "ACCESS_CONTROL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "ACL", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Extension", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SubjectsPerAccessControlEntry", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TargetsPerAccessControlEntry", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AccessControlEntriesPerFabric", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Basic Information", + "code": 40, + "mfgCode": null, + "define": "BASIC_INFORMATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DataModelRevision", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "VendorName", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "VendorID", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ProductName", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ProductID", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NodeLabel", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Location", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "HardwareVersion", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "HardwareVersionString", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SoftwareVersion", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SoftwareVersionString", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UniqueID", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CapabilityMinima", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "CapabilityMinimaStruct", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SpecificationVersion", + "code": 21, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxPathsPerInvoke", + "code": 22, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Localization Configuration", + "code": 43, + "mfgCode": null, + "define": "LOCALIZATION_CONFIGURATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "ActiveLocale", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedLocales", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "General Commissioning", + "code": 48, + "mfgCode": null, + "define": "GENERAL_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ArmFailSafe", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ArmFailSafeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "SetRegulatoryConfig", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SetRegulatoryConfigResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CommissioningComplete", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CommissioningCompleteResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "Breadcrumb", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BasicCommissioningInfo", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "BasicCommissioningInfo", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RegulatoryConfig", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LocationCapability", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportsConcurrentConnection", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Network Commissioning", + "code": 49, + "mfgCode": null, + "define": "NETWORK_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "MaxNetworks", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Networks", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "InterfaceEnabled", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkingStatus", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "NetworkCommissioningStatusEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkID", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastConnectErrorValue", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int32s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Diagnostic Logs", + "code": 50, + "mfgCode": null, + "define": "DIAGNOSTIC_LOGS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "RetrieveLogsRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RetrieveLogsResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "General Diagnostics", + "code": 51, + "mfgCode": null, + "define": "GENERAL_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "TestEventTrigger", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TimeSnapshot", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TimeSnapshotResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NetworkInterfaces", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RebootCount", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UpTime", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TestEventTriggersEnabled", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Administrator Commissioning", + "code": 60, + "mfgCode": null, + "define": "ADMINISTRATOR_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "OpenCommissioningWindow", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RevokeCommissioning", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "WindowStatus", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "CommissioningWindowStatusEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminFabricIndex", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "fabric_idx", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminVendorId", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Operational Credentials", + "code": 62, + "mfgCode": null, + "define": "OPERATIONAL_CREDENTIALS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AttestationRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AttestationResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CertificateChainRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CertificateChainResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CSRRequest", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CSRResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AddNOC", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "UpdateNOC", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NOCResponse", + "code": 8, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "UpdateFabricLabel", + "code": 9, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveFabric", + "code": 10, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddTrustedRootCertificate", + "code": 11, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NOCs", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Fabrics", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedFabrics", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CommissionedFabrics", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TrustedRootCertificates", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentFabricIndex", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Group Key Management", + "code": 63, + "mfgCode": null, + "define": "GROUP_KEY_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "KeySetWrite", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetRead", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "KeySetRemove", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndices", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndicesResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "GroupKeyMap", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GroupTable", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxGroupsPerFabric", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxGroupKeysPerFabric", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + }, + { + "id": 2, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 777, + "profileId": 259, + "label": "MA-heatpump", + "name": "MA-heatpump", + "deviceTypeOrder": 0 + }, + "deviceTypes": [ + { + "code": 777, + "profileId": 259, + "label": "MA-heatpump", + "name": "MA-heatpump", + "deviceTypeOrder": 0 + }, + { + "code": 17, + "profileId": 259, + "label": "MA-powersource", + "name": "MA-powersource", + "deviceTypeOrder": 1 + }, + { + "code": 1296, + "profileId": 259, + "label": "MA-electricalsensor", + "name": "MA-electricalsensor", + "deviceTypeOrder": 2 + }, + { + "code": 1293, + "profileId": 259, + "label": "Device Energy Management", + "name": "Device Energy Management", + "deviceTypeOrder": 3 + } + ], + "deviceVersions": [ + 1, + 1, + 1, + 1 + ], + "deviceIdentifiers": [ + 777, + 17, + 1296, + 1293 + ], + "deviceTypeName": "MA-heatpump", + "deviceTypeCode": 777, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "IdentifyTime", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "IdentifyType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "IdentifyTypeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TagList", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Power Source", + "code": 47, + "mfgCode": null, + "define": "POWER_SOURCE_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "Status", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "PowerSourceStatusEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Order", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Description", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EndpointList", + "code": 31, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Electrical Power Measurement", + "code": 144, + "mfgCode": null, + "define": "ELECTRICAL_POWER_MEASUREMENT_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "PowerMode", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "PowerModeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfMeasurementTypes", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Accuracy", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Voltage", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "voltage_mv", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveCurrent", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "amperage_ma", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActivePower", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "power_mw", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Electrical Energy Measurement", + "code": 145, + "mfgCode": null, + "define": "ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "Accuracy", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "MeasurementAccuracyStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CumulativeEnergyImported", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "EnergyMeasurementStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Device Energy Management", + "code": 152, + "mfgCode": null, + "define": "DEVICE_ENERGY_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "attributes": [ + { + "name": "ESAType", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "ESATypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ESACanGenerate", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ESAState", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "ESAStateEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AbsMinPower", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "power_mw", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AbsMaxPower", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "power_mw", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Power Topology", + "code": 156, + "mfgCode": null, + "define": "POWER_TOPOLOGY_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Device Energy Management Mode", + "code": 159, + "mfgCode": null, + "define": "DEVICE_ENERGY_MANAGEMENT_MODE_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "ChangeToMode", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ChangeToModeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "SupportedModes", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentMode", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Thermostat", + "code": 513, + "mfgCode": null, + "define": "THERMOSTAT_CLUSTER", + "side": "client", + "enabled": 1, + "commands": [ + { + "name": "SetpointRaiseLower", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + } + ] + } + ] + }, + { + "id": 3, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 770, + "profileId": 259, + "label": "MA-tempsensor", + "name": "MA-tempsensor", + "deviceTypeOrder": 0 + }, + "deviceTypes": [ + { + "code": 770, + "profileId": 259, + "label": "MA-tempsensor", + "name": "MA-tempsensor", + "deviceTypeOrder": 0 + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 770 + ], + "deviceTypeName": "MA-tempsensor", + "deviceTypeCode": 770, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "IdentifyTime", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "IdentifyType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "IdentifyTypeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Temperature Measurement", + "code": 1026, + "mfgCode": null, + "define": "TEMPERATURE_MEASUREMENT_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "MeasuredValue", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "6000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinMeasuredValue", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxMeasuredValue", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "90", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + }, + { + "id": 4, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 770, + "profileId": 259, + "label": "MA-tempsensor", + "name": "MA-tempsensor", + "deviceTypeOrder": 0 + }, + "deviceTypes": [ + { + "code": 770, + "profileId": 259, + "label": "MA-tempsensor", + "name": "MA-tempsensor", + "deviceTypeOrder": 0 + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 770 + ], + "deviceTypeName": "MA-tempsensor", + "deviceTypeCode": 770, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "IdentifyTime", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "IdentifyType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "IdentifyTypeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Temperature Measurement", + "code": 1026, + "mfgCode": null, + "define": "TEMPERATURE_MEASUREMENT_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "MeasuredValue", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MinMeasuredValue", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxMeasuredValue", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "90", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + } + ], + "endpoints": [ + { + "endpointTypeName": "MA-rootdevice", + "endpointTypeIndex": 0, + "profileId": 259, + "endpointId": 0, + "networkId": null, + "parentEndpointIdentifier": null + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 1, + "profileId": 259, + "endpointId": 1, + "networkId": 0, + "parentEndpointIdentifier": 0 + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 2, + "profileId": 259, + "endpointId": 2, + "networkId": 0, + "parentEndpointIdentifier": 0 + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 3, + "profileId": 259, + "endpointId": 3, + "networkId": 0, + "parentEndpointIdentifier": null + } + ] +} + + diff --git a/examples/chef/sample_app_util/matter_device_types.json b/examples/chef/sample_app_util/matter_device_types.json index 3390dec8a584d7..60e307f0dcf70a 100644 --- a/examples/chef/sample_app_util/matter_device_types.json +++ b/examples/chef/sample_app_util/matter_device_types.json @@ -51,5 +51,6 @@ "Dishwasher": 117, "Smoke CO Alarm": 118, "Water Valve": 66, - "Water Leak Detector": 67 + "Water Leak Detector": 67, + "HeatPump": 777 } From b9d69a2c174ad384cfa588cb2c3f9fa5a2ccebfb Mon Sep 17 00:00:00 2001 From: C Freeman Date: Tue, 17 Dec 2024 12:51:47 -0500 Subject: [PATCH 09/19] Scenes management: Fix access on CopyScene (#36865) --- .../all-clusters-common/all-clusters-app.matter | 2 +- .../all-clusters-common/all-clusters-minimal-app.matter | 2 +- .../chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter | 2 +- .../light-switch-common/icd-lit-light-switch-app.matter | 2 +- .../light-switch-common/light-switch-app.matter | 2 +- examples/light-switch-app/qpg/zap/switch.matter | 2 +- .../lighting-common/lighting-app.matter | 2 +- examples/lighting-app/lighting-common/lighting-app.matter | 2 +- .../lighting-app/silabs/data_model/lighting-thread-app.matter | 2 +- .../lighting-app/silabs/data_model/lighting-wifi-app.matter | 2 +- examples/placeholder/linux/apps/app1/config.matter | 2 +- examples/placeholder/linux/apps/app2/config.matter | 2 +- .../virtual-device-common/virtual-device-app.matter | 2 +- .../zap/tests/outputs/all-clusters-app/app-templates/access.h | 3 +++ .../zap/tests/outputs/lighting-app/app-templates/access.h | 3 +++ src/app/zap-templates/zcl/data-model/chip/scene.xml | 1 + src/controller/data_model/controller-clusters.matter | 2 +- 17 files changed, 21 insertions(+), 14 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index 071a3fcf7c5b76..fc877675127909 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -4010,7 +4010,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** Attributes and commands for monitoring HEPA filters in a device */ diff --git a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter index ae50904721e813..c3fac02bab41a7 100644 --- a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter +++ b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter @@ -2879,7 +2879,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** An interface to a generic way to secure a door */ diff --git a/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter b/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter index cc875bbd196bf7..aabfbccc2d0a90 100644 --- a/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter +++ b/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter @@ -1908,7 +1908,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** The server cluster provides an interface to occupancy sensing functionality based on one or more sensing modalities, including configuration and provision of notifications of occupancy status. */ diff --git a/examples/light-switch-app/light-switch-common/icd-lit-light-switch-app.matter b/examples/light-switch-app/light-switch-common/icd-lit-light-switch-app.matter index 67ed0ab5715709..a3e73a8cd0b348 100644 --- a/examples/light-switch-app/light-switch-common/icd-lit-light-switch-app.matter +++ b/examples/light-switch-app/light-switch-common/icd-lit-light-switch-app.matter @@ -2438,7 +2438,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** Attributes and commands for controlling the color properties of a color-capable light. */ diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.matter b/examples/light-switch-app/light-switch-common/light-switch-app.matter index 07910e283f3a0a..f3410b59dfa0a8 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.matter +++ b/examples/light-switch-app/light-switch-common/light-switch-app.matter @@ -2438,7 +2438,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** Attributes and commands for controlling the color properties of a color-capable light. */ diff --git a/examples/light-switch-app/qpg/zap/switch.matter b/examples/light-switch-app/qpg/zap/switch.matter index 03e0f51ad0830d..dcf118163d8ec4 100644 --- a/examples/light-switch-app/qpg/zap/switch.matter +++ b/examples/light-switch-app/qpg/zap/switch.matter @@ -2555,7 +2555,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** Attributes and commands for controlling the color properties of a color-capable light. */ diff --git a/examples/lighting-app-data-mode-no-unique-id/lighting-common/lighting-app.matter b/examples/lighting-app-data-mode-no-unique-id/lighting-common/lighting-app.matter index e8e99173b85a17..431011ab0c9859 100644 --- a/examples/lighting-app-data-mode-no-unique-id/lighting-common/lighting-app.matter +++ b/examples/lighting-app-data-mode-no-unique-id/lighting-common/lighting-app.matter @@ -2246,7 +2246,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** Attributes and commands for controlling the color properties of a color-capable light. */ diff --git a/examples/lighting-app/lighting-common/lighting-app.matter b/examples/lighting-app/lighting-common/lighting-app.matter index 769d929e580836..80db43eedb8548 100644 --- a/examples/lighting-app/lighting-common/lighting-app.matter +++ b/examples/lighting-app/lighting-common/lighting-app.matter @@ -2246,7 +2246,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** Attributes and commands for controlling the color properties of a color-capable light. */ diff --git a/examples/lighting-app/silabs/data_model/lighting-thread-app.matter b/examples/lighting-app/silabs/data_model/lighting-thread-app.matter index 9fb02976f031d5..3c8202d4392460 100644 --- a/examples/lighting-app/silabs/data_model/lighting-thread-app.matter +++ b/examples/lighting-app/silabs/data_model/lighting-thread-app.matter @@ -1950,7 +1950,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** Attributes and commands for controlling the color properties of a color-capable light. */ diff --git a/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter b/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter index 1619fc9622caf4..16f4d7247f44ac 100644 --- a/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter +++ b/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter @@ -2241,7 +2241,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** Attributes and commands for controlling the color properties of a color-capable light. */ diff --git a/examples/placeholder/linux/apps/app1/config.matter b/examples/placeholder/linux/apps/app1/config.matter index fe5fe0bfe6d84b..9daced64e142bd 100644 --- a/examples/placeholder/linux/apps/app1/config.matter +++ b/examples/placeholder/linux/apps/app1/config.matter @@ -3514,7 +3514,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** An interface to a generic way to secure a door */ diff --git a/examples/placeholder/linux/apps/app2/config.matter b/examples/placeholder/linux/apps/app2/config.matter index 68de2f9ffba90e..e81c96d55c248c 100644 --- a/examples/placeholder/linux/apps/app2/config.matter +++ b/examples/placeholder/linux/apps/app2/config.matter @@ -3471,7 +3471,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** An interface to a generic way to secure a door */ diff --git a/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter b/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter index b9a3224db7f109..1ae60c5b6c6c25 100644 --- a/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter +++ b/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter @@ -2354,7 +2354,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** An interface to a generic way to secure a door */ diff --git a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/access.h b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/access.h index 9b35ecb22d178c..cea3c62600180c 100644 --- a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/access.h +++ b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/access.h @@ -400,6 +400,7 @@ 0x00000062, /* Cluster: Scenes Management, Command: RemoveScene, Privilege: manage */ \ 0x00000062, /* Cluster: Scenes Management, Command: RemoveAllScenes, Privilege: manage */ \ 0x00000062, /* Cluster: Scenes Management, Command: StoreScene, Privilege: manage */ \ + 0x00000062, /* Cluster: Scenes Management, Command: CopyScene, Privilege: manage */ \ 0x00000201, /* Cluster: Thermostat, Command: AtomicRequest, Privilege: manage */ \ 0xFFF1FC06, /* Cluster: Fault Injection, Command: FailAtFault, Privilege: manage */ \ 0xFFF1FC06, /* Cluster: Fault Injection, Command: FailRandomlyAtFault, Privilege: manage */ \ @@ -450,6 +451,7 @@ 0x00000002, /* Cluster: Scenes Management, Command: RemoveScene, Privilege: manage */ \ 0x00000003, /* Cluster: Scenes Management, Command: RemoveAllScenes, Privilege: manage */ \ 0x00000004, /* Cluster: Scenes Management, Command: StoreScene, Privilege: manage */ \ + 0x00000040, /* Cluster: Scenes Management, Command: CopyScene, Privilege: manage */ \ 0x000000FE, /* Cluster: Thermostat, Command: AtomicRequest, Privilege: manage */ \ 0x00000000, /* Cluster: Fault Injection, Command: FailAtFault, Privilege: manage */ \ 0x00000001, /* Cluster: Fault Injection, Command: FailRandomlyAtFault, Privilege: manage */ \ @@ -500,6 +502,7 @@ chip::Access::Privilege::kManage, /* Cluster: Scenes Management, Command: RemoveScene, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Scenes Management, Command: RemoveAllScenes, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Scenes Management, Command: StoreScene, Privilege: manage */ \ + chip::Access::Privilege::kManage, /* Cluster: Scenes Management, Command: CopyScene, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Thermostat, Command: AtomicRequest, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Fault Injection, Command: FailAtFault, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Fault Injection, Command: FailRandomlyAtFault, Privilege: manage */ \ diff --git a/scripts/tools/zap/tests/outputs/lighting-app/app-templates/access.h b/scripts/tools/zap/tests/outputs/lighting-app/app-templates/access.h index acef1673384c14..c062b9376f4666 100644 --- a/scripts/tools/zap/tests/outputs/lighting-app/app-templates/access.h +++ b/scripts/tools/zap/tests/outputs/lighting-app/app-templates/access.h @@ -200,6 +200,7 @@ 0x00000062, /* Cluster: Scenes Management, Command: RemoveScene, Privilege: manage */ \ 0x00000062, /* Cluster: Scenes Management, Command: RemoveAllScenes, Privilege: manage */ \ 0x00000062, /* Cluster: Scenes Management, Command: StoreScene, Privilege: manage */ \ + 0x00000062, /* Cluster: Scenes Management, Command: CopyScene, Privilege: manage */ \ } // Parallel array data (cluster, *command*, privilege) for invoke command @@ -242,6 +243,7 @@ 0x00000002, /* Cluster: Scenes Management, Command: RemoveScene, Privilege: manage */ \ 0x00000003, /* Cluster: Scenes Management, Command: RemoveAllScenes, Privilege: manage */ \ 0x00000004, /* Cluster: Scenes Management, Command: StoreScene, Privilege: manage */ \ + 0x00000040, /* Cluster: Scenes Management, Command: CopyScene, Privilege: manage */ \ } // Parallel array data (cluster, command, *privilege*) for invoke command @@ -284,6 +286,7 @@ chip::Access::Privilege::kManage, /* Cluster: Scenes Management, Command: RemoveScene, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Scenes Management, Command: RemoveAllScenes, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Scenes Management, Command: StoreScene, Privilege: manage */ \ + chip::Access::Privilege::kManage, /* Cluster: Scenes Management, Command: CopyScene, Privilege: manage */ \ } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/app/zap-templates/zcl/data-model/chip/scene.xml b/src/app/zap-templates/zcl/data-model/chip/scene.xml index ceea35e3759e69..fdd4a65c9cb29c 100644 --- a/src/app/zap-templates/zcl/data-model/chip/scene.xml +++ b/src/app/zap-templates/zcl/data-model/chip/scene.xml @@ -169,6 +169,7 @@ limitations under the License. + diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 31da395b05cd31..35b85ec5ffbd77 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -4272,7 +4272,7 @@ provisional cluster ScenesManagement = 98 { /** Get an unused scene identifier when no commissioning tool is in the network, or for a commissioning tool to get the used scene identifiers within a certain group */ fabric command GetSceneMembership(GetSceneMembershipRequest): GetSceneMembershipResponse = 6; /** Allows a client to efficiently copy scenes from one group/scene identifier pair to another group/scene identifier pair. */ - fabric command CopyScene(CopySceneRequest): CopySceneResponse = 64; + fabric command access(invoke: manage) CopyScene(CopySceneRequest): CopySceneResponse = 64; } /** Attributes and commands for monitoring HEPA filters in a device */ From d0ec3a716c69a25f25690239cfc16c46c802ef51 Mon Sep 17 00:00:00 2001 From: C Freeman Date: Tue, 17 Dec 2024 12:52:27 -0500 Subject: [PATCH 10/19] General diagnostics: Fix access on PayloadTestRequest (#36864) --- .../air-purifier-common/air-purifier-app.matter | 2 +- .../air-quality-sensor-common/air-quality-sensor-app.matter | 2 +- .../all-clusters-common/all-clusters-app.matter | 2 +- .../all-clusters-common/all-clusters-minimal-app.matter | 2 +- examples/bridge-app/bridge-common/bridge-app.matter | 2 +- .../devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter | 2 +- examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter | 2 +- ...eraturesensor_humiditysensor_thermostat_56de3d5f45.matter | 2 +- .../chef/devices/rootnode_airqualitysensor_e63187f6c9.matter | 2 +- .../chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter | 2 +- .../devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter | 2 +- .../chef/devices/rootnode_contactsensor_27f76aeaf5.matter | 2 +- .../chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter | 2 +- ...ditysensor_airqualitysensor_powersource_367e7cea91.matter | 2 +- .../chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter | 2 +- .../devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter | 2 +- examples/chef/devices/rootnode_dishwasher_cc105034fe.matter | 2 +- examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter | 2 +- .../devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter | 2 +- examples/chef/devices/rootnode_fan_7N2TobIlOX.matter | 2 +- examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter | 2 +- .../chef/devices/rootnode_genericswitch_2dfff6e516.matter | 2 +- .../chef/devices/rootnode_genericswitch_9866e35d0b.matter | 2 +- .../devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter | 2 +- .../chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter | 2 +- .../chef/devices/rootnode_laundrydryer_01796fe396.matter | 2 +- .../chef/devices/rootnode_laundrywasher_fb10d238c8.matter | 2 +- examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter | 2 +- .../chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter | 2 +- examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter | 2 +- examples/chef/devices/rootnode_onofflight_samplemei.matter | 2 +- .../chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter | 2 +- .../chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter | 2 +- .../chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter | 2 +- examples/chef/devices/rootnode_pump_5f904818cc.matter | 2 +- examples/chef/devices/rootnode_pump_a811bb33a0.matter | 2 +- ...ledcabinet_temperaturecontrolledcabinet_ffdb696680.matter | 2 +- .../devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter | 2 +- .../devices/rootnode_roomairconditioner_9cf3607804.matter | 2 +- .../chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter | 2 +- examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter | 2 +- .../devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter | 2 +- examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter | 2 +- .../devices/rootnode_waterleakdetector_0b067acfa3.matter | 2 +- examples/chef/devices/rootnode_watervalve_6bb39f1f67.matter | 2 +- .../chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter | 2 +- .../contact-sensor-common/contact-sensor-app.matter | 2 +- .../contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter | 2 +- .../contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter | 2 +- .../dishwasher-app/dishwasher-common/dishwasher-app.matter | 2 +- .../silabs/data_model/dishwasher-thread-app.matter | 2 +- .../silabs/data_model/dishwasher-wifi-app.matter | 2 +- .../energy-management-common/energy-management-app.matter | 2 +- .../fabric-bridge-common/fabric-bridge-app.matter | 2 +- examples/fabric-sync/bridge/fabric-bridge.matter | 2 +- .../laundry-washer-app/nxp/zap/laundry-washer-app.matter | 2 +- .../light-switch-common/icd-lit-light-switch-app.matter | 2 +- .../light-switch-common/light-switch-app.matter | 2 +- examples/light-switch-app/qpg/zap/switch.matter | 2 +- .../lighting-common/lighting-app.matter | 2 +- .../bouffalolab/data_model/lighting-app-ethernet.matter | 2 +- .../bouffalolab/data_model/lighting-app-thread.matter | 2 +- .../bouffalolab/data_model/lighting-app-wifi.matter | 2 +- examples/lighting-app/lighting-common/lighting-app.matter | 2 +- examples/lighting-app/nxp/zap/lighting-on-off.matter | 2 +- examples/lighting-app/qpg/zap/light.matter | 2 +- .../silabs/data_model/lighting-thread-app.matter | 2 +- .../lighting-app/silabs/data_model/lighting-wifi-app.matter | 2 +- .../lit-icd-app/lit-icd-common/lit-icd-server-app.matter | 2 +- examples/lock-app/lock-common/lock-app.matter | 2 +- examples/lock-app/nxp/zap/lock-app.matter | 2 +- examples/lock-app/qpg/zap/lock.matter | 2 +- examples/lock-app/silabs/data_model/lock-app.matter | 2 +- .../microwave-oven-common/microwave-oven-app.matter | 2 +- .../network-manager-common/network-manager-app.matter | 2 +- .../ota-provider-common/ota-provider-app.matter | 2 +- .../ota-requestor-common/ota-requestor-app.matter | 2 +- examples/placeholder/linux/apps/app1/config.matter | 2 +- examples/placeholder/linux/apps/app2/config.matter | 2 +- examples/pump-app/pump-common/pump-app.matter | 2 +- examples/pump-app/silabs/data_model/pump-thread-app.matter | 2 +- examples/pump-app/silabs/data_model/pump-wifi-app.matter | 2 +- .../pump-controller-common/pump-controller-app.matter | 2 +- .../refrigerator-common/refrigerator-app.matter | 2 +- .../silabs/data_model/refrigerator-thread-app.matter | 2 +- .../silabs/data_model/refrigerator-wifi-app.matter | 2 +- examples/rvc-app/rvc-common/rvc-app.matter | 2 +- .../smoke-co-alarm-common/smoke-co-alarm-app.matter | 2 +- .../temperature-measurement.matter | 2 +- examples/thermostat/nxp/zap/thermostat_matter_br.matter | 2 +- examples/thermostat/nxp/zap/thermostat_matter_thread.matter | 2 +- examples/thermostat/nxp/zap/thermostat_matter_wifi.matter | 2 +- examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter | 2 +- examples/thermostat/thermostat-common/thermostat.matter | 2 +- examples/thread-br-app/thread-br-common/thread-br-app.matter | 2 +- examples/tv-app/tv-common/tv-app.matter | 2 +- .../tv-casting-app/tv-casting-common/tv-casting-app.matter | 2 +- .../virtual-device-common/virtual-device-app.matter | 2 +- .../water-leak-detector-app.matter | 2 +- examples/window-app/common/window-app.matter | 2 +- .../tests/outputs/all-clusters-app/app-templates/access.h | 3 +++ .../zcl/data-model/chip/general-diagnostics-cluster.xml | 5 +++-- src/controller/data_model/controller-clusters.matter | 2 +- 103 files changed, 107 insertions(+), 103 deletions(-) diff --git a/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter b/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter index 8b8743c6b67330..be9b08eecf6c5d 100644 --- a/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter +++ b/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter @@ -1147,7 +1147,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/air-quality-sensor-app/air-quality-sensor-common/air-quality-sensor-app.matter b/examples/air-quality-sensor-app/air-quality-sensor-common/air-quality-sensor-app.matter index 896a27edd0d365..3fac5bbaeac2d1 100644 --- a/examples/air-quality-sensor-app/air-quality-sensor-common/air-quality-sensor-app.matter +++ b/examples/air-quality-sensor-app/air-quality-sensor-common/air-quality-sensor-app.matter @@ -1100,7 +1100,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index fc877675127909..be6f4c0622c94a 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -2050,7 +2050,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter index c3fac02bab41a7..e7c61c1c308a05 100644 --- a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter +++ b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter @@ -1965,7 +1965,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/bridge-app/bridge-common/bridge-app.matter b/examples/bridge-app/bridge-common/bridge-app.matter index 26a16622741c6c..a17e26628c0deb 100644 --- a/examples/bridge-app/bridge-common/bridge-app.matter +++ b/examples/bridge-app/bridge-common/bridge-app.matter @@ -1454,7 +1454,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter b/examples/chef/devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter index 9a91b17a2a718a..931784e091f027 100644 --- a/examples/chef/devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter +++ b/examples/chef/devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter @@ -1262,7 +1262,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter b/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter index dc4334462e5cd8..d3e3b7b2d5eb47 100644 --- a/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter +++ b/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter @@ -1219,7 +1219,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter b/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter index 7c5232970dfaf5..dfa25e487b78e9 100644 --- a/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter +++ b/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter @@ -1070,7 +1070,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter b/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter index ac2265df8d50a4..aef07a846c9fd0 100644 --- a/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter +++ b/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter @@ -1406,7 +1406,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter index f9b32f989dbce5..9d1c73090d23c3 100644 --- a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter +++ b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter @@ -1344,7 +1344,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter b/examples/chef/devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter index 5f0c6496f87d65..17b103e7d38b00 100644 --- a/examples/chef/devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter +++ b/examples/chef/devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter @@ -1421,7 +1421,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter b/examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter index 8c08a4e1540b5e..b28730a4017232 100644 --- a/examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter +++ b/examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter @@ -1406,7 +1406,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter b/examples/chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter index 1d5b5856208131..4f9bdd54889000 100644 --- a/examples/chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter +++ b/examples/chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter @@ -1504,7 +1504,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_contactsensor_lightsensor_occupancysensor_temperaturesensor_pressuresensor_flowsensor_humiditysensor_airqualitysensor_powersource_367e7cea91.matter b/examples/chef/devices/rootnode_contactsensor_lightsensor_occupancysensor_temperaturesensor_pressuresensor_flowsensor_humiditysensor_airqualitysensor_powersource_367e7cea91.matter index 27c88b4fb8435e..c7acde0a5c341a 100644 --- a/examples/chef/devices/rootnode_contactsensor_lightsensor_occupancysensor_temperaturesensor_pressuresensor_flowsensor_humiditysensor_airqualitysensor_powersource_367e7cea91.matter +++ b/examples/chef/devices/rootnode_contactsensor_lightsensor_occupancysensor_temperaturesensor_pressuresensor_flowsensor_humiditysensor_airqualitysensor_powersource_367e7cea91.matter @@ -1290,7 +1290,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter b/examples/chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter index 57166f3ba46159..a2b13bd5ffdb72 100644 --- a/examples/chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter +++ b/examples/chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter @@ -1442,7 +1442,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter b/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter index aabfbccc2d0a90..b2c67e9c9a4a4b 100644 --- a/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter +++ b/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter @@ -1442,7 +1442,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_dishwasher_cc105034fe.matter b/examples/chef/devices/rootnode_dishwasher_cc105034fe.matter index d730676d92ece9..9eac1825e8d0b0 100644 --- a/examples/chef/devices/rootnode_dishwasher_cc105034fe.matter +++ b/examples/chef/devices/rootnode_dishwasher_cc105034fe.matter @@ -1061,7 +1061,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Wi-Fi Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter b/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter index 6aa16252672dcd..57ebf108fce25f 100644 --- a/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter +++ b/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter @@ -1406,7 +1406,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter b/examples/chef/devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter index 71363c84a7d8a5..11c3186dcbfc10 100644 --- a/examples/chef/devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter +++ b/examples/chef/devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter @@ -1442,7 +1442,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter b/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter index 1acdbca51279a4..217d06a4e7c2c7 100644 --- a/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter +++ b/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter @@ -1224,7 +1224,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter b/examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter index 466dbe2c419115..7d4b787540cbe3 100644 --- a/examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter +++ b/examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter @@ -1245,7 +1245,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter b/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter index 0ae39923c10a27..aa8846b6c64d4f 100644 --- a/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter +++ b/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter @@ -1252,7 +1252,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** This cluster exposes interactions with a switch device, for the purpose of using those interactions by other devices. diff --git a/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter b/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter index 6a66018ef40f60..5d79f67076a948 100644 --- a/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter +++ b/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter @@ -1252,7 +1252,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** This cluster exposes interactions with a switch device, for the purpose of using those interactions by other devices. diff --git a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter index 36a655d47df5b6..76eac769b14b2b 100644 --- a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter +++ b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter @@ -1442,7 +1442,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter b/examples/chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter index e633b0f2bebc4c..a401aed997c79d 100644 --- a/examples/chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter +++ b/examples/chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter @@ -1245,7 +1245,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_laundrydryer_01796fe396.matter b/examples/chef/devices/rootnode_laundrydryer_01796fe396.matter index bb05b243f8283d..7960936439f774 100644 --- a/examples/chef/devices/rootnode_laundrydryer_01796fe396.matter +++ b/examples/chef/devices/rootnode_laundrydryer_01796fe396.matter @@ -1061,7 +1061,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Wi-Fi Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_laundrywasher_fb10d238c8.matter b/examples/chef/devices/rootnode_laundrywasher_fb10d238c8.matter index 2e76d3f34a3a85..c92cf98aed3b59 100644 --- a/examples/chef/devices/rootnode_laundrywasher_fb10d238c8.matter +++ b/examples/chef/devices/rootnode_laundrywasher_fb10d238c8.matter @@ -994,7 +994,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Wi-Fi Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter b/examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter index 32528515cf121b..167fb98e36ece9 100644 --- a/examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter +++ b/examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter @@ -1245,7 +1245,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter b/examples/chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter index 04cf5fb646d7bb..2d35dcb2f8840d 100644 --- a/examples/chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter +++ b/examples/chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter @@ -1245,7 +1245,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter b/examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter index c4cc8357d94ef8..f91a4df653c42f 100644 --- a/examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter +++ b/examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter @@ -1442,7 +1442,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_onofflight_samplemei.matter b/examples/chef/devices/rootnode_onofflight_samplemei.matter index 32b351b6e81791..174f5c119469fa 100644 --- a/examples/chef/devices/rootnode_onofflight_samplemei.matter +++ b/examples/chef/devices/rootnode_onofflight_samplemei.matter @@ -1442,7 +1442,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter b/examples/chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter index 81fb81958f8f5d..190a3a4edc4e86 100644 --- a/examples/chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter +++ b/examples/chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter @@ -1317,7 +1317,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter b/examples/chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter index 94414ae3165662..4da57e8e1b3686 100644 --- a/examples/chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter +++ b/examples/chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter @@ -1317,7 +1317,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter b/examples/chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter index 1bc2e8726e1083..3d493f926633f9 100644 --- a/examples/chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter +++ b/examples/chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter @@ -1245,7 +1245,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_pump_5f904818cc.matter b/examples/chef/devices/rootnode_pump_5f904818cc.matter index 8cd43edf190fd9..741dda60e307bc 100644 --- a/examples/chef/devices/rootnode_pump_5f904818cc.matter +++ b/examples/chef/devices/rootnode_pump_5f904818cc.matter @@ -1044,7 +1044,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/chef/devices/rootnode_pump_a811bb33a0.matter b/examples/chef/devices/rootnode_pump_a811bb33a0.matter index 5b2371526d9a59..50c2dd31633bd9 100644 --- a/examples/chef/devices/rootnode_pump_a811bb33a0.matter +++ b/examples/chef/devices/rootnode_pump_a811bb33a0.matter @@ -1044,7 +1044,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/chef/devices/rootnode_refrigerator_temperaturecontrolledcabinet_temperaturecontrolledcabinet_ffdb696680.matter b/examples/chef/devices/rootnode_refrigerator_temperaturecontrolledcabinet_temperaturecontrolledcabinet_ffdb696680.matter index bfbd486f6e0d01..686d67e3fa49aa 100644 --- a/examples/chef/devices/rootnode_refrigerator_temperaturecontrolledcabinet_temperaturecontrolledcabinet_ffdb696680.matter +++ b/examples/chef/devices/rootnode_refrigerator_temperaturecontrolledcabinet_temperaturecontrolledcabinet_ffdb696680.matter @@ -922,7 +922,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Wi-Fi Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter b/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter index dbc56cd15e5d26..9abd9b19729f7d 100644 --- a/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter +++ b/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter @@ -1329,7 +1329,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter b/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter index 467ad0c462767d..bb4a46da845f29 100644 --- a/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter +++ b/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter @@ -1142,7 +1142,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter b/examples/chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter index b7e31f0bdcbf1c..f64237210be6fc 100644 --- a/examples/chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter +++ b/examples/chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter @@ -1329,7 +1329,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter b/examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter index c5a1ccc522a4c3..ef250cb35245ec 100644 --- a/examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter +++ b/examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter @@ -1365,7 +1365,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter b/examples/chef/devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter index 6199388887e069..e26a62dfd2f1b1 100644 --- a/examples/chef/devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter +++ b/examples/chef/devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter @@ -1245,7 +1245,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter index 79930324883042..549c98f930b62b 100644 --- a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter +++ b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter @@ -1306,7 +1306,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/chef/devices/rootnode_waterleakdetector_0b067acfa3.matter b/examples/chef/devices/rootnode_waterleakdetector_0b067acfa3.matter index 1ea6c421aba885..67f17e7ab95b4c 100644 --- a/examples/chef/devices/rootnode_waterleakdetector_0b067acfa3.matter +++ b/examples/chef/devices/rootnode_waterleakdetector_0b067acfa3.matter @@ -1329,7 +1329,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/chef/devices/rootnode_watervalve_6bb39f1f67.matter b/examples/chef/devices/rootnode_watervalve_6bb39f1f67.matter index 0e4ffe5dc8ee14..7105d9904673da 100644 --- a/examples/chef/devices/rootnode_watervalve_6bb39f1f67.matter +++ b/examples/chef/devices/rootnode_watervalve_6bb39f1f67.matter @@ -1269,7 +1269,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter b/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter index 0f1d25c571179f..30b58d92053827 100644 --- a/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter +++ b/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter @@ -1245,7 +1245,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/contact-sensor-app/contact-sensor-common/contact-sensor-app.matter b/examples/contact-sensor-app/contact-sensor-common/contact-sensor-app.matter index 55820ca5377f4f..fed65931ab4d49 100644 --- a/examples/contact-sensor-app/contact-sensor-common/contact-sensor-app.matter +++ b/examples/contact-sensor-app/contact-sensor-common/contact-sensor-app.matter @@ -1224,7 +1224,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter b/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter index 899dc159a0baaa..f3027e97812e05 100644 --- a/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter +++ b/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter @@ -1147,7 +1147,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter b/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter index 3c88ebe1202775..6fd0de001695a9 100644 --- a/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter +++ b/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter @@ -1147,7 +1147,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/dishwasher-app/dishwasher-common/dishwasher-app.matter b/examples/dishwasher-app/dishwasher-common/dishwasher-app.matter index 6ee107a38f063e..8e3096b7a08efc 100644 --- a/examples/dishwasher-app/dishwasher-common/dishwasher-app.matter +++ b/examples/dishwasher-app/dishwasher-common/dishwasher-app.matter @@ -1070,7 +1070,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Wi-Fi Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/dishwasher-app/silabs/data_model/dishwasher-thread-app.matter b/examples/dishwasher-app/silabs/data_model/dishwasher-thread-app.matter index 93222a8580e5ba..87d6dca00e4391 100644 --- a/examples/dishwasher-app/silabs/data_model/dishwasher-thread-app.matter +++ b/examples/dishwasher-app/silabs/data_model/dishwasher-thread-app.matter @@ -1255,7 +1255,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/dishwasher-app/silabs/data_model/dishwasher-wifi-app.matter b/examples/dishwasher-app/silabs/data_model/dishwasher-wifi-app.matter index 24abdb39862888..e2daba3687f4fa 100644 --- a/examples/dishwasher-app/silabs/data_model/dishwasher-wifi-app.matter +++ b/examples/dishwasher-app/silabs/data_model/dishwasher-wifi-app.matter @@ -1255,7 +1255,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.matter b/examples/energy-management-app/energy-management-common/energy-management-app.matter index bdcbe117c8344b..d7db07d6c94993 100644 --- a/examples/energy-management-app/energy-management-common/energy-management-app.matter +++ b/examples/energy-management-app/energy-management-common/energy-management-app.matter @@ -1292,7 +1292,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter b/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter index 06e76db5ecee1a..2d1148bef83cd8 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter +++ b/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter @@ -1118,7 +1118,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/fabric-sync/bridge/fabric-bridge.matter b/examples/fabric-sync/bridge/fabric-bridge.matter index 06e76db5ecee1a..2d1148bef83cd8 100644 --- a/examples/fabric-sync/bridge/fabric-bridge.matter +++ b/examples/fabric-sync/bridge/fabric-bridge.matter @@ -1118,7 +1118,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter b/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter index 37b7786af95b80..678ca3b0f4082f 100644 --- a/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter +++ b/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter @@ -1360,7 +1360,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/light-switch-app/light-switch-common/icd-lit-light-switch-app.matter b/examples/light-switch-app/light-switch-common/icd-lit-light-switch-app.matter index a3e73a8cd0b348..2e3827d9ae2268 100644 --- a/examples/light-switch-app/light-switch-common/icd-lit-light-switch-app.matter +++ b/examples/light-switch-app/light-switch-common/icd-lit-light-switch-app.matter @@ -1367,7 +1367,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.matter b/examples/light-switch-app/light-switch-common/light-switch-app.matter index f3410b59dfa0a8..b50c93ec27d357 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.matter +++ b/examples/light-switch-app/light-switch-common/light-switch-app.matter @@ -1367,7 +1367,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/light-switch-app/qpg/zap/switch.matter b/examples/light-switch-app/qpg/zap/switch.matter index dcf118163d8ec4..2eb47604f38781 100644 --- a/examples/light-switch-app/qpg/zap/switch.matter +++ b/examples/light-switch-app/qpg/zap/switch.matter @@ -1751,7 +1751,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/lighting-app-data-mode-no-unique-id/lighting-common/lighting-app.matter b/examples/lighting-app-data-mode-no-unique-id/lighting-common/lighting-app.matter index 431011ab0c9859..4c7e31646de0fa 100644 --- a/examples/lighting-app-data-mode-no-unique-id/lighting-common/lighting-app.matter +++ b/examples/lighting-app-data-mode-no-unique-id/lighting-common/lighting-app.matter @@ -1421,7 +1421,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/lighting-app/bouffalolab/data_model/lighting-app-ethernet.matter b/examples/lighting-app/bouffalolab/data_model/lighting-app-ethernet.matter index 7ce2b52c2db8a2..277e8bc07c66ea 100644 --- a/examples/lighting-app/bouffalolab/data_model/lighting-app-ethernet.matter +++ b/examples/lighting-app/bouffalolab/data_model/lighting-app-ethernet.matter @@ -1421,7 +1421,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/lighting-app/bouffalolab/data_model/lighting-app-thread.matter b/examples/lighting-app/bouffalolab/data_model/lighting-app-thread.matter index bc48c4056b2b45..e7a1fd8a68f6aa 100644 --- a/examples/lighting-app/bouffalolab/data_model/lighting-app-thread.matter +++ b/examples/lighting-app/bouffalolab/data_model/lighting-app-thread.matter @@ -1421,7 +1421,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/lighting-app/bouffalolab/data_model/lighting-app-wifi.matter b/examples/lighting-app/bouffalolab/data_model/lighting-app-wifi.matter index d896f4308f956d..94444d34e7f16b 100644 --- a/examples/lighting-app/bouffalolab/data_model/lighting-app-wifi.matter +++ b/examples/lighting-app/bouffalolab/data_model/lighting-app-wifi.matter @@ -1421,7 +1421,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/lighting-app/lighting-common/lighting-app.matter b/examples/lighting-app/lighting-common/lighting-app.matter index 80db43eedb8548..53f31a35e85a38 100644 --- a/examples/lighting-app/lighting-common/lighting-app.matter +++ b/examples/lighting-app/lighting-common/lighting-app.matter @@ -1421,7 +1421,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/lighting-app/nxp/zap/lighting-on-off.matter b/examples/lighting-app/nxp/zap/lighting-on-off.matter index c80d7cfa191a0e..a3f91b06d14683 100644 --- a/examples/lighting-app/nxp/zap/lighting-on-off.matter +++ b/examples/lighting-app/nxp/zap/lighting-on-off.matter @@ -1374,7 +1374,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/lighting-app/qpg/zap/light.matter b/examples/lighting-app/qpg/zap/light.matter index fbefaabad5bb1f..f6ac363e2f3e98 100644 --- a/examples/lighting-app/qpg/zap/light.matter +++ b/examples/lighting-app/qpg/zap/light.matter @@ -1421,7 +1421,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/lighting-app/silabs/data_model/lighting-thread-app.matter b/examples/lighting-app/silabs/data_model/lighting-thread-app.matter index 3c8202d4392460..7a2429dad1428c 100644 --- a/examples/lighting-app/silabs/data_model/lighting-thread-app.matter +++ b/examples/lighting-app/silabs/data_model/lighting-thread-app.matter @@ -1374,7 +1374,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Thread Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems */ diff --git a/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter b/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter index 16f4d7247f44ac..83614e8cc918d7 100644 --- a/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter +++ b/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter @@ -1680,7 +1680,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter index 3c51bf0b1bdf73..a54445b68294e6 100644 --- a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter +++ b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter @@ -1126,7 +1126,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Thread Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems */ diff --git a/examples/lock-app/lock-common/lock-app.matter b/examples/lock-app/lock-common/lock-app.matter index 650458149c4620..0220deb75b9797 100644 --- a/examples/lock-app/lock-common/lock-app.matter +++ b/examples/lock-app/lock-common/lock-app.matter @@ -1432,7 +1432,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/lock-app/nxp/zap/lock-app.matter b/examples/lock-app/nxp/zap/lock-app.matter index 281f19877b8eab..da021c44546d03 100644 --- a/examples/lock-app/nxp/zap/lock-app.matter +++ b/examples/lock-app/nxp/zap/lock-app.matter @@ -1164,7 +1164,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/lock-app/qpg/zap/lock.matter b/examples/lock-app/qpg/zap/lock.matter index 74ab5d744a5702..f2c759e8f7fe70 100644 --- a/examples/lock-app/qpg/zap/lock.matter +++ b/examples/lock-app/qpg/zap/lock.matter @@ -1224,7 +1224,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/lock-app/silabs/data_model/lock-app.matter b/examples/lock-app/silabs/data_model/lock-app.matter index 8a7695c75d6c87..ee3cc824b79d14 100644 --- a/examples/lock-app/silabs/data_model/lock-app.matter +++ b/examples/lock-app/silabs/data_model/lock-app.matter @@ -1432,7 +1432,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter b/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter index fbc5c3625aad5f..bf5f45f4027a80 100644 --- a/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter +++ b/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter @@ -990,7 +990,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Wi-Fi Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/network-manager-app/network-manager-common/network-manager-app.matter b/examples/network-manager-app/network-manager-common/network-manager-app.matter index 4847e0ff9e22c2..4e3c7d01aa0bc4 100644 --- a/examples/network-manager-app/network-manager-common/network-manager-app.matter +++ b/examples/network-manager-app/network-manager-common/network-manager-app.matter @@ -896,7 +896,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Thread Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems */ diff --git a/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter b/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter index 7538f304f356d4..9619f70767810d 100644 --- a/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter +++ b/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter @@ -1097,7 +1097,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter b/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter index 5269b6e7094558..2c4f638037a3f2 100644 --- a/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter +++ b/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter @@ -1249,7 +1249,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/placeholder/linux/apps/app1/config.matter b/examples/placeholder/linux/apps/app1/config.matter index 9daced64e142bd..6bc47afef7015b 100644 --- a/examples/placeholder/linux/apps/app1/config.matter +++ b/examples/placeholder/linux/apps/app1/config.matter @@ -2125,7 +2125,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/placeholder/linux/apps/app2/config.matter b/examples/placeholder/linux/apps/app2/config.matter index e81c96d55c248c..9b116eb8ba7780 100644 --- a/examples/placeholder/linux/apps/app2/config.matter +++ b/examples/placeholder/linux/apps/app2/config.matter @@ -2082,7 +2082,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/pump-app/pump-common/pump-app.matter b/examples/pump-app/pump-common/pump-app.matter index d4ac8e35a3c9b2..a07feba84c3886 100644 --- a/examples/pump-app/pump-common/pump-app.matter +++ b/examples/pump-app/pump-common/pump-app.matter @@ -1318,7 +1318,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Thread Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems */ diff --git a/examples/pump-app/silabs/data_model/pump-thread-app.matter b/examples/pump-app/silabs/data_model/pump-thread-app.matter index 7d730d759c139a..c56d83fc2bc844 100644 --- a/examples/pump-app/silabs/data_model/pump-thread-app.matter +++ b/examples/pump-app/silabs/data_model/pump-thread-app.matter @@ -1318,7 +1318,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Thread Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems */ diff --git a/examples/pump-app/silabs/data_model/pump-wifi-app.matter b/examples/pump-app/silabs/data_model/pump-wifi-app.matter index 7d730d759c139a..c56d83fc2bc844 100644 --- a/examples/pump-app/silabs/data_model/pump-wifi-app.matter +++ b/examples/pump-app/silabs/data_model/pump-wifi-app.matter @@ -1318,7 +1318,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Thread Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems */ diff --git a/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter b/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter index a7c2ebcd0fbbdf..c4d91f94c05faf 100644 --- a/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter +++ b/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter @@ -1193,7 +1193,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Thread Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems */ diff --git a/examples/refrigerator-app/refrigerator-common/refrigerator-app.matter b/examples/refrigerator-app/refrigerator-common/refrigerator-app.matter index f3149e01afe4c9..b99237cdfd6036 100644 --- a/examples/refrigerator-app/refrigerator-common/refrigerator-app.matter +++ b/examples/refrigerator-app/refrigerator-common/refrigerator-app.matter @@ -922,7 +922,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Wi-Fi Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/refrigerator-app/silabs/data_model/refrigerator-thread-app.matter b/examples/refrigerator-app/silabs/data_model/refrigerator-thread-app.matter index 38c88d543ec6a2..838776ac2a823b 100644 --- a/examples/refrigerator-app/silabs/data_model/refrigerator-thread-app.matter +++ b/examples/refrigerator-app/silabs/data_model/refrigerator-thread-app.matter @@ -1172,7 +1172,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Thread Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems */ diff --git a/examples/refrigerator-app/silabs/data_model/refrigerator-wifi-app.matter b/examples/refrigerator-app/silabs/data_model/refrigerator-wifi-app.matter index acb85ae85a4066..530f00d32fd7ab 100644 --- a/examples/refrigerator-app/silabs/data_model/refrigerator-wifi-app.matter +++ b/examples/refrigerator-app/silabs/data_model/refrigerator-wifi-app.matter @@ -1172,7 +1172,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Wi-Fi Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/rvc-app/rvc-common/rvc-app.matter b/examples/rvc-app/rvc-common/rvc-app.matter index 0db897b3f7bd23..512f54cfd7fe52 100644 --- a/examples/rvc-app/rvc-common/rvc-app.matter +++ b/examples/rvc-app/rvc-common/rvc-app.matter @@ -993,7 +993,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter b/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter index d4d7f8c93ed3c9..3bd4cae0d926b7 100644 --- a/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter +++ b/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter @@ -1483,7 +1483,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter b/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter index 17ab13992cbdc3..75105aaad3c7da 100644 --- a/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter +++ b/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter @@ -1123,7 +1123,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/thermostat/nxp/zap/thermostat_matter_br.matter b/examples/thermostat/nxp/zap/thermostat_matter_br.matter index 8a8d69fce64421..1ba87a1fbd58b5 100644 --- a/examples/thermostat/nxp/zap/thermostat_matter_br.matter +++ b/examples/thermostat/nxp/zap/thermostat_matter_br.matter @@ -1197,7 +1197,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/thermostat/nxp/zap/thermostat_matter_thread.matter b/examples/thermostat/nxp/zap/thermostat_matter_thread.matter index a2a2f2d93acd05..af687b2ba11bcb 100644 --- a/examples/thermostat/nxp/zap/thermostat_matter_thread.matter +++ b/examples/thermostat/nxp/zap/thermostat_matter_thread.matter @@ -1197,7 +1197,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/thermostat/nxp/zap/thermostat_matter_wifi.matter b/examples/thermostat/nxp/zap/thermostat_matter_wifi.matter index b5b24560e31cd1..825a527c59b155 100644 --- a/examples/thermostat/nxp/zap/thermostat_matter_wifi.matter +++ b/examples/thermostat/nxp/zap/thermostat_matter_wifi.matter @@ -1197,7 +1197,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter b/examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter index 86383cf90492b8..96ed93bd8c07b9 100644 --- a/examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter +++ b/examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter @@ -1321,7 +1321,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/thermostat/thermostat-common/thermostat.matter b/examples/thermostat/thermostat-common/thermostat.matter index 1c062da0fecabc..03428f294324cf 100644 --- a/examples/thermostat/thermostat-common/thermostat.matter +++ b/examples/thermostat/thermostat-common/thermostat.matter @@ -1382,7 +1382,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/thread-br-app/thread-br-common/thread-br-app.matter b/examples/thread-br-app/thread-br-common/thread-br-app.matter index 4aa0db4a702334..b1ef02cd5aa47f 100644 --- a/examples/thread-br-app/thread-br-common/thread-br-app.matter +++ b/examples/thread-br-app/thread-br-common/thread-br-app.matter @@ -896,7 +896,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Thread Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems */ diff --git a/examples/tv-app/tv-common/tv-app.matter b/examples/tv-app/tv-common/tv-app.matter index 3cf472ee1de91c..1023de099d4976 100644 --- a/examples/tv-app/tv-common/tv-app.matter +++ b/examples/tv-app/tv-common/tv-app.matter @@ -1617,7 +1617,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter b/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter index b1f1cb4916fed1..d02a997c5e7487 100644 --- a/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter +++ b/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter @@ -1361,7 +1361,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter b/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter index 1ae60c5b6c6c25..ad1da15819866d 100644 --- a/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter +++ b/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter @@ -1585,7 +1585,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/examples/water-leak-detector-app/water-leak-detector-common/water-leak-detector-app.matter b/examples/water-leak-detector-app/water-leak-detector-common/water-leak-detector-app.matter index 5d4d31b28f4e41..cb185ad5ea10a8 100644 --- a/examples/water-leak-detector-app/water-leak-detector-common/water-leak-detector-app.matter +++ b/examples/water-leak-detector-app/water-leak-detector-common/water-leak-detector-app.matter @@ -1346,7 +1346,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ diff --git a/examples/window-app/common/window-app.matter b/examples/window-app/common/window-app.matter index 850b8f047ef83d..c0b7cbd37dd69e 100644 --- a/examples/window-app/common/window-app.matter +++ b/examples/window-app/common/window-app.matter @@ -1462,7 +1462,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ diff --git a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/access.h b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/access.h index cea3c62600180c..8e2e0ca373a86c 100644 --- a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/access.h +++ b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/access.h @@ -373,6 +373,7 @@ 0x00000031, /* Cluster: Network Commissioning, Command: ConnectNetwork, Privilege: administer */ \ 0x00000031, /* Cluster: Network Commissioning, Command: ReorderNetwork, Privilege: administer */ \ 0x00000033, /* Cluster: General Diagnostics, Command: TestEventTrigger, Privilege: manage */ \ + 0x00000033, /* Cluster: General Diagnostics, Command: PayloadTestRequest, Privilege: manage */ \ 0x00000034, /* Cluster: Software Diagnostics, Command: ResetWatermarks, Privilege: manage */ \ 0x00000035, /* Cluster: Thread Network Diagnostics, Command: ResetCounts, Privilege: manage */ \ 0x00000037, /* Cluster: Ethernet Network Diagnostics, Command: ResetCounts, Privilege: manage */ \ @@ -424,6 +425,7 @@ 0x00000006, /* Cluster: Network Commissioning, Command: ConnectNetwork, Privilege: administer */ \ 0x00000008, /* Cluster: Network Commissioning, Command: ReorderNetwork, Privilege: administer */ \ 0x00000000, /* Cluster: General Diagnostics, Command: TestEventTrigger, Privilege: manage */ \ + 0x00000003, /* Cluster: General Diagnostics, Command: PayloadTestRequest, Privilege: manage */ \ 0x00000000, /* Cluster: Software Diagnostics, Command: ResetWatermarks, Privilege: manage */ \ 0x00000000, /* Cluster: Thread Network Diagnostics, Command: ResetCounts, Privilege: manage */ \ 0x00000000, /* Cluster: Ethernet Network Diagnostics, Command: ResetCounts, Privilege: manage */ \ @@ -475,6 +477,7 @@ chip::Access::Privilege::kAdminister, /* Cluster: Network Commissioning, Command: ConnectNetwork, Privilege: administer */ \ chip::Access::Privilege::kAdminister, /* Cluster: Network Commissioning, Command: ReorderNetwork, Privilege: administer */ \ chip::Access::Privilege::kManage, /* Cluster: General Diagnostics, Command: TestEventTrigger, Privilege: manage */ \ + chip::Access::Privilege::kManage, /* Cluster: General Diagnostics, Command: PayloadTestRequest, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Software Diagnostics, Command: ResetWatermarks, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Thread Network Diagnostics, Command: ResetCounts, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Ethernet Network Diagnostics, Command: ResetCounts, Privilege: manage */ \ diff --git a/src/app/zap-templates/zcl/data-model/chip/general-diagnostics-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/general-diagnostics-cluster.xml index c3bae609c66a21..ac628ffcede887 100644 --- a/src/app/zap-templates/zcl/data-model/chip/general-diagnostics-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/general-diagnostics-cluster.xml @@ -151,7 +151,7 @@ limitations under the License. - + Request a variable length payload response. @@ -159,9 +159,10 @@ limitations under the License. + - + Response for the PayloadTestRequest command. diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 35b85ec5ffbd77..aa2707931f36d6 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -1990,7 +1990,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ From 4ae6882682c403581294f80df59d35f73821cd15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Tue, 17 Dec 2024 19:07:09 +0100 Subject: [PATCH 11/19] Update paths.py (#36852) Fix the path to the documentation file. --- scripts/spec_xml/paths.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/spec_xml/paths.py b/scripts/spec_xml/paths.py index 3a5159cc514bf1..d4e269759f17f2 100644 --- a/scripts/spec_xml/paths.py +++ b/scripts/spec_xml/paths.py @@ -71,7 +71,7 @@ def get_documentation_file_path(): Returns the path to the documentation file. """ chip_root = get_chip_root() - documentation_file = os.path.join(chip_root, 'docs', 'spec_clusters.md') + documentation_file = os.path.join(chip_root, 'docs', 'ids_and_codes', 'spec_clusters.md') if not os.path.exists(documentation_file): raise FileNotFoundError(f"Documentation file does not exist: {documentation_file}") return documentation_file From dbb08f51b596e58c2622b39b20d454a6e94d04a6 Mon Sep 17 00:00:00 2001 From: BoB13-Matter Date: Wed, 18 Dec 2024 03:27:00 +0900 Subject: [PATCH 12/19] Fix Global Buffer Overflow in AudioOutputManager.cpp (#36858) --- .../tv-common/clusters/audio-output/AudioOutputManager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/tv-app/tv-common/clusters/audio-output/AudioOutputManager.cpp b/examples/tv-app/tv-common/clusters/audio-output/AudioOutputManager.cpp index 77a1e2111b44be..4a2a1a0609c448 100644 --- a/examples/tv-app/tv-common/clusters/audio-output/AudioOutputManager.cpp +++ b/examples/tv-app/tv-common/clusters/audio-output/AudioOutputManager.cpp @@ -62,6 +62,11 @@ bool AudioOutputManager::HandleRenameOutput(const uint8_t & index, const chip::C { if (output.index == index) { + if (sizeof(mCharDataBuffer[index]) < name.size()) + { + return audioOutputRenamed; + } + audioOutputRenamed = true; memcpy(this->Data(index), name.data(), name.size()); output.name = chip::CharSpan(this->Data(index), name.size()); From b159e9c694038c06a074943b614d34dfd3a37321 Mon Sep 17 00:00:00 2001 From: BoB13-Matter Date: Wed, 18 Dec 2024 03:27:12 +0900 Subject: [PATCH 13/19] Fix Global Buffer Overflow in MediaInputManager.cpp (#36856) --- .../tv-common/clusters/media-input/MediaInputManager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/tv-app/tv-common/clusters/media-input/MediaInputManager.cpp b/examples/tv-app/tv-common/clusters/media-input/MediaInputManager.cpp index 0c1dac40832e96..dd3ed3664bcd2a 100644 --- a/examples/tv-app/tv-common/clusters/media-input/MediaInputManager.cpp +++ b/examples/tv-app/tv-common/clusters/media-input/MediaInputManager.cpp @@ -99,6 +99,11 @@ bool MediaInputManager::HandleRenameInput(const uint8_t index, const chip::CharS { if (input.index == index) { + if (sizeof(mCharDataBuffer[index]) < name.size()) + { + return mediaInputRenamed; + } + mediaInputRenamed = true; memcpy(this->Data(index), name.data(), name.size()); input.name = chip::CharSpan(this->Data(index), name.size()); From 52d4406d7168320a93a9305d45d2a4a664bff788 Mon Sep 17 00:00:00 2001 From: C Freeman Date: Tue, 17 Dec 2024 13:27:40 -0500 Subject: [PATCH 14/19] TC-IDM-10.6: Add device type revision test (#36698) * Door lock: Fix device type revisions Root node - revision 2 deprecated the power configuration cluster (not on this device) - revision 3 added MACL restrictions (not applicable to this device) Door lock - revision 2 is the matter initial revision, which is what this should have been - revision 3 changes the scenes management cluster revision, but it doesn't affect anything on the device because it's disallowed and also provisional * TC-IDM-10.6: Add device type revision test * Restyled by autopep8 --------- Co-authored-by: Restyled.io --- examples/lock-app/lock-common/lock-app.matter | 4 +- examples/lock-app/lock-common/lock-app.zap | 284 ++---------------- src/python_testing/TC_DeviceConformance.py | 44 ++- 3 files changed, 63 insertions(+), 269 deletions(-) diff --git a/examples/lock-app/lock-common/lock-app.matter b/examples/lock-app/lock-common/lock-app.matter index 0220deb75b9797..29c096abfa96dd 100644 --- a/examples/lock-app/lock-common/lock-app.matter +++ b/examples/lock-app/lock-common/lock-app.matter @@ -2799,7 +2799,7 @@ cluster DoorLock = 257 { } endpoint 0 { - device type ma_rootdevice = 22, version 1; + device type ma_rootdevice = 22, version 3; device type ma_powersource = 17, version 1; binding cluster OtaSoftwareUpdateProvider; @@ -3181,7 +3181,7 @@ endpoint 0 { } endpoint 1 { device type ma_powersource = 17, version 1; - device type ma_doorlock = 10, version 1; + device type ma_doorlock = 10, version 3; server cluster Identify { diff --git a/examples/lock-app/lock-common/lock-app.zap b/examples/lock-app/lock-common/lock-app.zap index cd8979532f284e..467412d7796566 100644 --- a/examples/lock-app/lock-common/lock-app.zap +++ b/examples/lock-app/lock-common/lock-app.zap @@ -1,6 +1,6 @@ { "fileFormat": 2, - "featureLevel": 103, + "featureLevel": 104, "creator": "zap", "keyValuePairs": [ { @@ -38,35 +38,38 @@ "id": 1, "name": "MA-rootdevice", "deviceTypeRef": { - "code": 17, + "code": 22, "profileId": 259, - "label": "MA-powersource", - "name": "MA-powersource" + "label": "MA-rootdevice", + "name": "MA-rootdevice", + "deviceTypeOrder": 0 }, "deviceTypes": [ { - "code": 17, + "code": 22, "profileId": 259, - "label": "MA-powersource", - "name": "MA-powersource" + "label": "MA-rootdevice", + "name": "MA-rootdevice", + "deviceTypeOrder": 0 }, { - "code": 22, + "code": 17, "profileId": 259, - "label": "MA-rootdevice", - "name": "MA-rootdevice" + "label": "MA-powersource", + "name": "MA-powersource", + "deviceTypeOrder": 1 } ], "deviceVersions": [ - 1, + 3, 1 ], "deviceIdentifiers": [ - 17, - 22 + 22, + 17 ], - "deviceTypeName": "MA-powersource", - "deviceTypeCode": 17, + "deviceTypeName": "MA-rootdevice", + "deviceTypeCode": 22, "deviceTypeProfileId": 259, "clusters": [ { @@ -173,22 +176,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -359,22 +346,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -817,22 +788,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 1, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -1135,22 +1090,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -1337,22 +1276,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -1582,22 +1505,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -1890,22 +1797,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -2226,22 +2117,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -4083,22 +3958,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -4383,22 +4242,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -4603,22 +4446,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -4884,24 +4711,27 @@ "code": 10, "profileId": 259, "label": "MA-doorlock", - "name": "MA-doorlock" + "name": "MA-doorlock", + "deviceTypeOrder": 0 }, "deviceTypes": [ { "code": 10, "profileId": 259, "label": "MA-doorlock", - "name": "MA-doorlock" + "name": "MA-doorlock", + "deviceTypeOrder": 0 }, { "code": 17, "profileId": 259, "label": "MA-powersource", - "name": "MA-powersource" + "name": "MA-powersource", + "deviceTypeOrder": 1 } ], "deviceVersions": [ - 1, + 3, 1 ], "deviceIdentifiers": [ @@ -5002,22 +4832,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -5172,22 +4986,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -5422,22 +5220,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -6306,22 +6088,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, diff --git a/src/python_testing/TC_DeviceConformance.py b/src/python_testing/TC_DeviceConformance.py index 6a8c840c648265..a7843a521105a0 100644 --- a/src/python_testing/TC_DeviceConformance.py +++ b/src/python_testing/TC_DeviceConformance.py @@ -30,7 +30,7 @@ # --PICS src/app/tests/suites/certification/ci-pics-values # --trace-to json:${TRACE_TEST_JSON}.json # --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto -# --tests test_TC_IDM_10_2 +# --tests test_TC_IDM_10_2 test_TC_IDM_10_6 # factory-reset: true # quiet: true # === END CI TEST ARGUMENTS === @@ -273,6 +273,35 @@ def record_warning(location, problem): return success, problems + def check_device_type_revisions(self) -> tuple[bool, list[ProblemNotice]]: + success = True + problems = [] + + def record_error(location, problem): + nonlocal success + problems.append(ProblemNotice("IDM-10.6", location, ProblemSeverity.ERROR, problem, "")) + success = False + + for endpoint_id, endpoint in self.endpoints.items(): + if Clusters.Descriptor not in endpoint: + # Descriptor cluster presence checked in 10.5 + continue + + standard_device_types = [x for x in endpoint[Clusters.Descriptor] + [Clusters.Descriptor.Attributes.DeviceTypeList] if device_type_id_type(x.deviceType) == DeviceTypeIdType.kStandard] + for device_type in standard_device_types: + device_type_id = device_type.deviceType + if device_type_id not in self.xml_device_types.keys(): + # problem recorded in 10.5 + continue + expected_revision = self.xml_device_types[device_type_id].revision + actual_revision = device_type.revision + if expected_revision != actual_revision: + location = ClusterPathLocation(endpoint_id=endpoint_id, cluster_id=Clusters.Descriptor.id) + record_error( + location, f"Expected Device type revision for device type {device_type_id} {self.xml_device_types[device_type_id].name} on endpoint {endpoint_id} does not match revision on DUT. Expected: {expected_revision} DUT: {actual_revision}") + return success, problems + def check_device_type(self, fail_on_extra_clusters: bool = True, allow_provisional: bool = False) -> tuple[bool, list[ProblemNotice]]: success = True problems = [] @@ -311,13 +340,6 @@ def record_warning(location, problem): record_error(location=location, problem='Unknown device type ID in standard range') continue - if device_type_id not in self.xml_device_types.keys(): - location = DeviceTypePathLocation(device_type_id=device_type_id) - record_error(location=location, problem='Unknown device type') - continue - - # TODO: check revision. Possibly in another test? - xml_device = self.xml_device_types[device_type_id] # IDM 10.1 checks individual clusters for validity, # so here we can ignore checks for invalid and manufacturer clusters. @@ -385,6 +407,12 @@ def test_TC_IDM_10_5(self): if not success: self.fail_current_test("Problems with Device type conformance on one or more endpoints") + def test_TC_IDM_10_6(self): + success, problems = self.check_device_type_revisions() + self.problems.extend(problems) + if not success: + self.fail_current_test("Problems with Device type revisions on one or more endpoints") + if __name__ == "__main__": default_matter_test_main() From dca8f9bde5f2fcd60153d6584b7470d57d4ba14f Mon Sep 17 00:00:00 2001 From: Raul Marquez <130402456+raul-marquez-csa@users.noreply.github.com> Date: Tue, 17 Dec 2024 10:27:48 -0800 Subject: [PATCH 15/19] [TC-SC-4.3] Discovery [DUT as Commissionee] (#31982) * Adds TC_SC_4_3.py * Fixes TXT record not available when making direct query with name and type * Fixes restyle, adds comments to operational service logic * Fix restlye for mdns class * Adds get_service_types to mdns class * Fix restyle * Steps progress * Fix restyle * Fix restyle * Adds test to tests.yaml * Fix lint * Fix lit-icd-app path in tests.yaml * Fix SII key logic * Addresses latest review comments * Fix lint * Replaces 1 sec fixed sleep in operational service logic with service listener event wait time * Merge from master * MDNS class update progress * Adds MdnsAsyncServiceInfo class * Adds get_service_by_record_type to mdns class * TC progress * Fix restyle * Fix restyle * Fix lint * Fix restyle * tests.yaml from master * tests.yaml from master * Updates steps output and test runner configs * Adds tc to tests.yaml * Update * Updates to make a fresh question each time * Update progress * Fix restyle * Fix Lint * Fix restyle * Fix lint * Adds CI task tags * Completes step 11 * Fix restyled * Steps 8,11 * Fix restyled * Adds timeout to get_service_types * Updates get_service_types description * Update src/python_testing/TC_SC_4_3.py Co-authored-by: C Freeman * Adds clarifying comment * Adds MCORE.COM PICS checks * Updates contains_ipv6_address * Removes listener dealy * Fix restyled * Fix restyled * Fix lint * Updates ipv6 check * Fixes ipv6 checks * Restore ms delay * continue * Step 9 - Updates hostname character length check, other adjustments * removes temp test file * Restyled by autopep8 * Removes test case YAML and manualTests.json reference * Fix restyle * Updates CI python test arguments * Fix typo * matter_testing import update * Update src/python_testing/TC_SC_4_3.py Co-authored-by: C Freeman * Update src/python_testing/TC_SC_4_3.py Co-authored-by: C Freeman * Update src/python_testing/TC_SC_4_3.py Co-authored-by: C Freeman * Addresses latest * Fix restyle * Testing zeroconf class imports * service info refactor * Fix restyle * Fix restyle * Updates mdns service info init * Fix restyle * Updates MdnsAsyncServiceInfo --------- Co-authored-by: C Freeman Co-authored-by: Restyled.io --- .../suites/certification/Test_TC_SC_4_3.yaml | 55 --- src/app/tests/suites/manualTests.json | 1 - src/python_testing/TC_SC_4_3.py | 407 ++++++++++++++++++ .../mdns_discovery/mdns_async_service_info.py | 135 ++++++ .../mdns_discovery/mdns_discovery.py | 181 +++++++- .../mdns_discovery/mdns_service_type_enum.py | 26 -- 6 files changed, 703 insertions(+), 102 deletions(-) delete mode 100644 src/app/tests/suites/certification/Test_TC_SC_4_3.yaml create mode 100644 src/python_testing/TC_SC_4_3.py create mode 100644 src/python_testing/mdns_discovery/mdns_async_service_info.py delete mode 100644 src/python_testing/mdns_discovery/mdns_service_type_enum.py diff --git a/src/app/tests/suites/certification/Test_TC_SC_4_3.yaml b/src/app/tests/suites/certification/Test_TC_SC_4_3.yaml deleted file mode 100644 index 8521cb24bc8daa..00000000000000 --- a/src/app/tests/suites/certification/Test_TC_SC_4_3.yaml +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) 2021 Project CHIP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default - -name: 3.4.3. [TC-SC-4.3] Discovery [DUT as Commissionee] - -PICS: - - MCORE.ROLE.COMMISSIONEE - -config: - nodeId: 0x12344321 - cluster: "Basic Information" - endpoint: 0 - -tests: - - label: "Note" - verification: | - Chip-tool command used below are an example to verify the DUT as controller test cases. For certification test, we expect DUT should have a capability or way to run the equivalent command. - disabled: true - - - label: - "Step 1: DUT is commissioned to TH and DUT is instructed to advertise - its operational service (_matter._tcp)." - verification: | - 1. Provision the DUT by TH (Chip-tool) - disabled: true - - - label: "Step 2: Scan for DNS-SD advertising" - PICS: - MCORE.COM.WIFI && MCORE.COM.ETH && MCORE.COM.THR && MCORE.ICD && - MCORE.SC.SII_OP_DISCOVERY_KEY && MCORE.SC.SAI_OP_DISCOVERY_KEY && - MCORE.SC.SAT_OP_DISCOVERY_KEY && MCORE.SC.T_KEY - verification: | - avahi-browse -rt _matter._tcp - - Verify the device is advertising _matterc._udp service like below output in TH terminal Log: (Verify for the DUT's actual values (like vendor ID, PID ..etc) as mentioned in the expected outcome of the test plan, The below log contains the data from the reference raspi accessory) - - + veth721e1d9 IPv6 433B62F8F07F4327-0000000000000001 _matter._tcp local - = veth721e1d9 IPv6 433B62F8F07F4327-0000000000000001 _matter._tcp local - hostname = [E45F0149AE290000.local] - address = [fe80::28e0:95ff:fed9:3085] - port = [5540] - txt = ["T=1" "SAI=300" "SII=5000"] - disabled: true diff --git a/src/app/tests/suites/manualTests.json b/src/app/tests/suites/manualTests.json index 4b7961b29deb01..c63714edc4317b 100644 --- a/src/app/tests/suites/manualTests.json +++ b/src/app/tests/suites/manualTests.json @@ -220,7 +220,6 @@ "Test_TC_SC_3_4", "Test_TC_SC_4_1", "Test_TC_SC_4_2", - "Test_TC_SC_4_3", "Test_TC_SC_4_4", "Test_TC_SC_4_5", "Test_TC_SC_4_6", diff --git a/src/python_testing/TC_SC_4_3.py b/src/python_testing/TC_SC_4_3.py new file mode 100644 index 00000000000000..e0ce02d2a58398 --- /dev/null +++ b/src/python_testing/TC_SC_4_3.py @@ -0,0 +1,407 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments +# for details about the block below. + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${LIT_ICD_APP} +# factory-reset: true +# quiet: true +# app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# script-args: > +# --storage-path admin_storage.json +# --commissioning-method on-network +# --discriminator 1234 +# --passcode 20202021 +# --trace-to json:${TRACE_TEST_JSON}.json +# --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + +import ipaddress +import logging +import re + +import chip.clusters as Clusters +from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mdns_discovery.mdns_discovery import DNSRecordType, MdnsDiscovery, MdnsServiceType +from mobly import asserts +from zeroconf.const import _TYPE_AAAA, _TYPES + +''' +Purpose +The purpose of this test case is to verify that a Matter node is discoverable +and can advertise its services in a Matter network. + +Test Plan +https://github.com/CHIP-Specifications/chip-test-plans/blob/master/src/securechannel.adoc#343-tc-sc-43-discovery-dut_commissionee +''' + + +class TC_SC_4_3(MatterBaseTest): + + def steps_TC_SC_4_3(self): + return [TestStep(1, "DUT is commissioned on the same fabric as TH."), + TestStep(2, "TH reads ServerList attribute from the Descriptor cluster on EP0. ", + "If the ICD Management cluster ID (70,0x46) is present in the list, set supports_icd to true, otherwise set supports_icd to false."), + TestStep(3, + "If supports_icd is true, TH reads ActiveModeThreshold from the ICD Management cluster on EP0 and saves as active_mode_threshold.", ""), + TestStep(4, "If supports_icd is true, TH reads FeatureMap from the ICD Management cluster on EP0. If the LITS feature is set, set supports_lit to true. Otherwise set supports_lit to false.", ""), + TestStep(5, "TH constructs the instance name for the DUT as the 64-bit compressed Fabric identifier, and the assigned 64-bit Node identifier, each expressed as a fixed-length sixteen-character hexadecimal string, encoded as ASCII (UTF-8) text using capital letters, separated by a hyphen.", ""), + TestStep(6, "TH performs a query for the SRV record against the qname instance_qname.", + "Verify SRV record is returned"), + TestStep(7, "TH performs a query for the TXT record against the qname instance_qname.", + "Verify TXT record is returned"), + TestStep(8, "TH performs a query for the AAAA record against the target listed in the SRV record", + "Verify AAAA record is returned"), + TestStep(9, "TH verifies the following from the returned records:", + "TH verifies the following from the returned records: The hostname must be a fixed-length twelve-character (or sixteen-character) hexadecimal string, encoded as ASCII (UTF-8) text using capital letters.. ICD TXT key: • If supports_lit is false, verify that the ICD key is NOT present in the TXT record • If supports_lit is true, verify the ICD key IS present in the TXT record, and it has the value of 0 or 1 (ASCII) SII TXT key: • If supports_icd is true and supports_lit is false, set sit_mode to true • If supports_icd is true and supports_lit is true, set sit_mode to true if ICD=0 otherwise set sit_mode to false • If supports_icd is false, set sit_mode to false • If sit_mode is true, verify that the SII key IS present in the TXT record • if the SII key is present, verify it is a decimal value with no leading zeros and is less than or equal to 3600000 (1h in ms) SAI TXT key: • if supports_icd is true, verify that the SAI key is present in the TXT record • If the SAI key is present, verify it is a decimal value with no leading zeros and is less than or equal to 3600000 (1h in ms)"), + TestStep(10, "TH performs a DNS-SD browse for _I._sub._matter._tcp.local, where is the 64-bit compressed Fabric identifier, expressed as a fixed-length, sixteencharacter hexadecimal string, encoded as ASCII (UTF-8) text using capital letters.", + "Verify DUT returns a PTR record with DNS-SD instance name set to instance_name"), + TestStep(11, "TH performs a DNS-SD browse for _matter._tcp.local", + "Verify DUT returns a PTR record with DNS-SD instance name set to instance_name"), + ] + + ONE_HOUR_IN_MS = 3600000 + MAX_SAT_VALUE = 65535 + MAX_T_VALUE = 6 + + async def get_descriptor_server_list(self): + return await self.read_single_attribute_check_success( + endpoint=0, + dev_ctrl=self.default_controller, + cluster=Clusters.Descriptor, + attribute=Clusters.Descriptor.Attributes.ServerList + ) + + async def get_idle_mode_threshhold_ms(self): + return await self.read_single_attribute_check_success( + endpoint=0, + dev_ctrl=self.default_controller, + cluster=Clusters.IcdManagement, + attribute=Clusters.IcdManagement.Attributes.ActiveModeThreshold + ) + + async def get_icd_feature_map(self): + return await self.read_single_attribute_check_success( + endpoint=0, + dev_ctrl=self.default_controller, + cluster=Clusters.IcdManagement, + attribute=Clusters.IcdManagement.Attributes.FeatureMap + ) + + def get_dut_instance_name(self) -> str: + node_id = self.dut_node_id + compressed_fabric_id = self.default_controller.GetCompressedFabricId() + instance_name = f'{compressed_fabric_id:016X}-{node_id:016X}' + return instance_name + + def get_operational_subtype(self) -> str: + compressed_fabric_id = self.default_controller.GetCompressedFabricId() + service_name = f'_I{compressed_fabric_id:016X}._sub.{MdnsServiceType.OPERATIONAL.value}' + return service_name + + @staticmethod + def verify_decimal_value(input_value, max_value: int): + try: + input_float = float(input_value) + input_int = int(input_float) + + if str(input_value).startswith("0") and input_int != 0: + return (False, f"Input ({input_value}) has leading zeros.") + + if input_float != input_int: + return (False, f"Input ({input_value}) is not an integer.") + + if input_int <= max_value: + return (True, f"Input ({input_value}) is valid.") + else: + return (False, f"Input ({input_value}) exceeds the allowed value {max_value}.") + except ValueError: + return (False, f"Input ({input_value}) is not a valid decimal number.") + + def verify_t_value(self, t_value): + # Verify t_value is a decimal number without leading zeros and less than or equal to 6 + try: + T_int = int(t_value) + if T_int < 0 or T_int > self.MAX_T_VALUE: + return False, f"T value ({t_value}) is not in the range 0 to 6. ({t_value})" + if str(t_value).startswith("0") and T_int != 0: + return False, f"T value ({t_value}) has leading zeros." + if T_int != float(t_value): + return False, f"T value ({t_value}) is not an integer." + + # Convert to bitmap and verify bit 0 is clear + if T_int & 1 == 0: + return True, f"T value ({t_value}) is valid and bit 0 is clear." + else: + return False, f"Bit 0 is not clear. T value ({t_value})" + except ValueError: + return False, f"T value ({t_value}) is not a valid integer" + + @staticmethod + def is_ipv6_address(addresses): + if isinstance(addresses, str): + addresses = [addresses] + + for address in addresses: + try: + # Attempt to create an IPv6 address object. If successful, this is an IPv6 address. + ipaddress.IPv6Address(address) + return True, "At least one IPv6 address is present." + except ipaddress.AddressValueError: + # If an AddressValueError is raised, the current address is not a valid IPv6 address. + return False, f"Invalid IPv6 address encountered: {address}, provided addresses: {addresses}" + return False, "No IPv6 addresses found." + + @staticmethod + def extract_ipv6_address(text): + items = text.split(',') + return items[-1] + + @staticmethod + def verify_hostname(hostname: str) -> bool: + # Remove any trailing dot + if hostname.endswith('.'): + hostname = hostname[:-1] + + # Remove '.local' suffix if present + if hostname.endswith('.local'): + hostname = hostname[:-6] + + # Regular expression to match an uppercase hexadecimal string of 12 or 16 characters + pattern = re.compile(r'^[0-9A-F]{12}$|^[0-9A-F]{16}$') + return bool(pattern.match(hostname)) + + @async_test_body + async def test_TC_SC_4_3(self): + supports_icd = None + supports_lit = None + active_mode_threshold_ms = None + instance_name = None + + # *** STEP 1 *** + # DUT is commissioned on the same fabric as TH. + self.step(1) + + # *** STEP 2 *** + # TH reads from the DUT the ServerList attribute from the Descriptor cluster on EP0. If the ICD Management + # cluster ID (70,0x46) is present in the list, set supports_icd to true, otherwise set supports_icd to false. + self.step(2) + ep0_servers = await self.get_descriptor_server_list() + + # Check if ep0_servers contain the ICD Management cluster ID (0x0046) + supports_icd = Clusters.IcdManagement.id in ep0_servers + logging.info(f"supports_icd: {supports_icd}") + + # *** STEP 3 *** + # If supports_icd is true, TH reads ActiveModeThreshold from the ICD Management cluster on EP0 and saves + # as active_mode_threshold. + self.step(3) + if supports_icd: + active_mode_threshold_ms = await self.get_idle_mode_threshhold_ms() + logging.info(f"active_mode_threshold_ms: {active_mode_threshold_ms}") + + # *** STEP 4 *** + # If supports_icd is true, TH reads FeatureMap from the ICD Management cluster on EP0. If the LITS feature + # is set, set supports_lit to true. Otherwise set supports_lit to false. + self.step(4) + if supports_icd: + feature_map = await self.get_icd_feature_map() + LITS = Clusters.IcdManagement.Bitmaps.Feature.kLongIdleTimeSupport + supports_lit = bool(feature_map & LITS == LITS) + logging.info(f"kLongIdleTimeSupport set: {supports_lit}") + + # *** STEP 5 *** + # TH constructs the instance name for the DUT as the 64-bit compressed Fabric identifier, and the + # assigned 64-bit Node identifier, each expressed as a fixed-length sixteen-character hexadecimal + # string, encoded as ASCII (UTF-8) text using capital letters, separated by a hyphen. + self.step(5) + instance_name = self.get_dut_instance_name() + instance_qname = f"{instance_name}.{MdnsServiceType.OPERATIONAL.value}" + + # *** STEP 6 *** + # TH performs a query for the SRV record against the qname instance_qname. + # Verify SRV record is returned + self.step(6) + mdns = MdnsDiscovery() + operational_record = await mdns.get_service_by_record_type( + service_name=instance_qname, + service_type=MdnsServiceType.OPERATIONAL.value, + record_type=DNSRecordType.SRV, + log_output=True + ) + + # Will be used in Step 8 and 11 + # This is the hostname + hostname = operational_record.server + + # Verify SRV record is returned + srv_record_returned = operational_record is not None and operational_record.service_name == instance_qname + asserts.assert_true(srv_record_returned, "SRV record was not returned") + + # *** STEP 7 *** + # TH performs a query for the TXT record against the qname instance_qname. + # Verify TXT record is returned + self.step(7) + operational_record = await mdns.get_service_by_record_type( + service_name=instance_qname, + service_type=MdnsServiceType.OPERATIONAL.value, + record_type=DNSRecordType.TXT, + log_output=True + ) + + # Verify TXT record is returned and it contains values + txt_record_returned = operational_record.txt_record is not None and bool(operational_record.txt_record) + asserts.assert_true(txt_record_returned, "TXT record not returned or contains no values") + + # *** STEP 8 *** + # TH performs a query for the AAAA record against the target listed in the SRV record. + # Verify AAAA record is returned + self.step(8) + + quada_record = await mdns.get_service_by_record_type( + service_name=hostname, + service_type=MdnsServiceType.OPERATIONAL.value, + record_type=DNSRecordType.AAAA, + log_output=True + ) + + answer_record_type = quada_record.get_type(quada_record.type) + quada_record_type = _TYPES[_TYPE_AAAA] + + # Verify AAAA record is returned + asserts.assert_equal(hostname, quada_record.name, f"Server name mismatch: {hostname} vs {quada_record.name}") + asserts.assert_equal(quada_record_type, answer_record_type, + f"Record type should be {quada_record_type} but got {answer_record_type}") + + # # *** STEP 9 *** + # TH verifies the following from the returned records: The hostname must be a fixed-length twelve-character (or sixteen-character) + # hexadecimal string, encoded as ASCII (UTF-8) text using capital letters.. ICD TXT key: • If supports_lit is false, verify that the + # ICD key is NOT present in the TXT record • If supports_lit is true, verify the ICD key IS present in the TXT record, and it has the + # value of 0 or 1 (ASCII) SII TXT key: • If supports_icd is true and supports_lit is false, set sit_mode to true • If supports_icd is + # true and supports_lit is true, set sit_mode to true if ICD=0 otherwise set sit_mode to false • If supports_icd is false, set + # sit_mode to false • If sit_mode is true, verify that the SII key IS present in the TXT record • if the SII key is present, verify + # it is a decimal value with no leading zeros and is less than or equal to 3600000 (1h in ms) SAI TXT key: • if supports_icd is true, + # verify that the SAI key is present in the TXT record • If the SAI key is present, verify it is a decimal value with no leading + # zeros and is less than or equal to 3600000 (1h in ms) + self.step(9) + + # Verify hostname character length (12 or 16) + asserts.assert_true(self.verify_hostname(hostname=hostname), + f"Hostname for '{hostname}' is not a 12 or 16 character uppercase hexadecimal string") + + # ICD TXT KEY + if supports_lit: + logging.info("supports_lit is true, verify the ICD key IS present in the TXT record, and it has the value of 0 or 1 (ASCII).") + + # Verify the ICD key IS present + asserts.assert_in('ICD', operational_record.txt_record, "ICD key is NOT present in the TXT record.") + + # Verify it has the value of 0 or 1 (ASCII) + icd_value = int(operational_record.txt_record['ICD']) + asserts.assert_true(icd_value == 0 or icd_value == 1, "ICD value is different than 0 or 1 (ASCII).") + else: + logging.info("supports_lit is false, verify that the ICD key is NOT present in the TXT record.") + asserts.assert_not_in('ICD', operational_record.txt_record, "ICD key is present in the TXT record.") + + # SII TXT KEY + if supports_icd and not supports_lit: + sit_mode = True + + if supports_icd and supports_lit: + if icd_value == 0: + sit_mode = True + else: + sit_mode = False + + if not supports_icd: + sit_mode = False + + if sit_mode: + logging.info("sit_mode is True, verify the SII key IS present.") + asserts.assert_in('SII', operational_record.txt_record, "SII key is NOT present in the TXT record.") + + logging.info("Verify SII value is a decimal with no leading zeros and is less than or equal to 3600000 (1h in ms).") + sii_value = operational_record.txt_record['SII'] + result, message = self.verify_decimal_value(sii_value, self.ONE_HOUR_IN_MS) + asserts.assert_true(result, message) + + # SAI TXT KEY + if supports_icd: + logging.info("supports_icd is True, verify the SAI key IS present.") + asserts.assert_in('SAI', operational_record.txt_record, "SAI key is NOT present in the TXT record.") + + logging.info("Verify SAI value is a decimal with no leading zeros and is less than or equal to 3600000 (1h in ms).") + sai_value = operational_record.txt_record['SAI'] + result, message = self.verify_decimal_value(sai_value, self.ONE_HOUR_IN_MS) + asserts.assert_true(result, message) + + # SAT TXT KEY + if 'SAT' in operational_record.txt_record: + logging.info( + "SAT key is present in TXT record, verify that it is a decimal value with no leading zeros and is less than or equal to 65535.") + sat_value = operational_record.txt_record['SAT'] + result, message = self.verify_decimal_value(sat_value, self.MAX_SAT_VALUE) + asserts.assert_true(result, message) + + if supports_icd: + logging.info("supports_icd is True, verify the SAT value is equal to active_mode_threshold.") + asserts.assert_equal(int(sat_value), active_mode_threshold_ms) + + # T TXT KEY + if 'T' in operational_record.txt_record: + logging.info("T key is present in TXT record, verify if that it is a decimal value with no leading zeros and is less than or equal to 6. Convert the value to a bitmap and verify bit 0 is clear.") + t_value = operational_record.txt_record['T'] + result, message = self.verify_t_value(t_value) + asserts.assert_true(result, message) + + # AAAA + logging.info("Verify the AAAA record contains at least one IPv6 address") + ipv6_address = self.extract_ipv6_address(str(quada_record)) + result, message = self.is_ipv6_address(ipv6_address) + asserts.assert_true(result, message) + + # # *** STEP 10 *** + # TH performs a DNS-SD browse for _I._sub._matter._tcp.local, where is the 64-bit compressed + # Fabric identifier, expressed as a fixed-length, sixteencharacter hexadecimal string, encoded as ASCII (UTF-8) + # text using capital letters. Verify DUT returns a PTR record with DNS-SD instance name set to instance_name + self.step(10) + service_types = await mdns.get_service_types(log_output=True) + op_sub_type = self.get_operational_subtype() + asserts.assert_in(op_sub_type, service_types, f"No PTR record with DNS-SD instance name '{op_sub_type}' wsa found.") + + # # *** STEP 11 *** + # TH performs a DNS-SD browse for _matter._tcp.local + # Verify DUT returns a PTR record with DNS-SD instance name set to instance_name + self.step(11) + op_service_info = await mdns._get_service( + service_type=MdnsServiceType.OPERATIONAL, + log_output=True, + discovery_timeout_sec=15 + ) + + # Verify DUT returns a PTR record with DNS-SD instance name set instance_name + asserts.assert_equal(op_service_info.server, hostname, + f"No PTR record with DNS-SD instance name '{MdnsServiceType.OPERATIONAL.value}'") + asserts.assert_equal(instance_name, op_service_info.instance_name, "Instance name mismatch") + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/mdns_discovery/mdns_async_service_info.py b/src/python_testing/mdns_discovery/mdns_async_service_info.py new file mode 100644 index 00000000000000..61d1dc73ebcb04 --- /dev/null +++ b/src/python_testing/mdns_discovery/mdns_async_service_info.py @@ -0,0 +1,135 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +import enum +from random import randint +from typing import TYPE_CHECKING, Optional + +from zeroconf import (BadTypeInNameException, DNSOutgoing, DNSQuestion, DNSQuestionType, ServiceInfo, Zeroconf, current_time_millis, + service_type_name) +from zeroconf.const import (_CLASS_IN, _DUPLICATE_QUESTION_INTERVAL, _FLAGS_QR_QUERY, _LISTENER_TIME, _MDNS_PORT, _TYPE_A, + _TYPE_AAAA, _TYPE_SRV, _TYPE_TXT) + +_AVOID_SYNC_DELAY_RANDOM_INTERVAL = (20, 120) + + +@enum.unique +class DNSRecordType(enum.Enum): + """An MDNS record type. + + "A" - A MDNS record type + "AAAA" - AAAA MDNS record type + "SRV" - SRV MDNS record type + "TXT" - TXT MDNS record type + """ + + A = 0 + AAAA = 1 + SRV = 2 + TXT = 3 + + +class MdnsAsyncServiceInfo(ServiceInfo): + def __init__(self, name: str, type_: str) -> None: + super().__init__(type_=type_, name=name) + + if type_ and not type_.endswith(service_type_name(name, strict=False)): + raise BadTypeInNameException + + self._name = name + self.type = type_ + self.key = name.lower() + + async def async_request( + self, + zc: Zeroconf, + timeout: float, + question_type: Optional[DNSQuestionType] = None, + addr: Optional[str] = None, + port: int = _MDNS_PORT, + record_type: DNSRecordType = None + ) -> bool: + """Returns true if the service could be discovered on the + network, and updates this object with details discovered. + + This method will be run in the event loop. + + Passing addr and port is optional, and will default to the + mDNS multicast address and port. This is useful for directing + requests to a specific host that may be able to respond across + subnets. + """ + if not zc.started: + await zc.async_wait_for_start() + + now = current_time_millis() + + if TYPE_CHECKING: + assert zc.loop is not None + + first_request = True + delay = _LISTENER_TIME + next_ = now + last = now + timeout + try: + zc.async_add_listener(self, None) + while not self._is_complete: + if last <= now: + return False + if next_ <= now: + this_question_type = question_type or DNSQuestionType.QU if first_request else DNSQuestionType.QM + out: DNSOutgoing = self._generate_request_query(this_question_type, record_type) + first_request = False + + if out.questions: + zc.async_send(out, addr, port) + next_ = now + delay + next_ += randint(*_AVOID_SYNC_DELAY_RANDOM_INTERVAL) + + if this_question_type is DNSQuestionType.QM and delay < _DUPLICATE_QUESTION_INTERVAL: + delay = _DUPLICATE_QUESTION_INTERVAL + + await self.async_wait(min(next_, last) - now, zc.loop) + now = current_time_millis() + finally: + zc.async_remove_listener(self) + + return True + + def _generate_request_query(self, question_type: DNSQuestionType, record_type: DNSRecordType) -> DNSOutgoing: + """Generate the request query.""" + out = DNSOutgoing(_FLAGS_QR_QUERY) + name = self._name + qu_question = question_type is DNSQuestionType.QU + + record_types = { + DNSRecordType.SRV: (_TYPE_SRV, "Requesting MDNS SRV record..."), + DNSRecordType.TXT: (_TYPE_TXT, "Requesting MDNS TXT record..."), + DNSRecordType.A: (_TYPE_A, "Requesting MDNS A record..."), + DNSRecordType.AAAA: (_TYPE_AAAA, "Requesting MDNS AAAA record..."), + } + + # Iterate over record types, add question uppon match + for r_type, (type_const, message) in record_types.items(): + if record_type is None or record_type == r_type: + print(message) + question = DNSQuestion(name, type_const, _CLASS_IN) + question.unicast = qu_question + out.add_question(question) + + return out diff --git a/src/python_testing/mdns_discovery/mdns_discovery.py b/src/python_testing/mdns_discovery/mdns_discovery.py index f8c9d46d70760a..2d7337b622a536 100644 --- a/src/python_testing/mdns_discovery/mdns_discovery.py +++ b/src/python_testing/mdns_discovery/mdns_discovery.py @@ -15,15 +15,19 @@ # limitations under the License. # - import asyncio import json import logging from dataclasses import asdict, dataclass from enum import Enum -from typing import Dict, List, Optional - -from zeroconf import IPVersion, ServiceStateChange, Zeroconf +from time import sleep +from typing import Dict, List, Optional, Union, cast + +from mdns_discovery.mdns_async_service_info import DNSRecordType, MdnsAsyncServiceInfo +from zeroconf import IPVersion, ServiceListener, ServiceStateChange, Zeroconf +from zeroconf._dns import DNSRecord +from zeroconf._engine import AsyncListener +from zeroconf._protocol.incoming import DNSIncoming from zeroconf.asyncio import AsyncServiceBrowser, AsyncServiceInfo, AsyncZeroconfServiceTypes logger = logging.getLogger(__name__) @@ -34,9 +38,6 @@ class MdnsServiceInfo: # The unique name of the mDNS service. service_name: str - # The service type of the service, typically indicating the service protocol and domain. - service_type: str - # The instance name of the service. instance_name: str @@ -67,6 +68,9 @@ class MdnsServiceInfo: # The time-to-live value for other records associated with the service. other_ttl: int + # The service type of the service, typically indicating the service protocol and domain. + service_type: Optional[str] = None + class MdnsServiceType(Enum): """ @@ -78,6 +82,25 @@ class MdnsServiceType(Enum): BORDER_ROUTER = "_meshcop._udp.local." +class MdnsServiceListener(ServiceListener): + """ + A service listener required during mDNS service discovery + """ + + def __init__(self): + self.updated_event = asyncio.Event() + + def add_service(self, zeroconf: Zeroconf, service_type: str, name: str) -> None: + sleep(0.125) + self.updated_event.set() + + def remove_service(self, zeroconf: Zeroconf, service_type: str, name: str) -> None: + pass + + def update_service(self, zeroconf: Zeroconf, service_type: str, name: str) -> None: + self.updated_event.set() + + class MdnsDiscovery: DISCOVERY_TIMEOUT_SEC = 15 @@ -118,7 +141,7 @@ async def get_commissioner_service(self, log_output: bool = False, """ Asynchronously discovers a commissioner mDNS service within the network. - Args: + Optional args: log_output (bool): Logs the discovered services to the console. Defaults to False. discovery_timeout_sec (float): Defaults to 15 seconds. @@ -134,7 +157,7 @@ async def get_commissionable_service(self, log_output: bool = False, """ Asynchronously discovers a commissionable mDNS service within the network. - Args: + Optional args: log_output (bool): Logs the discovered services to the console. Defaults to False. discovery_timeout_sec (float): Defaults to 15 seconds. @@ -153,16 +176,19 @@ async def get_operational_service(self, """ Asynchronously discovers an operational mDNS service within the network. - Args: + Optional args: log_output (bool): Logs the discovered services to the console. Defaults to False. discovery_timeout_sec (float): Defaults to 15 seconds. - node_id: the node id to create the service name from - compressed_fabric_id: the fabric id to create the service name from + node_id: the node id to create the service name from + compressed_fabric_id: the fabric id to create the service name from Returns: Optional[MdnsServiceInfo]: An instance of MdnsServiceInfo or None if timeout reached. """ - # Validation to ensure both or none of the parameters are provided + + # Validation to ensure that both node_id and compressed_fabric_id are provided or both are None. + if (node_id is None) != (compressed_fabric_id is None): + raise ValueError("Both node_id and compressed_fabric_id must be provided together or not at all.") self._name_filter = f'{compressed_fabric_id:016x}-{node_id:016x}.{MdnsServiceType.OPERATIONAL.value}'.upper() return await self._get_service(MdnsServiceType.OPERATIONAL, log_output, discovery_timeout_sec) @@ -173,7 +199,7 @@ async def get_border_router_service(self, log_output: bool = False, """ Asynchronously discovers a border router mDNS service within the network. - Args: + Optional args: log_output (bool): Logs the discovered services to the console. Defaults to False. discovery_timeout_sec (float): Defaults to 15 seconds. @@ -188,7 +214,7 @@ async def get_all_services(self, log_output: bool = False, """ Asynchronously discovers all available mDNS services within the network. - Args: + Optional args: log_output (bool): Logs the discovered services to the console. Defaults to False. discovery_timeout_sec (float): Defaults to 15 seconds. @@ -200,6 +226,114 @@ async def get_all_services(self, log_output: bool = False, return self._discovered_services + async def get_service_types(self, log_output: bool = False, discovery_timeout_sec: float = DISCOVERY_TIMEOUT_SEC,) -> List[str]: + """ + Asynchronously discovers all available mDNS services within the network and returns a list + of the service types discovered. This method utilizes the AsyncZeroconfServiceTypes.async_find() + function to perform the network scan for mDNS services. + + Optional args: + log_output (bool): If set to True, the discovered service types are logged to the console. + This can be useful for debugging or informational purposes. Defaults to False. + discovery_timeout_sec (float): The maximum time (in seconds) to wait for the discovery process. Defaults to 10.0 seconds. + + Returns: + List[str]: A list containing the service types (str) of the discovered mDNS services. Each + element in the list is a string representing a unique type of service found during + the discovery process. + """ + try: + discovered_services = list(await asyncio.wait_for(AsyncZeroconfServiceTypes.async_find(), timeout=discovery_timeout_sec)) + except asyncio.TimeoutError: + logger.info(f"MDNS service types discovery timed out after {discovery_timeout_sec} seconds.") + discovered_services = [] + + if log_output: + logger.info(f"MDNS discovered service types: {discovered_services}") + + return discovered_services + + async def get_service_by_record_type(self, service_name: str, + record_type: DNSRecordType, + service_type: str = None, + discovery_timeout_sec: float = DISCOVERY_TIMEOUT_SEC, + log_output: bool = False + ) -> Union[Optional[MdnsServiceInfo], Optional[DNSRecord]]: + """ + Asynchronously discovers an mDNS service within the network by service name, service type, + and record type. + + Required args: + service_name (str): The unique name of the mDNS service. + Example: + C82B83803DECA0B2-0000000012344321._matter._tcp.local. + + record_type (DNSRecordType): The type of record to look for (SRV, TXT, AAAA, A). + Example: + _matterd._tcp.local. (from the MdnsServiceType enum) + + Optional args: + service_type (str): The service type of the service. Defaults to None. + log_output (bool): Logs the discovered services to the console. Defaults to False. + discovery_timeout_sec (float): Defaults to 15 seconds. + + Returns: + Union[Optional[MdnsServiceInfo], Optional[DNSRecord]]: An instance of MdnsServiceInfo, + a DNSRecord object, or None. + """ + mdns_service_info = None + + if service_type: + logger.info( + f"\nLooking for MDNS service type '{service_type}', service name '{service_name}', record type '{record_type.name}'\n") + else: + logger.info( + f"\nLooking for MDNS service with service name '{service_name}', record type '{record_type.name}'\n") + + # Adds service listener + service_listener = MdnsServiceListener() + self._zc.add_service_listener(MdnsServiceType.OPERATIONAL.value, service_listener) + + # Wait for the add/update service event or timeout + try: + await asyncio.wait_for(service_listener.updated_event.wait(), discovery_timeout_sec) + except asyncio.TimeoutError: + logger.info(f"Service lookup for {service_name} timeout ({discovery_timeout_sec}) reached without an update.") + finally: + self._zc.remove_service_listener(service_listener) + + # Prepare and perform query + service_info = MdnsAsyncServiceInfo(name=service_name, type_=service_type) + is_discovered = await service_info.async_request( + self._zc, + 3000, + record_type=record_type) + + if record_type in [DNSRecordType.A, DNSRecordType.AAAA]: + # Service type not supplied so we can + # query against the target/server + for protocols in self._zc.engine.protocols: + listener = cast(AsyncListener, protocols) + if listener.data: + dns_incoming = DNSIncoming(listener.data) + if dns_incoming.data: + answers = dns_incoming.answers() + logger.info(f"\nIncoming DNSRecord: {answers}\n") + return answers.pop(0) if answers else None + else: + # Adds service to discovered services + if is_discovered: + mdns_service_info = self._to_mdns_service_info_class(service_info) + self._discovered_services = {} + self._discovered_services[service_type] = [] + if mdns_service_info is not None: + self._discovered_services[service_type].append(mdns_service_info) + + if log_output: + self._log_output() + + return mdns_service_info + # Private methods async def _discover(self, discovery_timeout_sec: float, @@ -228,7 +362,7 @@ async def _discover(self, self._event.clear() if all_services: - self._service_types = list(await AsyncZeroconfServiceTypes.async_find()) + self._service_types = list(set(await AsyncZeroconfServiceTypes.async_find())) logger.info(f"Browsing for MDNS service(s) of type: {self._service_types}") @@ -315,8 +449,9 @@ async def _query_service_info(self, zeroconf: Zeroconf, service_type: str, servi mdns_service_info = self._to_mdns_service_info_class(service_info) if service_type not in self._discovered_services: - self._discovered_services[service_type] = [mdns_service_info] - else: + self._discovered_services[service_type] = [] + + if mdns_service_info is not None: self._discovered_services[service_type].append(mdns_service_info) elif self._verbose_logging: logger.warning("Service information not found.") @@ -336,7 +471,7 @@ def _to_mdns_service_info_class(self, service_info: AsyncServiceInfo) -> MdnsSer mdns_service_info = MdnsServiceInfo( service_name=service_info.name, service_type=service_info.type, - instance_name=service_info.get_name(), + instance_name=self._get_instance_name(service_info), server=service_info.server, port=service_info.port, addresses=service_info.parsed_addresses(), @@ -350,6 +485,12 @@ def _to_mdns_service_info_class(self, service_info: AsyncServiceInfo) -> MdnsSer return mdns_service_info + def _get_instance_name(self, service_info: AsyncServiceInfo) -> str: + if service_info.type: + return service_info.name[: len(service_info.name) - len(service_info.type) - 1] + else: + return service_info.name + async def _get_service(self, service_type: MdnsServiceType, log_output: bool, discovery_timeout_sec: float @@ -380,7 +521,7 @@ async def _get_service(self, service_type: MdnsServiceType, def _log_output(self) -> str: """ - Converts the discovered services to a JSON string and log it. + Converts the discovered services to a JSON string and logs it. The method is intended to be used for debugging or informational purposes, providing a clear and comprehensive view of all services discovered during the mDNS service discovery process. diff --git a/src/python_testing/mdns_discovery/mdns_service_type_enum.py b/src/python_testing/mdns_discovery/mdns_service_type_enum.py deleted file mode 100644 index efd77ca3beef5c..00000000000000 --- a/src/python_testing/mdns_discovery/mdns_service_type_enum.py +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2024 Project CHIP Authors -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -from enum import Enum - - -class MdnsServiceType(Enum): - COMMISSIONER = "_matterd._udp.local." - COMMISSIONABLE = "_matterc._udp.local." - OPERATIONAL = "_matter._tcp.local." - BORDER_ROUTER = "_meshcop._udp.local." From 2c6c421db07460d2878be4f7ccc29d470e1278ce Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 17 Dec 2024 13:38:08 -0500 Subject: [PATCH 16/19] Make AddressResolver not keep duplicate IP addresses in its cache (#36861) * Add FAILING unit test that address resolve does dedup of inputs * Unit tests pass, but code is not YET complete * Tests still pass... * Update comments * Restyle * Include fix * Restyled by clang-format * Enforce more lookup results... this makes tests happy and also it sounds like just picking a single address by default is a bit low * Fix casts * Apparently adding mdns results increases RAM a lot and esp32 m5 does not have sufficient space. This is a bit concerning ... * Fix condition that I messed up * Update non-LL interface for the dedup logic as well * Fix includes * Fix typo * moved a bit the test guard: we have 2 tests that need 3 slots and more --------- Co-authored-by: Restyled.io Co-authored-by: Andrei Litvin --- .../AddressResolve_DefaultImpl.cpp | 39 +++-- .../tests/TestAddressResolve_DefaultImpl.cpp | 150 +++++++++++++++++- 2 files changed, 170 insertions(+), 19 deletions(-) diff --git a/src/lib/address_resolve/AddressResolve_DefaultImpl.cpp b/src/lib/address_resolve/AddressResolve_DefaultImpl.cpp index 2fc4e5a526fb65..4b60bbf6e59f28 100644 --- a/src/lib/address_resolve/AddressResolve_DefaultImpl.cpp +++ b/src/lib/address_resolve/AddressResolve_DefaultImpl.cpp @@ -19,6 +19,7 @@ #include #include +#include namespace chip { namespace AddressResolve { @@ -128,6 +129,17 @@ NodeLookupAction NodeLookupHandle::NextAction(System::Clock::Timestamp now) bool NodeLookupResults::UpdateResults(const ResolveResult & result, const Dnssd::IPAddressSorter::IpScore newScore) { + Transport::PeerAddress addressWithAdjustedInterface = result.address; + if (!addressWithAdjustedInterface.GetIPAddress().IsIPv6LinkLocal()) + { + // Only use the DNS-SD resolution's InterfaceID for addresses that are IPv6 LLA. + // For all other addresses, we should rely on the device's routing table to route messages sent. + // Forcing messages down an InterfaceId might fail. For example, in bridged networks like Thread, + // mDNS advertisements are not usually received on the same interface the peer is reachable on. + addressWithAdjustedInterface.SetInterface(Inet::InterfaceId::Null()); + ChipLogDetail(Discovery, "Lookup clearing interface for non LL address"); + } + uint8_t insertAtIndex = 0; for (; insertAtIndex < kNodeLookupResultsLen; insertAtIndex++) { @@ -138,7 +150,14 @@ bool NodeLookupResults::UpdateResults(const ResolveResult & result, const Dnssd: } auto & oldAddress = results[insertAtIndex].address; - auto oldScore = Dnssd::IPAddressSorter::ScoreIpAddress(oldAddress.GetIPAddress(), oldAddress.GetInterface()); + + if (oldAddress == addressWithAdjustedInterface) + { + // this address is already in our list. + return false; + } + + auto oldScore = Dnssd::IPAddressSorter::ScoreIpAddress(oldAddress.GetIPAddress(), oldAddress.GetInterface()); if (newScore > oldScore) { // This is a score update, it will replace a previous entry. @@ -151,6 +170,10 @@ bool NodeLookupResults::UpdateResults(const ResolveResult & result, const Dnssd: return false; } + // we are guaranteed no duplicates here: + // - insertAtIndex MUST be with some score that is `< newScore`, so all + // addresses with a `newScore` were duplicate-checked + // Move the following valid entries one level down. for (auto i = count; i > insertAtIndex; i--) { @@ -168,17 +191,9 @@ bool NodeLookupResults::UpdateResults(const ResolveResult & result, const Dnssd: count++; } - auto & updatedResult = results[insertAtIndex]; - updatedResult = result; - if (!updatedResult.address.GetIPAddress().IsIPv6LinkLocal()) - { - // Only use the DNS-SD resolution's InterfaceID for addresses that are IPv6 LLA. - // For all other addresses, we should rely on the device's routing table to route messages sent. - // Forcing messages down an InterfaceId might fail. For example, in bridged networks like Thread, - // mDNS advertisements are not usually received on the same interface the peer is reachable on. - updatedResult.address.SetInterface(Inet::InterfaceId::Null()); - ChipLogDetail(Discovery, "Lookup clearing interface for non LL address"); - } + auto & updatedResult = results[insertAtIndex]; + updatedResult = result; + updatedResult.address = addressWithAdjustedInterface; return true; } diff --git a/src/lib/address_resolve/tests/TestAddressResolve_DefaultImpl.cpp b/src/lib/address_resolve/tests/TestAddressResolve_DefaultImpl.cpp index 266939fa3f5d3b..7099414bce05a1 100644 --- a/src/lib/address_resolve/tests/TestAddressResolve_DefaultImpl.cpp +++ b/src/lib/address_resolve/tests/TestAddressResolve_DefaultImpl.cpp @@ -18,10 +18,25 @@ #include #include +#include +#include +#include using namespace chip; using namespace chip::AddressResolve; +namespace pw { + +template <> +StatusWithSize ToString(const Transport::PeerAddress & addr, pw::span buffer) +{ + char buff[Transport::PeerAddress::kMaxToStringSize]; + addr.ToString(buff); + return pw::string::Format(buffer, "IP<%s>", buff); +} + +} // namespace pw + namespace { using chip::Dnssd::IPAddressSorter::IpScore; @@ -29,13 +44,34 @@ using chip::Dnssd::IPAddressSorter::ScoreIpAddress; constexpr uint8_t kNumberOfAvailableSlots = CHIP_CONFIG_MDNS_RESOLVE_LOOKUP_RESULTS; -Transport::PeerAddress GetAddressWithLowScore(uint16_t port = CHIP_PORT, Inet::InterfaceId interfaceId = Inet::InterfaceId::Null()) +/// Get an address that should have `kUniqueLocal` (one of the lowest) priority. +/// +/// Since for various tests we check filling the cache with values, we allow +/// unique address generation by varying the `idx` parameter +/// +/// @param idx - a value to generate a unique IP address (in case we do not want dedups to happen) +/// @param port - port in case some tests would like to vary it. Required for PeerAddress +/// @param interfaceId - interface required for PeerAddress +Transport::PeerAddress GetAddressWithLowScore(uint16_t idx = 4, uint16_t port = CHIP_PORT, + Inet::InterfaceId interfaceId = Inet::InterfaceId::Null()) { // Unique Local - expect score "3" Inet::IPAddress ipAddress; - if (!Inet::IPAddress::FromString("fdff:aabb:ccdd:1::4", ipAddress)) + + auto high = static_cast(idx >> 8); + auto low = static_cast(idx & 0xFF); + + StringBuilder<64> address; + address.Add("fdff:aabb:ccdd:1::"); + if (high != 0) { - ChipLogError(NotSpecified, "!!!!!!!! IP Parse failure"); + address.AddFormat("%x:", high); + } + address.AddFormat("%x", low); + + if (!Inet::IPAddress::FromString(address.c_str(), ipAddress)) + { + ChipLogError(NotSpecified, "!!!!!!!! IP Parse failure for %s", address.c_str()); } return Transport::PeerAddress::UDP(ipAddress, port, interfaceId); } @@ -66,8 +102,60 @@ Transport::PeerAddress GetAddressWithHighScore(uint16_t port = CHIP_PORT, Inet:: return Transport::PeerAddress::UDP(ipAddress, port, interfaceId); } -TEST(TestAddressResolveDefaultImpl, TestLookupResult) +#if CHIP_CONFIG_MDNS_RESOLVE_LOOKUP_RESULTS >= 3 + +// test requires at least 3 slots: for high, medium and low +TEST(TestAddressResolveDefaultImpl, UpdateResultsDoesNotAddDuplicatesWhenFull) +{ + Impl::NodeLookupResults results; + ASSERT_EQ(results.count, 0); + + for (auto i = 0; i < kNumberOfAvailableSlots; i++) + { + ResolveResult result; + result.address = GetAddressWithLowScore(static_cast(i + 10)); + ASSERT_TRUE(results.UpdateResults(result, Dnssd::IPAddressSorter::IpScore::kUniqueLocal)); + } + ASSERT_EQ(results.count, kNumberOfAvailableSlots); + + // Adding another one should fail as there is no more room + ResolveResult result; + result.address = GetAddressWithLowScore(static_cast(5)); + ASSERT_FALSE(results.UpdateResults(result, Dnssd::IPAddressSorter::IpScore::kUniqueLocal)); + ASSERT_EQ(results.count, kNumberOfAvailableSlots); + + // however one with higher priority should work + result.address = GetAddressWithHighScore(); + ASSERT_TRUE(results.UpdateResults(result, Dnssd::IPAddressSorter::IpScore::kGlobalUnicast)); + ASSERT_EQ(results.count, kNumberOfAvailableSlots); + + // however not duplicate + ASSERT_FALSE(results.UpdateResults(result, Dnssd::IPAddressSorter::IpScore::kGlobalUnicast)); + ASSERT_EQ(results.count, kNumberOfAvailableSlots); + + // another higher priority one + result.address = GetAddressWithMediumScore(); + ASSERT_TRUE(results.UpdateResults(result, Dnssd::IPAddressSorter::IpScore::kLinkLocal)); + ASSERT_EQ(results.count, kNumberOfAvailableSlots); + + // however not duplicate + ASSERT_FALSE(results.UpdateResults(result, Dnssd::IPAddressSorter::IpScore::kLinkLocal)); + ASSERT_EQ(results.count, kNumberOfAvailableSlots); +} + +// test requires at least 3 slots: for high, medium and low +TEST(TestAddressResolveDefaultImpl, UpdateResultsDoesNotAddDuplicates) { + static_assert(Impl::kNodeLookupResultsLen >= 3, "Test uses 3 address slots"); + + Impl::NodeLookupResults results; + ASSERT_EQ(results.count, 0); + + // The order below is VERY explicit to test both before and after inserts + // - low first + // - high (to be before low) + // - medium (to be after high, even though before low) + ResolveResult lowResult; lowResult.address = GetAddressWithLowScore(); @@ -77,6 +165,49 @@ TEST(TestAddressResolveDefaultImpl, TestLookupResult) ResolveResult highResult; highResult.address = GetAddressWithHighScore(); + results.UpdateResults(lowResult, Dnssd::IPAddressSorter::IpScore::kUniqueLocal); + ASSERT_EQ(results.count, 1); + + // same address again. we should not actually insert it! + results.UpdateResults(lowResult, Dnssd::IPAddressSorter::IpScore::kUniqueLocal); + ASSERT_EQ(results.count, 1); + + // we CAN insert a different one + results.UpdateResults(highResult, Dnssd::IPAddressSorter::IpScore::kGlobalUnicast); + ASSERT_EQ(results.count, 2); + + // extra insertions of the same address should NOT make a difference + results.UpdateResults(lowResult, Dnssd::IPAddressSorter::IpScore::kUniqueLocal); + ASSERT_EQ(results.count, 2); + results.UpdateResults(highResult, Dnssd::IPAddressSorter::IpScore::kGlobalUnicast); + ASSERT_EQ(results.count, 2); + + // we CAN insert a different one + results.UpdateResults(mediumResult, Dnssd::IPAddressSorter::IpScore::kLinkLocal); + ASSERT_EQ(results.count, 3); + + // re-insertin any of these should not make a difference + results.UpdateResults(lowResult, Dnssd::IPAddressSorter::IpScore::kUniqueLocal); + ASSERT_EQ(results.count, 3); + results.UpdateResults(highResult, Dnssd::IPAddressSorter::IpScore::kGlobalUnicast); + ASSERT_EQ(results.count, 3); + results.UpdateResults(mediumResult, Dnssd::IPAddressSorter::IpScore::kLinkLocal); + ASSERT_EQ(results.count, 3); +} + +#endif + +TEST(TestAddressResolveDefaultImpl, TestLookupResult) +{ + ResolveResult lowResult; + lowResult.address = GetAddressWithLowScore(static_cast(1)); + + ResolveResult mediumResult; + mediumResult.address = GetAddressWithMediumScore(); + + ResolveResult highResult; + highResult.address = GetAddressWithHighScore(); + // Ensure test expectations regarding ordering is matched IpScore lowScore = ScoreIpAddress(lowResult.address.GetIPAddress(), Inet::InterfaceId::Null()); @@ -115,6 +246,8 @@ TEST(TestAddressResolveDefaultImpl, TestLookupResult) // Fill all the possible slots. for (auto i = 0; i < kNumberOfAvailableSlots; i++) { + // Set up UNIQUE addresses to not apply dedup here + lowResult.address = GetAddressWithLowScore(static_cast(i + 10)); handle.LookupResult(lowResult); } @@ -123,7 +256,7 @@ TEST(TestAddressResolveDefaultImpl, TestLookupResult) { EXPECT_TRUE(handle.HasLookupResult()); outResult = handle.TakeLookupResult(); - EXPECT_EQ(lowResult.address, outResult.address); + EXPECT_EQ(GetAddressWithLowScore(static_cast(i + 10)), outResult.address); } // Check that the results has been consumed properly. @@ -134,6 +267,7 @@ TEST(TestAddressResolveDefaultImpl, TestLookupResult) // Fill all the possible slots by giving it 2 times more results than the available slots. for (auto i = 0; i < kNumberOfAvailableSlots * 2; i++) { + lowResult.address = GetAddressWithLowScore(static_cast(i + 1000)); handle.LookupResult(lowResult); } @@ -142,7 +276,7 @@ TEST(TestAddressResolveDefaultImpl, TestLookupResult) { EXPECT_TRUE(handle.HasLookupResult()); outResult = handle.TakeLookupResult(); - EXPECT_EQ(lowResult.address, outResult.address); + EXPECT_EQ(GetAddressWithLowScore(static_cast(i + 1000)), outResult.address); } // Check that the results has been consumed properly. @@ -167,6 +301,7 @@ TEST(TestAddressResolveDefaultImpl, TestLookupResult) // Fill all the possible slots. for (auto i = 0; i < kNumberOfAvailableSlots; i++) { + lowResult.address = GetAddressWithLowScore(static_cast(i + 10)); handle.LookupResult(lowResult); } @@ -192,7 +327,8 @@ TEST(TestAddressResolveDefaultImpl, TestLookupResult) { EXPECT_TRUE(handle.HasLookupResult()); outResult = handle.TakeLookupResult(); - EXPECT_EQ(lowResult.address, outResult.address); + // - 2 because we start from 2 at the top for the high and medium slots + EXPECT_EQ(GetAddressWithLowScore(static_cast(i + 10 - 2)), outResult.address); } } From a9bd0ce94d0bb34a20b1fe59374b02d80cb78fb9 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Tue, 17 Dec 2024 11:26:26 -0800 Subject: [PATCH 17/19] Decouple InitDataModelHandler from libCHIP (#36725) * Decouple InitDataModelHandler from libCHIP * Use StartUp to init * Seperate namespace cleanup out * Mock function for linking * Restyled by clang-format * Add API comment * Fix mutiple defination conflicts * Address review comments * Restyled by whitespace * Seperate InitDataModel out * Revert "Seperate InitDataModel out" This reverts commit 5a8af59841ed4eb0bc573ba877d5ade7f31aa212. * Do not directly manipulate the base class's Startup method * Address review comment * Restyled by whitespace * Adjust the init order * Restyled by whitespace * Update src/app/server/Server.cpp Co-authored-by: Boris Zbarsky * Update src/controller/CHIPDeviceControllerFactory.cpp Co-authored-by: Boris Zbarsky * Add TODO comment * documented/named InitDataModel to make it clear that this is a temporary hack for a test --------- Co-authored-by: Restyled.io Co-authored-by: Boris Zbarsky --- src/app/server/Server.cpp | 30 ++++++++++--------- .../tests/TestCommissioningWindowManager.cpp | 3 -- src/app/tests/TestInteractionModelEngine.cpp | 2 +- src/app/tests/test-ember-api.cpp | 3 ++ .../CHIPDeviceControllerFactory.cpp | 10 ++----- .../tests/TestServerCommandDispatch.cpp | 18 +++++++++++ .../tests/data_model/DataModelFixtures.cpp | 3 ++ .../codegen/CodegenDataModelProvider.cpp | 9 ++++++ .../codegen/CodegenDataModelProvider.h | 6 ++++ .../tests/TestCodegenModelViaMocks.cpp | 3 ++ 10 files changed, 61 insertions(+), 26 deletions(-) diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index 4e0df666e36e47..2e4a10a452fa9e 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #if CONFIG_NETWORK_LAYER_BLE #include @@ -170,17 +169,6 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams) SuccessOrExit(err = mAttributePersister.Init(mDeviceStorage)); SetSafeAttributePersistenceProvider(&mAttributePersister); - // SetDataModelProvider() actually initializes/starts the provider. We need - // to preserve the following ordering guarantees: - // - // 1) Provider initialization (under SetDataModelProvider) happens after - // SetSafeAttributePersistenceProvider, since the provider can then use - // the safe persistence provider to implement and initialize its own attribute persistence logic. - // 2) For now, provider initialization happens before InitDataModelHandler(), which depends - // on atttribute persistence being already set up before it runs. Longer-term, the logic from - // InitDataModelHandler should just move into the codegen provider. - app::InteractionModelEngine::GetInstance()->SetDataModelProvider(initParams.dataModelProvider); - { FabricTable::InitParams fabricTableInitParams; fabricTableInitParams.storage = mDeviceStorage; @@ -302,8 +290,22 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams) } #endif // CHIP_CONFIG_ENABLE_SERVER_IM_EVENT - // This initializes clusters, so should come after lower level initialization. - InitDataModelHandler(); + // SetDataModelProvider() initializes and starts the provider, which in turn + // triggers the initialization of cluster implementations. This callsite is + // critical because it ensures that cluster-level initialization occurs only + // after all necessary low-level dependencies have been set up. + // + // Ordering guarantees: + // 1) Provider initialization (under SetDataModelProvider) must happen after + // SetSafeAttributePersistenceProvider to ensure the provider can leverage + // the safe persistence provider for attribute persistence logic. + // 2) It must occur after all low-level components that cluster implementations + // might depend on have been initialized, as they rely on these components + // during their own initialization. + // + // This remains the single point of entry to ensure that all cluster-level + // initialization is performed in the correct order. + app::InteractionModelEngine::GetInstance()->SetDataModelProvider(initParams.dataModelProvider); #if defined(CHIP_APP_USE_ECHO) err = InitEchoHandler(&mExchangeMgr); diff --git a/src/app/tests/TestCommissioningWindowManager.cpp b/src/app/tests/TestCommissioningWindowManager.cpp index 7d1e22626b29dd..1fe151107707ce 100644 --- a/src/app/tests/TestCommissioningWindowManager.cpp +++ b/src/app/tests/TestCommissioningWindowManager.cpp @@ -41,9 +41,6 @@ using chip::CommissioningWindowAdvertisement; using chip::CommissioningWindowManager; using chip::Server; -// Mock function for linking -void InitDataModelHandler() {} - namespace { bool sAdminFabricIndexDirty = false; bool sAdminVendorIdDirty = false; diff --git a/src/app/tests/TestInteractionModelEngine.cpp b/src/app/tests/TestInteractionModelEngine.cpp index 30ca7d0001f01b..87aa3e3c64f58b 100644 --- a/src/app/tests/TestInteractionModelEngine.cpp +++ b/src/app/tests/TestInteractionModelEngine.cpp @@ -39,8 +39,8 @@ #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS #include #include - #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS + namespace { class NullReadHandlerCallback : public chip::app::ReadHandler::ManagementCallback diff --git a/src/app/tests/test-ember-api.cpp b/src/app/tests/test-ember-api.cpp index 2b630327a21897..48ab29cb53942d 100644 --- a/src/app/tests/test-ember-api.cpp +++ b/src/app/tests/test-ember-api.cpp @@ -34,3 +34,6 @@ uint16_t emberAfGetClusterServerEndpointIndex(chip::EndpointId endpoint, chip::C } return endpoint; } + +// Mock function for linking +void InitDataModelHandler() {} diff --git a/src/controller/CHIPDeviceControllerFactory.cpp b/src/controller/CHIPDeviceControllerFactory.cpp index 649c3a37408a26..3d84d0b6b35442 100644 --- a/src/controller/CHIPDeviceControllerFactory.cpp +++ b/src/controller/CHIPDeviceControllerFactory.cpp @@ -252,16 +252,10 @@ CHIP_ERROR DeviceControllerFactory::InitSystemState(FactoryInitParams params) chip::app::InteractionModelEngine * interactionModelEngine = chip::app::InteractionModelEngine::GetInstance(); - // Note placement of this BEFORE `InitDataModelHandler` since InitDataModelHandler may - // rely on ember (does emberAfInit() and configure which may load data from NVM). - // - // Expected forward path is that we will move move and more things inside datamodel - // provider (e.g. storage settings) so we want datamodelprovider available before - // `InitDataModelHandler`. + // Initialize the data model now that everything cluster implementations might + // depend on is initalized. interactionModelEngine->SetDataModelProvider(params.dataModelProvider); - InitDataModelHandler(); - ReturnErrorOnFailure(Dnssd::Resolver::Instance().Init(stateParams.udpEndPointManager)); if (params.enableServerInteractions) diff --git a/src/controller/tests/TestServerCommandDispatch.cpp b/src/controller/tests/TestServerCommandDispatch.cpp index 2389ce08e6baf2..f4457c0013ef34 100644 --- a/src/controller/tests/TestServerCommandDispatch.cpp +++ b/src/controller/tests/TestServerCommandDispatch.cpp @@ -126,6 +126,9 @@ CHIP_ERROR TestClusterCommandHandler::EnumerateAcceptedCommands(const ConcreteCl namespace { +// TODO:(#36837) implementing its own provider instead of using "CodegenDataModelProvider" +// TestServerCommandDispatch should provide its own dedicated data model provider rather than using CodegenDataModelProvider +// provider. This class exists solely for one specific test scenario, on a temporary basis. class DispatchTestDataModel : public CodegenDataModelProvider { public: @@ -134,6 +137,20 @@ class DispatchTestDataModel : public CodegenDataModelProvider static DispatchTestDataModel instance; return instance; } + + // The Startup method initializes the data model provider with a given context. + // This approach ensures that the test relies on a more controlled and explicit data model provider + // rather than depending on the code-generated one with undefined modifications. + CHIP_ERROR Startup(DataModel::InteractionModelContext context) override + { + ReturnErrorOnFailure(CodegenDataModelProvider::Startup(context)); + return CHIP_NO_ERROR; + } + +protected: + // Since the current unit tests do not involve any cluster implementations, we override InitDataModelForTesting + // to do nothing, thereby preventing calls to the Ember-specific InitDataModelHandler. + void InitDataModelForTesting() override {} }; class TestServerCommandDispatch : public chip::Test::AppContext @@ -144,6 +161,7 @@ class TestServerCommandDispatch : public chip::Test::AppContext AppContext::SetUp(); mOldProvider = InteractionModelEngine::GetInstance()->SetDataModelProvider(&DispatchTestDataModel::Instance()); } + void TearDown() { InteractionModelEngine::GetInstance()->SetDataModelProvider(mOldProvider); diff --git a/src/controller/tests/data_model/DataModelFixtures.cpp b/src/controller/tests/data_model/DataModelFixtures.cpp index 6cb4f114c3d1ef..d5c02b5f0d16d3 100644 --- a/src/controller/tests/data_model/DataModelFixtures.cpp +++ b/src/controller/tests/data_model/DataModelFixtures.cpp @@ -40,6 +40,9 @@ using namespace chip::app::Clusters; using namespace chip::app::Clusters::UnitTesting; using namespace chip::Protocols; +// Mock function for linking +void InitDataModelHandler() {} + namespace chip { namespace app { diff --git a/src/data-model-providers/codegen/CodegenDataModelProvider.cpp b/src/data-model-providers/codegen/CodegenDataModelProvider.cpp index b599ba1dfdc0dd..1cf34fcb2c8fbb 100644 --- a/src/data-model-providers/codegen/CodegenDataModelProvider.cpp +++ b/src/data-model-providers/codegen/CodegenDataModelProvider.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -417,6 +418,8 @@ CHIP_ERROR CodegenDataModelProvider::Startup(DataModel::InteractionModelContext } } + InitDataModelForTesting(); + return CHIP_NO_ERROR; } @@ -859,6 +862,12 @@ ConcreteCommandPath CodegenDataModelProvider::NextGeneratedCommand(const Concret return ConcreteCommandPath(before.mEndpointId, before.mClusterId, commandId); } +void CodegenDataModelProvider::InitDataModelForTesting() +{ + // Call the Ember-specific InitDataModelHandler + InitDataModelHandler(); +} + std::optional CodegenDataModelProvider::FirstDeviceType(EndpointId endpoint) { // Use the `Index` version even though `emberAfDeviceTypeListFromEndpoint` would work because diff --git a/src/data-model-providers/codegen/CodegenDataModelProvider.h b/src/data-model-providers/codegen/CodegenDataModelProvider.h index 0493272dbbff47..e3455d5ce03a1b 100644 --- a/src/data-model-providers/codegen/CodegenDataModelProvider.h +++ b/src/data-model-providers/codegen/CodegenDataModelProvider.h @@ -187,6 +187,12 @@ class CodegenDataModelProvider : public DataModel::Provider void Temporary_ReportAttributeChanged(const AttributePathParams & path) override; +protected: + // Temporary hack for a test: Initializes the data model for testing purposes only. + // This method serves as a placeholder and should NOT be used outside of specific tests. + // It is expected to be removed or replaced with a proper implementation in the future.TODO:(#36837). + virtual void InitDataModelForTesting(); + private: // Iteration is often done in a tight loop going through all values. // To avoid N^2 iterations, cache a hint of where something is positioned diff --git a/src/data-model-providers/codegen/tests/TestCodegenModelViaMocks.cpp b/src/data-model-providers/codegen/tests/TestCodegenModelViaMocks.cpp index 302d26a8941cd0..fd2165983891b5 100644 --- a/src/data-model-providers/codegen/tests/TestCodegenModelViaMocks.cpp +++ b/src/data-model-providers/codegen/tests/TestCodegenModelViaMocks.cpp @@ -75,6 +75,9 @@ using namespace chip::app::Clusters::Globals::Attributes; using chip::Protocols::InteractionModel::Status; +// Mock function for linking +void InitDataModelHandler() {} + namespace { constexpr AttributeId kAttributeIdReadOnly = 0x3001; From 1c9216276943a6643993da85f3d4b328e03b9945 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 17 Dec 2024 15:11:08 -0500 Subject: [PATCH 18/19] zap regen (#36876) Co-authored-by: Andrei Litvin --- examples/chef/devices/rootnode_heatpump_87ivjRAECh.matter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/chef/devices/rootnode_heatpump_87ivjRAECh.matter b/examples/chef/devices/rootnode_heatpump_87ivjRAECh.matter index 87ff9a38821291..ecd48d74867218 100644 --- a/examples/chef/devices/rootnode_heatpump_87ivjRAECh.matter +++ b/examples/chef/devices/rootnode_heatpump_87ivjRAECh.matter @@ -1269,7 +1269,7 @@ cluster GeneralDiagnostics = 51 { /** Take a snapshot of system time and epoch time. */ command TimeSnapshot(): TimeSnapshotResponse = 1; /** Request a variable length payload response. */ - command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; + command access(invoke: manage) PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } /** Commands to trigger a Node to allow a new Administrator to commission it. */ From 37fa87375ce0d56e5851e61436ec9c983335cd73 Mon Sep 17 00:00:00 2001 From: Rohit Jadhav <69809379+jadhavrohit924@users.noreply.github.com> Date: Wed, 18 Dec 2024 04:31:38 +0530 Subject: [PATCH 19/19] [ESP32]: Removed esp32-m5-with-rpc from the CI. (#36872) * [ESP32]: Removed esp32-m5-with-rpc from the CI. * Add esp32 with rpc and ipv6only variation to CI * Add default sdkconfig. --- .github/workflows/examples-esp32.yaml | 10 +- .vscode/tasks.json | 2 - .../esp32/sdkconfig_rpc.defaults | 92 +++++++++++++++++++ integrations/cloudbuild/smoke-test.yaml | 1 - scripts/build/BUILD.gn | 1 - scripts/build/test.py | 1 - ...tack-all-clusters-minimal-rpc-ipv6only.txt | 26 ------ 7 files changed, 101 insertions(+), 32 deletions(-) create mode 100644 examples/all-clusters-app/esp32/sdkconfig_rpc.defaults delete mode 100644 scripts/build/testdata/dry_run_esp32-m5stack-all-clusters-minimal-rpc-ipv6only.txt diff --git a/.github/workflows/examples-esp32.yaml b/.github/workflows/examples-esp32.yaml index 3d3112d2972ecd..cd6a5f1225e9da 100644 --- a/.github/workflows/examples-esp32.yaml +++ b/.github/workflows/examples-esp32.yaml @@ -83,7 +83,6 @@ jobs: "./scripts/build/build_examples.py \ --enable-flashbundle \ --target esp32-m5stack-all-clusters-minimal \ - --target esp32-m5stack-all-clusters-rpc-ipv6only \ --pregen-dir ./zzz_pregenerated \ build \ --copy-artifacts-to out/artifacts \ @@ -95,6 +94,15 @@ jobs: mv scripts/tools/zap/generate.py.renamed scripts/tools/zap/generate.py - name: Build example All Clusters App(Target:ESP32C3) run: scripts/examples/esp_example.sh all-clusters-app sdkconfig.defaults.esp32c3 esp32c3 + - name: Build example All Clusters App(Target:ESP32) + run: | + ./scripts/run_in_build_env.sh \ + "./scripts/build/build_examples.py \ + --enable-flashbundle \ + --target esp32-devkitc-all-clusters-rpc-ipv6only \ + build \ + --copy-artifacts-to out/artifacts \ + " - name: Copy aside build products run: | mkdir -p example_binaries/esp32-build diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a0ae1b95fe4730..0a2b379ccb0f01 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -579,8 +579,6 @@ "esp32-devkitc-temperature-measurement", "esp32-m5stack-all-clusters", "esp32-m5stack-all-clusters-ipv6only", - "esp32-m5stack-all-clusters-rpc", - "esp32-m5stack-all-clusters-rpc-ipv6only", "infineon-psoc6-all-clusters", "infineon-psoc6-lock", "infineon-psoc6-light", diff --git a/examples/all-clusters-app/esp32/sdkconfig_rpc.defaults b/examples/all-clusters-app/esp32/sdkconfig_rpc.defaults new file mode 100644 index 00000000000000..3faf5754c82a99 --- /dev/null +++ b/examples/all-clusters-app/esp32/sdkconfig_rpc.defaults @@ -0,0 +1,92 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# Copyright (c) 2024 Nest Labs, Inc. +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Description: +# CI uses this to select the ESP32. +# +CONFIG_IDF_TARGET="esp32" +CONFIG_IDF_TARGET_ESP32=y + +# Default to 921600 baud when flashing and monitoring device +CONFIG_ESPTOOLPY_BAUD_921600B=y +CONFIG_ESPTOOLPY_BAUD=921600 +CONFIG_ESPTOOLPY_COMPRESSED=y +CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 + +#enable BT +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y + +#enable lwip ipv6 autoconfig +CONFIG_LWIP_IPV6_AUTOCONFIG=y + +# Use a custom partition table +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" + +# Vendor and product id +CONFIG_DEVICE_VENDOR_ID=0xFFF1 +CONFIG_DEVICE_PRODUCT_ID=0x8001 + +# Main task needs a bit more stack than the default +# default is 3584, bump this up to 5k. +CONFIG_ESP_MAIN_TASK_STACK_SIZE=5120 + +# PW RPC Debug channel +CONFIG_EXAMPLE_UART_PORT_NUM=0 +CONFIG_EXAMPLE_UART_BAUD_RATE=115200 +CONFIG_EXAMPLE_UART_RXD=3 +CONFIG_EXAMPLE_UART_TXD=1 +CONFIG_ENABLE_PW_RPC=y + +# Disable shell +CONFIG_ENABLE_CHIP_SHELL=n + +# Serial Flasher config +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" + + +#disable Bluetooth modem sleep +#enable it may cause GPIO ISR triggers continuously +CONFIG_BTDM_CTRL_MODEM_SLEEP=n +CONFIG_BTDM_CTRL_MODEM_SLEEP_MODE_ORIG=n +CONFIG_BTDM_CTRL_LPCLK_SEL_MAIN_XTAL=n + +# Enable HKDF in mbedtls +CONFIG_MBEDTLS_HKDF_C=y + +# Build chip tests +CONFIG_BUILD_CHIP_TESTS=y + +# Move functions from IRAM to flash +CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y + +CONFIG_DIAG_USE_EXTERNAL_LOG_WRAP=y + +# Memory Optimizations +CONFIG_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BTDM_CTRL_BLE_MAX_CONN=1 +CONFIG_BT_NIMBLE_ROLE_CENTRAL=n +CONFIG_BT_NIMBLE_ROLE_OBSERVER=n + +# Reduce the event logging buffer to reduce the DRAM overflow +# TODO: [ESP32] Fix the DRAM overflow in esp32 apps #34717 +CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE=512 +CONFIG_EVENT_LOGGING_INFO_BUFFER_SIZE=512 +CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE=512 diff --git a/integrations/cloudbuild/smoke-test.yaml b/integrations/cloudbuild/smoke-test.yaml index 9a48c18494406d..7725253af6c9f7 100644 --- a/integrations/cloudbuild/smoke-test.yaml +++ b/integrations/cloudbuild/smoke-test.yaml @@ -34,7 +34,6 @@ steps: ./scripts/build/build_examples.py --enable-flashbundle --target esp32-devkitc-light-rpc --target esp32-m5stack-all-clusters-ipv6only --target - esp32-m5stack-all-clusters-rpc-ipv6only --target esp32-m5stack-light --target esp32-m5stack-light-ipv6only --target esp32-m5stack-ota-requestor build --create-archives diff --git a/scripts/build/BUILD.gn b/scripts/build/BUILD.gn index 36b8209285576e..f5995db875efe2 100644 --- a/scripts/build/BUILD.gn +++ b/scripts/build/BUILD.gn @@ -26,7 +26,6 @@ pw_python_package("build_examples") { "testdata/dry_run_android-arm64-chip-tool.txt", "testdata/dry_run_efr32-brd4187c-light-rpc-no-version.txt", "testdata/dry_run_esp32-devkitc-light-rpc.txt", - "testdata/dry_run_esp32-m5stack-all-clusters-minimal-rpc-ipv6only.txt", "testdata/dry_run_linux-arm64-chip-tool-ipv6only-clang.txt", "testdata/dry_run_linux-arm64-ota-requestor-nodeps-ipv6only.txt", "testdata/dry_run_linux-x64-all-clusters-coverage.txt", diff --git a/scripts/build/test.py b/scripts/build/test.py index 48a7e4fe53bafc..f1488ba17b870a 100644 --- a/scripts/build/test.py +++ b/scripts/build/test.py @@ -108,7 +108,6 @@ def test_general_dry_runs(self): # build options do not change too much TARGETS = [ 'esp32-devkitc-light-rpc', - 'esp32-m5stack-all-clusters-minimal-rpc-ipv6only', 'android-arm64-chip-tool', 'nrf-nrf52840dk-pump', 'efr32-brd4187c-light-rpc-no-version', diff --git a/scripts/build/testdata/dry_run_esp32-m5stack-all-clusters-minimal-rpc-ipv6only.txt b/scripts/build/testdata/dry_run_esp32-m5stack-all-clusters-minimal-rpc-ipv6only.txt deleted file mode 100644 index 7d6977d6fc05cc..00000000000000 --- a/scripts/build/testdata/dry_run_esp32-m5stack-all-clusters-minimal-rpc-ipv6only.txt +++ /dev/null @@ -1,26 +0,0 @@ -# Commands will be run in CHIP project root. -cd "{root}" - -# Generating esp32-m5stack-all-clusters-minimal-rpc-ipv6only -mkdir -p {out}/esp32-m5stack-all-clusters-minimal-rpc-ipv6only - -cp examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack_rpc.defaults {out}/esp32-m5stack-all-clusters-minimal-rpc-ipv6only/sdkconfig.defaults - -rm -f examples/all-clusters-minimal-app/esp32/sdkconfig - -bash -c 'echo -e "\nCONFIG_DISABLE_IPV4=y\n" >>{out}/esp32-m5stack-all-clusters-minimal-rpc-ipv6only/sdkconfig.defaults' - -bash -c 'echo -e "\nCONFIG_LWIP_IPV4=n\n" >>{out}/esp32-m5stack-all-clusters-minimal-rpc-ipv6only/sdkconfig.defaults' - -bash -c 'echo -e "\nCONFIG_ESP_INSIGHTS_ENABLED=n\nCONFIG_ENABLE_ESP_INSIGHTS_TRACE=n\n" >>{out}/esp32-m5stack-all-clusters-minimal-rpc-ipv6only/sdkconfig.defaults' - -bash -c 'source $IDF_PATH/export.sh; source scripts/activate.sh; -export SDKCONFIG_DEFAULTS={out}/esp32-m5stack-all-clusters-minimal-rpc-ipv6only/sdkconfig.defaults -idf.py -C examples/all-clusters-minimal-app/esp32 -B {out}/esp32-m5stack-all-clusters-minimal-rpc-ipv6only reconfigure' - -rm -f examples/all-clusters-minimal-app/esp32/sdkconfig - -# Building esp32-m5stack-all-clusters-minimal-rpc-ipv6only -bash -c 'source $IDF_PATH/export.sh; source scripts/activate.sh; -export SDKCONFIG_DEFAULTS={out}/esp32-m5stack-all-clusters-minimal-rpc-ipv6only/sdkconfig.defaults -idf.py -C examples/all-clusters-minimal-app/esp32 -B {out}/esp32-m5stack-all-clusters-minimal-rpc-ipv6only build'