blob: c0f0345895167bb9b388d50f8b85f88504f76924 [file] [log] [blame] [view] [edit]
# 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](https://github.com/project-chip/connectedhomeip/tree/master/src/app/zap-templates/zcl/data-model/chip)
In order to define a new cluster, use
[Alchemy](https://github.com/project-chip/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](../zap_and_codegen/code_generation.md). 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](https://github.com/project-chip/connectedhomeip/blob/master/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](https://github.com/project-chip/connectedhomeip/tree/master/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](https://github.com/project-chip/connectedhomeip/tree/master/src/app/clusters/software-diagnostics-server).
### 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`
- This implements
[DefaultServerCluster](https://github.com/project-chip/connectedhomeip/blob/master/src/app/server-cluster/DefaultServerCluster.h)
or more generally the
[ServerClusterInterface](https://github.com/project-chip/connectedhomeip/blob/master/src/app/server-cluster/ServerClusterInterface.h)
interface.
- (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](https://github.com/project-chip/connectedhomeip/blob/master/src/app/server-cluster/ServerClusterContext.h)
to use
### Persistent storage
> [!IMPORTANT] Attribute persistence support is not fully defined in the new
> cluster format. This will be available after
> [#37924](https://github.com/project-chip/connectedhomeip/issues/37924) is
> fixed.
For general storage, the cluster context
[provides](https://github.com/project-chip/connectedhomeip/blob/master/src/app/server-cluster/ServerClusterContext.h)
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](https://github.com/project-chip/connectedhomeip/blob/master/scripts/py_matter_idl/matter/idl/generators/cpp/application/ServerClusterConfig.jinja)
and provide the following information:
- `chip::app::Clusters::<NAME>::kFixedClusterConfig` as an array of
[ClusterConfiguration](https://github.com/project-chip/connectedhomeip/blob/master/src/app/util/cluster-config.h).
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](https://github.com/project-chip/connectedhomeip/blob/master/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](https://github.com/project-chip/connectedhomeip/blob/master/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](https://github.com/project-chip/connectedhomeip/blob/master/src/app/zap-templates/zcl/zcl.json)
and
[src/app/zap-templates/zcl/zcl-with-test-extensions.json](https://github.com/project-chip/connectedhomeip/blob/master/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.