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 systemImplement 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 aClusterLogic
This implements DefaultServerCluster or more generally the ServerClusterInterface interface.
(optional) a
ClusterDriver
that provides callbacks to an application for cluster interactions. Within the SDK the nameDelegate
is often used, however since the delegate term is often overloaded, we suggest using the termDriver
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 worldthe
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
andapp_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
andchip::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 frameworkMATTER_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 ifCLUSTER
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 clusteremberAf<Cluster>ClusterInitCallback
andMatter<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 aDriver
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.