端点描述 Cluster(Descriptor)

Cluster ID: 0x001D  |  所在 Endpoint: 每个 Endpoint 都必须有(包括 Endpoint 0)

Descriptor 是 Matter 协议中最基础的 Cluster,它回答一个核心问题:这个 Endpoint 上有什么? Controller(手机、音箱、Hub)连上一个 Matter 设备后,第一件事就是读取各个 Endpoint 的 Descriptor, 从而知道设备支持哪些 Device Type、实现了哪些 Cluster、以及端点之间的层级关系。

这个 Cluster 是纯只读的 —— 没有任何 Command,只有 Attribute。设备在出厂时就决定了这些信息,运行时不会改变。

强制要求:每个 Endpoint 都必须实现 Descriptor

Descriptor Cluster 是 Matter 规范中的硬性要求(Mandatory)。 无论是 Endpoint 0(Root Node)还是功能端点(Endpoint 1、2、3...),都必须包含 Descriptor Cluster。 如果你的设备缺少它,将无法通过 Matter 认证,Controller 也无法正确识别设备能力。

Descriptor 解决什么问题

Matter 设备的数据模型是树状结构:一个 Node(物理设备)包含多个 Endpoint,每个 Endpoint 代表一个功能单元。 但 Controller 连上设备时,并不知道这棵树长什么样。Descriptor 就是这棵树的自描述机制:

  • DeviceTypeList —— 告诉 Controller "我是什么"(门锁?灯?开关?)
  • ServerList / ClientList —— 告诉 Controller "我能做什么"(支持哪些 Cluster)
  • PartsList —— 告诉 Controller "我下面还有谁"(子端点列表)
Endpoint 0 的特殊地位

Endpoint 0 是 Root Node(根节点),它的 Descriptor 有特殊含义:

  • 它的 PartsList 列出了该设备所有其他 Endpoint 的编号,是设备发现的起点
  • Controller 的标准流程是:先读 Endpoint 0 的 PartsList,拿到所有端点编号,再逐个读取每个端点的 Descriptor
  • Root Node 的 DeviceType 是 0x0016(Root Node Device Type)

属性总览

Descriptor 只有 5 个属性,但每个都至关重要。点击属性 ID 可跳转到详细说明。

ID 名称 类型 必选 说明
0x0000 DeviceTypeList list<DeviceTypeStruct> 是 端点支持的 Device Type 列表
0x0001 ServerList list<cluster_id> 是 端点实现的 Server Cluster 列表
0x0002 ClientList list<cluster_id> 是 端点实现的 Client Cluster 列表
0x0003 PartsList list<endpoint_id> 是 子端点编号列表
0x0004 TagList list<SemanticTagStruct> 否 语义标签列表(用于区分同类端点)

属性详解

DeviceTypeList(0x0000)

列出该端点支持的所有 Device Type。每个条目是一个 DeviceTypeStruct,包含设备类型 ID 和版本号。 大多数端点只有一个 Device Type,但规范允许一个端点同时声明多个。

DeviceTypeStruct 结构

字段 类型 说明
DeviceType devtype_id (uint32) Device Type ID,如 0x000A = Door Lock,0x0100 = On/Off Light
Revision uint16 该 Device Type 定义的版本号,用于区分不同规范版本间的差异
常见 Device Type ID

0x0016 Root Node  |  0x000A Door Lock  |  0x0100 On/Off Light  |  0x010D Extended Color Light  |  0x000E Aggregator (Bridge)  |  0x0107 Dimmable Light

ServerList(0x0001)

列出该端点作为 Server 实现的所有 Cluster ID。 所谓 Server,就是"持有数据、响应读写请求"的一方。 例如一把门锁的 Endpoint 1 的 ServerList 会包含 0x0101(DoorLock), 因为锁的状态(是否上锁、用户列表等)存储在设备端。

Controller 通过读取 ServerList,就知道可以对这个端点发送哪些 Cluster 的读/写/命令请求。

ClientList(0x0002)

列出该端点作为 Client 实现的所有 Cluster ID。 Client 是"发起请求"的一方 —— 大多数终端设备(灯、锁、传感器)的 ClientList 为空, 因为它们只被控制,不主动控制别人。

ClientList 非空的典型场景:物理开关(Switch)。 一个墙壁开关会在 ClientList 中声明 0x0006(OnOff Client), 表示它会主动向灯具发送开关命令。

PartsList(0x0003)

列出该端点的子端点编号。这个属性定义了端点之间的层级关系。

PartsList 的两种用法

在 Endpoint 0(Root Node)上:

  • PartsList 是一个扁平列表,包含该节点上所有其他 Endpoint 的编号
  • 这是 Controller 发现设备全部功能端点的唯一入口
  • 例如:[1, 2, 3] 表示设备还有 3 个功能端点

在功能端点上(Endpoint 1, 2, 3...):

  • 大多数情况下为空列表(叶子端点,没有子端点)
  • 只有 Bridge / Aggregator 设备的端点才会有非空的 PartsList,指向其桥接的子设备端点

TagList(0x0004)— 可选

为端点附加语义标签,用于区分功能相同但位置或用途不同的端点。 例如一个设备有两个温度传感器端点,可以通过 TagList 标记一个是"室内",另一个是"室外"。

TagList 需要设备声明 TAGLIST Feature(Feature Bit 0)才会出现。

SemanticTagStruct 结构

字段 类型 说明
MfgCode vendor_id (nullable) 厂商代码。null 表示使用标准定义的标签,非 null 表示厂商自定义标签
NamespaceID uint8 标签命名空间 ID,定义标签的分类体系
Tag uint8 标签值,在对应 Namespace 下的具体含义
Label string (nullable) 可选的人类可读标签文字,如 "Indoor"、"Left"

Controller 如何使用 Descriptor 发现设备

Controller 连上一个 Matter 设备后,标准的端点发现流程如下:

  1. 读取 Endpoint 0 的 PartsList —— 拿到所有功能端点编号,如 [1, 2, 3]
  2. 遍历每个端点,读取 DeviceTypeList —— 知道 Endpoint 1 是门锁、Endpoint 2 是温度传感器...
  3. 读取 ServerList —— 知道每个端点具体支持哪些 Cluster(能做哪些操作)
  4. 根据以上信息构建 UI —— 门锁端点显示开锁按钮,温度传感器端点显示温度数值
Wildcard Read 的替代方案

实际开发中,Controller 通常不会逐个属性读取,而是使用 Wildcard Read(通配符读取) 一次性读取所有 Endpoint 的 Descriptor Cluster,效率更高。 但理解上面的逐步流程有助于理解 Descriptor 各属性的作用。

动手试试:从原始数据里读出设备类型

打开 JSON 解析器,点“设备原始数据”示例再点解析,就能看到一把门锁的 DeviceTypeList、ServerList、PartsList 被逐项翻译成设备类型和 Cluster 名称。 DeviceTypeList 里的数字(如 10 = 0x000A 门锁)可以在 Matter ID 查询 里查到。

示例数据

场景一:普通设备(门锁)

Endpoint 0(Root Node)的 Descriptor:

{
  // Endpoint 0(Root Node)的 Descriptor
  "DeviceTypeList": [
    { "DeviceType": "0x0016", "Revision": 2 }   // Root Node
  ],
  "ServerList": [
    "0x001D",   // Descriptor
    "0x0028",   // BasicInformation
    "0x002F",   // PowerSource
    "0x0030",   // GeneralCommissioning
    "0x0031",   // NetworkCommissioning
    "0x003E",   // OperationalCredentials
    "0x0033"    // GeneralDiagnostics
  ],
  "ClientList": [],
  "PartsList": [ 1, 2, 3 ]   // 该节点还有 Endpoint 1、2、3
}

Endpoint 1(门锁功能端点)的 Descriptor:

{
  // Endpoint 1(功能端点,比如一把门锁)的 Descriptor
  "DeviceTypeList": [
    { "DeviceType": "0x000A", "Revision": 3 }   // DoorLock
  ],
  "ServerList": [
    "0x001D",   // Descriptor(自身)
    "0x0003",   // Identify
    "0x0101",   // DoorLock
    "0x002F"    // PowerSource
  ],
  "ClientList": [],
  "PartsList": []   // 叶子端点,没有子端点
}

场景二:Bridge 设备

Bridge(网关/桥接器)的 Endpoint 0 的 PartsList 会列出所有桥接的子设备:

{
  // Endpoint 0(Bridge 设备)的 Descriptor
  "DeviceTypeList": [
    { "DeviceType": "0x000E", "Revision": 2 }   // Aggregator(Bridge)
  ],
  "ServerList": [ "0x001D", "0x0028", "0x0039" ],
  "PartsList": [ 1, 2, 3, 4, 5 ]   // 桥接了 5 个子设备

  // 每个子端点(1~5)各自有独立的 Descriptor,
  // 描述各自的 DeviceType 和 Cluster 列表
}
开发提示

调试时如果发现 Controller 无法识别设备的某个功能,优先检查 Descriptor:

  • Endpoint 0 的 PartsList 是否包含了该功能端点?
  • 功能端点的 DeviceTypeList 是否正确?
  • 功能端点的 ServerList 是否包含了所需的 Cluster?