Writing and updating clusters#

The following checklist can be used to write a new cluster

  • Generate the XML based on the specification

  • Define a new src/app/clusters/<cluster-name> folder for the cluster code and integrate this into the build system

  • Implement cluster logic and unit tests under the new folder

  • Integrate the cluster into an example application

    • Add codegen-integration support for the cluster

    • integrate into an example app (e.g. all-clusters app)

  • Add integration tests for the new cluster

Cluster definitions#

Clusters are defined against the Matter specification. The underlying code for them is code-generated, based on XML definitions from src/app/zap-templates/zcl/data-model/chip In order to define a new cluster, use Alchemy to parse the specification asciidoc and generate/update the relevant XML files. Manual editing is discouraged as we have found that mistakes are easy to make and hard to spot.

Once you have a new or updated XML, run code generation. It is often sufficient to ./scripts/run_in_build_env.sh 'scripts/tools/zap_regen_all.py'

Integrating into the build system#

The build system maps cluster UPPER_SNAKE_CASE names into folder names. The mapping is done in src/app/zap_cluster_list.json and this file will need your new cluster added.

The mapping defines the folder under which the cluster resides, inside src/app/clusters

Cluster layout#

This layout describes a “code-driven capable cluster” implementation. You can see how an existing cluster implements this such as Software Diagnostics.

Cluster implementation basic design#

You will generally have 2 major classes:

  • ClusterLogic is intended to be type-safe implementation of the cluster.

    • It contains all the logic for the cluster

    • It contains all attribute storage for the cluster

    • Is unit tested

  • ClusterImplementation that provides a translation between value encoders/decoders and a ClusterLogic

  • (optional) a ClusterDriver that provides callbacks to an application for cluster interactions. Within the SDK the name Delegate is often used, however since the delegate term is often overloaded, we suggest using the term Driver for this.

Unit tests will reside in src/app/clusters/<cluster>/tests and will test ClusterLogic at a minimum, including varying features, correctness for attributes/commands and functionality.

ClusterImplementation can also be unit tested depending on the complexity of its implementation. If its implementation is reasonably simple, the integration tests should validate it.

Implementation considerations#

It is common that exposed attributes are optional or depend on feature enabling. Ensure that your class always returns correct data depending on selected features and functionality: this should be part of unit testing.

Consider if optimizing for flash/ram usage is required: common/large clusters may need this, other application clusters may be able to accept an overhead for maintainability. If compile-time flash/ram optimization is needed, use templates to select available features/attributes and if they are enabled or not.

Ensure that every attribute update will notify via the context interactionContext->dataModelChangeListener (https://github.com/project-chip/connectedhomeip/blob/master/src/app/data-model-provider/Context.h). This is required for subscriptions to work and should be unit tested:

  • CHIP_ERROR ClusterServerInterface::Startup(ServerClusterContext & context) will receive the context needed to communicate with the outside world

  • the context contains the InteractionModelContext to use

Persistent storage#

[!IMPORTANT] Attribute persistence support is not fully defined in the new cluster format. This will be available after #37924 is fixed.

For general storage, the cluster context provides a PersistentStorageDelegate.

Integration with application-specific code generation#

When using code generation for applications (i.e. a *.zap file), every application will have a source set that explicitly defines enabled items. To integrate with the codegen data model provider/generated code, following changes are needed:

  • create a CodegenIntegration.cpp file intended to make use of this static application configuration.

  • Add build system files: app_config_dependent_sources.gni and app_config_dependent_sources.cmake that contain this file and additional dependencies. See existing clusters for examples.

  • Make use of static configuration data as described below

Cluster-specific application configuration#

These are generated files available for inclusion as <app/static-cluster-config/<cluster-name>.h. They are generated from ServerClusterConfig.jinja and provide the following information:

  • chip::app::Clusters::<NAME>::kFixedClusterConfig as an array of ClusterConfiguration. Both initialization and static asserts can be done based on these configurations.

  • chip::app::Clusters::<NAME>::IsAttributeEnabledOnSomeEndpoint and chip::app::Clusters::<NAME>::IsCommandEnabledOnSomeEndpoint are available to check if a specific item is enabled on any endpoint. This can be useful for dynamic cluster support for code generation (e.g. to define the maximal things supported by a cluster that could be instantiated on an endpoint)

Further defines are available through inclusion of src/app/util/config.h, which will include gen_config.h and endpoint_config.h as generated files through ZAP. These provide:

  • CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT as a count of dynamic endpoints for the ember framework

  • MATTER_DM_<CLUSTER_DEFINE>_ENDPOINT_COUNT for a count of static endpoints (same as the kFixedClusterConfig array size)

  • MATTER_DM_<CLUSTER_DEFINE>_SERVER definition as a flag if CLUSTER is in use by the application at all

  • <CLUSTER_DEFINE>_ENABLE_<CMD_DEFINE>_CMD to define if a specific command is enabled on a cluster

Beyond that, the following callbacks will be available to initialize and shutdown clusters. Implement these as needed inside the CodegenIntegration.cpp file:

  • Matter<Cluster>ClusterServerInitCallback - single callback for initializing the cluster

  • emberAf<Cluster>ClusterInitCallback and Matter<Cluster>ServerShutdownCallback are called on endpoint startup and shutdown.

Optional compatibility layers:

  • Matter<Cluster>ClusterServerAttributeChangedCallback is currently called by ember-clusters after attribute changes. Consider if this should be called by a Driver registered to the cluster.

Update code-generation configuration#

To avoid duplication of implementations from ember, update src/app/common/templates/config-data.yaml and set CommandHandlerInterfaceOnlyClusters since ember command dispatch will not be needed

Update attributeAccessInterfaceAttributes in src/app/zap-templates/zcl/zcl.json and src/app/zap-templates/zcl/zcl-with-test-extensions.json to mark all attributes of the cluster as attribute access interface attributes, so that ember does not reserve RAM for them (ClusterLogic should contain this RAM now). List-typed attributes do not need to be added in these lists.