在 Matter SDK(connectedhomeip)中添加新 Device Type 与 Cluster 的完整实践指南
2026/9/16 14:44:05 网站建设 项目流程

在 Matter SDK(connectedhomeip)中添加新 Device Type 与 Cluster 的完整实践指南

【免费下载链接】connectedhomeipMatter (formerly Project CHIP) creates more connections between more objects, simplifying development for manufacturers and increasing compatibility for consumers, guided by the Connectivity Standards Alliance.项目地址: https://gitcode.com/GitHub_Trending/co/connectedhomeip

本指南基于connectedhomeip仓库的 docs/cluster_and_device_type_dev/how_to_add_new_dts_and_clusters.md 编写,系统梳理在 Matter SDK 代码生成体系中新增 Cluster(集群)与 Device Type(设备类型)的完整流程:从 XML 数据模型定义、ZAP 工具配置、代码生成,到 Server 端 C++ 实现、YAML/Python 测试与 CI 接入。读者完成阅读后,将掌握一套可复现的端到端开发方法,并能以仓库中已有的 Dishwasher Mode(洗碗机模式)集群作为模板快速上手。

1. 总体流程概览

在 Matter SDK 中,集群与设备类型的“源代码”是一系列 XML 定义文件(位于 src/app/zap-templates/zcl/data-model/chip),它们经 ZAP 工具与zap_regen_all.py等脚本转换成 C++ 代码(生成物位于 zzz_generated/app-common)。因此,新增一个集群本质上分为两大阶段:

  1. 数据模型阶段:编写 XML 集群定义,并把新集群注册到各类清单(zcl.jsonzcl-with-test-extensions.jsonzap_cluster_list.json等)中。
  2. 实现阶段:在 src/app/clusters 中实现集群逻辑,编写 YAML/Python 测试,并把测试接入 CI。

在动手之前,务必先完成 Matter 规范(spec)的评审与批准——文档明确强调,"the steps below assume that the related Matter specifications were properly reviewed and approved"。

整体工作流可概括为:写 XML → 注册清单 → ZAP 配置 → 生成代码 → 实现 Server → 写测试 → 接入 CI。以下各节逐一展开。

2. 将 Cluster 定义加入 SDK 数据模型

2.1 创建集群 XML 定义文件

新集群的 XML 定义应放入 src/app/zap-templates/zcl/data-model/chip 目录,文件按集群语义命名,例如dishwasher-mode-cluster.xmllaundry-washer-mode-cluster.xml

以 dishwasher-mode-cluster.xml 为例,一个标准集群定义包含以下关键元素:

<configurator xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../zcl.xsd"> <domain name="CHIP"/> <cluster> <domain>Appliances</domain> <name>Dishwasher Mode</name> <code>0x0059</code> <define>DISHWASHER_MODE_CLUSTER</define> <client init="false" tick="false">true</client> <server init="false" tick="false">true</server> <description>Attributes and commands for selecting a mode from a list of supported options.</description> <globalAttribute side="either" code="0xFFFD" value="3"/> <!-- 服务器端属性 --> <attribute side="server" code="0x0000" name="SupportedModes" define="SUPPORTED_MODES" type="array" entryType="ModeOptionStruct" length="255" minLength="2"/> <attribute side="server" code="0x0001" name="CurrentMode" define="CURRENT_MODE" type="int8u"/> <!-- 命令 --> <command source="client" code="0x00" name="ChangeToMode" response="ChangeToModeResponse"> <description>This command is used to change device modes.</description> <arg fieldId="0" name="NewMode" type="int8u"/> </command> <command source="server" code="0x01" name="ChangeToModeResponse" disableDefaultResponse="true"> <description>This command is sent by the device on receipt of the ChangeToMode command.</description> <arg fieldId="0" name="Status" type="enum8"/> <arg fieldId="1" name="StatusText" type="char_string" length="64" optional="true"/> </command> </cluster> </configurator>

要点说明:

  • <code>是集群的全局 ID(如0x0059),<define>是该集群在 C 代码中的宏名(如DISHWASHER_MODE_CLUSTER);
  • <attribute>声明属性 ID、类型(arrayint8uenum8等)、entryType(数组元素类型)与长度约束;
  • <command>声明命令的源(client/server)、命令 ID 与参数,response字段指定对应的响应命令;
  • 文件头部的<!-- XML generated by Alchemy; DO NOT EDIT. -->注释说明部分 XML 由 Alchemy 从规范.adoc自动生成,手工新增的集群则需自行保证与规范一致。

2.2 将新集群注册到各个清单文件

文档要求把每个新集群的引用加入以下文件,缺一不可:

  1. .github/workflows/tests.yaml—— CI 工作流,后续接入测试时也要修改;
  2. scripts/rules.matterlint—— Matterlint 规则文件;
  3. src/app/zap-templates/zcl/zcl-with-test-extensions.json—— 带测试扩展的 ZCL 数据模型清单(xmlFile列表);
  4. src/app/zap-templates/zcl/zcl.json—— 标准 ZCL 数据模型清单;
  5. src/controller/python/matter/clusters/__init__.py—— Python 控制器侧集群注册。

其中第 5 点尤为重要:若新集群是派生集群(derived cluster),必须在基集群定义中补充集群代码引用。例如在 mode-base-cluster.xml 中,ModeTagStructModeOptionStruct都通过<cluster code="0xXXXX"/>列出所有派生集群的 ID:

<struct name="ModeTagStruct"> <cluster code="0x0051"/> <!-- Laundry Washer Mode --> <cluster code="0x0052"/> <!-- Refrigerator and temperature controlled cabinet Mode --> <cluster code="0x0054"/> <!-- RVC Run Mode --> <cluster code="0x0055"/> <!-- RVC Clean Mode --> <cluster code="0x0059"/> <!-- Dishwasher Mode --> <cluster code="0x005E"/> <!-- Microwave Oven Mode --> <cluster code="0x0049"/> <!-- Oven Mode --> <cluster code="0x009D"/> <!-- Energy EVSE Mode --> <cluster code="0x009E"/> <!-- Water Heater Mode --> <cluster code="0x009F"/> <!-- Device Energy Management Mode --> </struct> <struct name="ModeOptionStruct"> <!-- 同样列出全部派生集群的 code --> </struct>

文档特别提醒:如果遗漏这一步,运行regen_all.py时可能抛出难以理解的异常。

2.3 在 Python 与 Android 控制器中启用新集群

控制器侧通过 ZAP 文件 src/controller/data_model/controller-clusters.zap 决定启用哪些集群。编辑该文件需要 ZAP GUI 工具:

  • 官方 nightly 构建:ZAP 工具官方 release 页;
  • 工具文档与源码:ZAP 官方仓库。

GUI 操作步骤(文档原文流程):

  1. 命令行进入 src/controller/data_model 目录;
  2. 运行 ZAP:
    • ../../../scripts/tools/zap/run_zaptool.sh controller-clusters.zap,或
    • ./scripts/tools/zap/run_zaptool.sh src/controller/data_model/controller-clusters.zap
  3. 在 GUI 左侧面板选择Endpoint-1
  4. 打开集群分组,例如Appliances
  5. 找到要启用的集群,例如Dishwasher Control
  6. Enable列的下拉框中选择 "Client";
  7. 点击File->Save保存配置;
  8. 关闭 GUI。

保存后,需在 src/app/zap_cluster_list.json 的ClientDirectories段为新集群添加条目,例如:

"DISHWASHER_MODE_CLUSTER": []

该文件(共 410 行)中的 ClientDirectories 以XXX_CLUSTER的宏名为键(见 src/app/zap_cluster_list.json),ServerDirectories 则以宏名为键、以所需生成目录列表为值(如"DISHWASHER_MODE_CLUSTER": ["mode-base-server"])。

2.4 更新 chip-tool 并重新生成代码

chip-tool 是 Matter 的参考命令行客户端,它同样由 XML 驱动生成(文档第 5 条 Notes 明确:"the CHIP-Tool reference client is generated from XML")。完成上述注册后:

  1. 重新生成所有 ZAP 代码:
    ./scripts/tools/zap_regen_all.py
  2. 重新构建 chip-tool,即可获得新集群支持:
    ./scripts/examples/gn_build_example.sh examples/chip-tool SOME-PATH/

2.5 旧集群定义的去向

Q&A 部分指出,旧版集群定义位于 src/app/zap-templates/zcl/data-model/silabs/general.xml,新集群定义统一放至data-model/chip目录,便于迁移与对照。

3. 添加 Device Type 定义到 SDK

3.1 定义设备类型 XML

在 matter-devices.xml 中追加新设备类型的 XML 定义。设备类型 XML 描述设备类型 ID、名称、必含的服务器端集群(server clusters)与可选集群等约束,是后续生成设备能力/描述(Descriptor、Part List 等)的数据来源。

3.2 实现命令行为与属性读写

文档将设备类型落地拆解为四步:

  1. 定义 XML(如上);
  2. 实现各应用共通的命令行为:TLV 载荷到 C++ 结构体的解析由 XML 自动生成代码完成(生成物见 zzz_generated/app-common/app-common/zap-generated),其余功能需手工实现。生成方式二选一:
    • 全量生成:./scripts/tools/zap_regen_all.py
    • 仅生成 app-common:
      ./scripts/tools/zap/generate.py -t src/app/common/templates/templates.json -o zzz_generated/app-common/app-common/zap-generated src/controller/data_model/controller-clusters.zap
  3. 实现各类型/列表/结构体属性的读写与存储:全局属性(如CommandListAttributeList)无需实现;非列表/结构体属性的处理代码由框架通用实现,通常无需额外工作;
  4. 实现所有应用通用的规范约束:如属性取值范围校验、属性间联动逻辑等。

4. 实现 Cluster 代码与测试(以 mode-base 派生集群为例)

4.1 集群实现位置

新集群的 C++ 实现位于 src/app/clusters,编写规范可参考 docs/guides/writing_clusters.md;测试位于 src/app/tests/suites。

4.2 示例集群服务器应用的两种选择

YAML 测试会跑在示例集群服务器(example cluster server application)上,文档给出两个选项:

  1. 直接在all-clusters-app中启用相关集群并以其作为示例服务器;文档建议同时提供一个仅含相关集群的精简示例应用("nice to have");
  2. 若集群有复杂的全局应用需求(如门锁、桥接、TV、OTA 集群),考虑独立示例应用。

4.3 从 mode-base 派生集群的 10 步清单(以 XYZMode 为例)

假设新集群名为XYZMode(文档示例),步骤如下:

  1. 创建精简的xyz-mode-cluster.xml:派生集群的定义比普通集群精简得多,因为它从 mode-base-cluster.xml 继承。参照 dishwasher-mode-cluster.xml,并根据规范判断是否需要StartUpModeOnMode属性;
  2. 将集群代码加入 mode-base-cluster.xml 的三处
    • <struct name="ModeTagStruct"> <cluster code="0xXXXX">(用集群 ID 替换XXXX);
    • <struct name="ModeOptionStruct"> <cluster code="0xXXXX">
    • <bitmap name="Feature" type="bitmap32"> <cluster code="0xXXXX">
  3. 编写xyz-mode.h:定义模式/标签/标签集。参照 dishwasher-mode.h:
    const uint8_t ModeNormal = 0; const uint8_t ModeHeavy = 1; const uint8_t ModeLight = 2; class DishwasherModeDelegate : public ModeBase::Delegate { private: using ModeTagStructType = detail::Structs::ModeTagStruct::Type; ModeTagStructType modeTagsNormal[1] = { { .mfgCode = {}, .value = to_underlying(ModeTag::kNormal) } }; const detail::Structs::ModeOptionStruct::Type kModeOptions[3] = { { .label = "Normal"_span, .mode = ModeNormal, .modeTags = DataModel::List<const ModeTagStructType>(modeTagsNormal) }, // ... }; CHIP_ERROR Init() override; void HandleChangeToMode(uint8_t mode, ModeBase::Commands::ChangeToModeResponse::Type & response) override; CHIP_ERROR GetModeLabelByIndex(uint8_t modeIndex, MutableCharSpan & label) override; CHIP_ERROR GetModeValueByIndex(uint8_t modeIndex, uint8_t & value) override; CHIP_ERROR GetModeTagsByIndex(uint8_t modeIndex, DataModel::List<ModeTagStructType> & tags) override; public: ~DishwasherModeDelegate() override = default; }; ModeBase::Instance * Instance(); void Shutdown();
  4. 编写xyz-mode.cpp实例化桩:参照 dishwasher-mode.cpp。该文件展示了模式集群的完整生命周期:
    • MatterDishwasherModeClusterInitCallback()中创建 Delegate 与ModeBase::InstanceInit()
    • HandleChangeToMode()依据GetFailTransition()决定返回kInvalidInMode还是kSuccess
    • GetModeLabelByIndex/GetModeValueByIndex/GetModeTagsByIndex按索引返回模式元数据;
    • Shutdown()负责释放 Delegate 与 Instance;
  5. 修改 examples/all-clusters-app/linux/main-common.cpp:添加#include "xyz-mode.h",并在ApplicationShutdown()中调用Clusters::XYZMode::Shutdown();
  6. 修改 examples/all-clusters-app/linux/BUILD.gn:把xyz-mode.cpp加入sources
  7. 修改 src/app/common/templates/config-data.yaml
    • EnumsNotUsedAsTypeInXML段添加<XYZMode>::ModeTag(现有示例为"DishwasherMode::ModeTag");
    • CommandHandlerInterfaceOnlyClusters段添加XYZ Mode(现有示例含Dishwasher Mode);
  8. 修改 src/app/util/util.cpp:在// Cluster Init Functions...段添加空定义void MatterXYZModePluginServerInitCallback() {}(现有示例见 src/app/util/util.cpp);
  9. 修改 src/app/zap-templates/zcl/zcl-with-test-extensions.json
    • xmlFile列表添加xyz-mode-cluster.xml
    • attributeAccessInterfaceAttributes中添加"XYZ Mode": [ "SupportedModes", "CurrentMode", "FeatureMap" ],使 ZAP 不再为这些属性生成处理代码(因为由CommandHandlerInterface/AttributeAccessInterface接管);
  10. 修改 src/app/zap_cluster_list.json
    • ClientDirectories: { }中添加XYZ_MODE_CLUSTER: []
    • ServerDirectories: { }中添加"XYZ_MODE_CLUSTER": ["mode-base-server"]

4.4 代码生成与生命周期

从源码结构可以推断,mode-base 派生集群的核心机制是:XML 只负责生成类型与访问器,运行时逻辑由ModeBase::Instance+ 应用层Delegate承载MatterDishwasherModeClusterInitCallback在端点初始化时被框架调用(见 src/app/util/util.cpp 中的 Cluster Init 段与MatterDishwasherModePluginServerInitCallback() {}空实现),开发者通过zcl-with-test-extensions.jsonattributeAccessInterfaceAttributes让 ZAP 跳过SupportedModes等属性,从而把数据源完全交给 Delegate 实现——这是 mode-base 派生集群能够以极低代码量复用的关键。

5. 编写测试计划与测试用例

5.1 测试计划模板

官方测试计划采用两个 adoc 模板:

  1. cluster_test_plan_template.adoc(集群测试计划模板);
  2. test_plan_template.adoc(设备类型测试计划模板)。

两者均位于 CHIP-Specifications/chip-test-plans 仓库的src/template目录。此外,文档提示应申请加入私有的csg-tt-test-plansSlack 频道(注意:测试计划仓库与 Slack 频道均为外部资源,本仓库仅保留使用指引)。

5.2 YAML 测试与 Python 测试的选择

文档给出明确的取舍建议:

  • 较简单的测试:使用 YAML 测试,存放于 src/app/tests/suites/certification,并同步更新 PICS.yaml;
  • 较复杂的测试:使用 Python 测试,存放于 src/python_testing;
  • 认证测试计划:认证(certification)目录下的 YAML 或 src/python_testing 的 Python 测试应尽量实现第 4 节对应的官方测试计划(Test Plan);
  • 非认证测试:src/app/tests/suites 中非 certification 目录的测试可以测试任何内容,作为官方测试计划 YAML 的前置或补充。

5.3 将测试接入 CI

CI 接入分两条路径:

  • Python 测试:加入 .github/workflows/tests.yaml,并确保提供脚本所需的全部参数(如 endpoint PIXIT);
  • YAML 测试:编辑 src/app/tests/suites/ciTests.json:
    1. 创建以设备命名的 section(如"MyDevice"),列出该设备的所有 YAML 测试;
    2. 把 section 名加入名为collection的列表;
    3. 执行./scripts/tools/zap_regen_all.py重新生成 ZAP 代码。

5.4 设备类型规格接入测试计划工具

将设备类型规格(device type spec)加入测试计划工具链:

  • 规格数据位于 CHIP-Specifications/chip-test-plans 仓库的 tools/device_type_requirements;
  • 该数据被 Test_TC_DESC_2_1.yaml 使用;
  • 文档注明:规划是让数据模型(DM)工具直接依据规范生成设备类型需求数据,届时上述手工维护将废弃。

5.5 将设备类型加入 Chef

Chef(Matter 的厨房式示例设备集合)在 examples/chef/devices 目录维护设备定义(每台设备对应一对.matter/.zap文件,见仓库目录结构),新设备类型需要同步加入。

6. 常见问题(Q&A)

Q1:测试活动(test events)可以选用哪些设备?能用一个跑在 RasPI 上的示例集群服务器应用吗?独立实现(independent realizations)必须跑在厂商硬件上吗?

A1:可以。其中一个实现可以是"测试工具(test harness)+ all-clusters 示例应用 + RasPI";另外两个独立实现必须跑在目标硬件上——可以是 mock-up(模型机)或原型机(prototype),不要求量产硬件。

Q2:Chef 工具如何用于上述交付物?

A2:TBD(文档尚未补充)。

Q3:如何使用 ZAP 工具自动生成代码并提交到 git 仓库?

A3:在文档中搜索zap_regen(即运行./scripts/tools/zap_regen_all.py),随后把变更的所有文件一并加入提交。

Q4:旧版集群定义在哪里?

A4:src/app/zap-templates/zcl/data-model/silabs/general.xml(即仓库中的 src/app/zap-templates/zcl/data-model/silabs/general.xml)。

Q5:ZAP 工具文档在哪里?

A5:ZAP 官方仓库 README(外部链接,此处不展开)。

7. 最佳实践小结

  • 先规范后编码:一切工作以 Matter 规范评审通过为前提;
  • 清单文件一次配齐zcl.jsonzcl-with-test-extensions.jsonrules.matterlinttests.yaml、Python__init__.py缺一不可,派生集群务必回填基集群的<cluster code>
  • 生成与实现分离:XML 只负责类型/访问器生成,运行时逻辑交给ModeBase::InstanceDelegate;用attributeAccessInterfaceAttributes告知 ZAP 跳过哪些属性;
  • 先 YAML 后 Python:简单测试用 YAML(同步 PICS.yaml),复杂测试用 Python(同步 tests.yaml 参数),认证计划务必对齐官方 Test Plan 模板;
  • 一切以zap_regen_all.py收尾:修改任何 ZAP 相关配置后,运行全量代码生成并提交全部产物。

【免费下载链接】connectedhomeipMatter (formerly Project CHIP) creates more connections between more objects, simplifying development for manufacturers and increasing compatibility for consumers, guided by the Connectivity Standards Alliance.项目地址: https://gitcode.com/GitHub_Trending/co/connectedhomeip

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询