docs/guides/migrating_ember_cluster_to_code_driven.md
This document provides a step-by-step guide for converting an existing Ember-based cluster to a modern, code-driven implementation. It is recommended to first read the guide on Writing Clusters for a general overview of the code-driven cluster architecture.
This checklist provides a granular, step-by-step process for migrating an Ember cluster to a code-driven implementation.
Before you begin the migration, consider structuring your changes into multiple, smaller pull requests. This approach significantly simplifies the review process, allowing reviewers to approve preliminary changes quickly. We recommend the following sequence of PRs:
PR 1: File Renames Only.
<name>-server.cpp to
<Name>Cluster.cpp.git diff from becoming confused and showing the
entire file as deleted and recreated, making the actual code changes
impossible to review.PR 2: Code Movement Only.
git diff --color-moved to verify
that code has only been moved, not altered. This allows for a rapid
review of structural changes.PR 3: The Core Logic Changes.
This structure respects the reviewer's time and helps get your changes merged faster. You can ask for an expedited review of the preliminary PRs in the project's Slack channel.
1.1: Understand the Existing Implementation:
AttributeAccessInterface (AAI), or CommandHandlerInterface
(CHI).
src/app/util handles data storage and access. In a
code-driven implementation, this data must be moved into member
variables within your new cluster class.AAI translates to the
ReadAttribute and WriteAttribute methods, while CHI translates
to the InvokeCommand method.persist, ram,
callback). This will inform how you handle data in the new
implementation.
persist, the new cluster should handle
persistence (load in Startup and store during writes).ram and loaded from the ZAP UI,
CodegenIntegration.cpp should load the value from ZAP via the
generated Accessors.h. A common example is the FeatureMap.ClusterRevision),
it should be marked as External by adding it to
attributeAccessInterfaceAttributes in zcl.json.1.2: Choose an Implementation Pattern:
1.3: Create the File Structure:
src/app/clusters/<name>/.
src/app/zap_cluster_list.json under the ServerDirectories
key.<Name>Cluster.h<Name>Cluster.cppCodegenIntegration.cpptests/Test<Name>Cluster.cppBUILD.gntests/BUILD.gnapp_config_dependent_sources.gniapp_config_dependent_sources.cmake2.1: Implement the Cluster Class:
<Name>Cluster class, inheriting from
DefaultServerCluster.Startup and Shutdown methods for resource
management.2.2: Implement Attribute Logic:
ReadAttribute and WriteAttribute methods,
translating any existing AAI logic.AttributePersistence helper to
load in Startup and save on writes.NotifyAttributeChangedIfSuccess) to ensure
subscriptions work correctly.2.3: Implement Command Logic:
Implement the InvokeCommand method, translating any existing CHI
or emberAf...Callback logic.
Example: An emberAf<CLUSTER>Cluster<COMMAND>Callback function
becomes a case in the InvokeCommand's switch statement:
// This:
emberAfAccessControlClusterReviewFabricRestrictionsCallback(...);
// Becomes this in the `InvokeCommand` implementation:
switch (request.path.mCommandId) {
// ...
case AccessControl::Commands::ReviewFabricRestrictions::Id:
// ...
}
Use a switch statement on the command ID to handle different
commands.
2.4: Implement Event Logic:
LogEvent with
mContext->interactionContext.eventsGenerator.GenerateEvent to make
events unit-testable.EventInfo method
if necessary.3.1: Update Build Files:
BUILD.gn and tests/BUILD.gn to include the new source
files.app_config_dependent_sources.gni and
app_config_dependent_sources.cmake to integrate the cluster into
the build system.3.2: Implement Codegen Integration:
CodegenIntegration.cpp, use the CodegenClusterIntegration
helper to read configuration values from the generated code.Note: The
CodegenClusterIntegrationhelper for optional attributes only supports attribute IDs up to 31. For clusters with higher attribute IDs, you will need a custom implementation.
3.3: Update ZAP Configuration:
src/app/common/templates/config-data.yaml, add the cluster to
the CommandHandlerInterfaceOnlyClusters array.src/app/zap-templates/zcl/zcl.json and
zcl-with-test-extensions.json, add all non-list attributes to the
attributeAccessInterfaceAttributes list../scripts/run_in_build_env.sh 'scripts/tools/zap_regen_all.py'
4.1: Write Unit Tests:
tests/Test<Name>Cluster.cpp, add unit tests for the new
implementation.4.2: Perform Integration Testing:
all-clusters-app).chip-tool or
matter-repl.