4. Matter数据模型与设备类型定义
Matter 的数据模型是整份规范中最需要“先想清楚再动手”的部分。它决定了设备在网络上如何被描述、被控制、被订阅,也决定了 ZAP 工具里每一个勾选项最终会变成什么样的代码。很多初学者在 ZAP 里点了一堆 Cluster,编译通过、设备也能上线,但控制器读到的属性名对不上、命令发过去没反应,根源往往不是代码写错,而是数据模型的层级关系没有理顺。
Matter 的数据模型是一棵树,从根往下依次是:Node(节点)→ Endpoint(端点)→ Cluster(簇)→ Attribute / Command / Event(属性 / 命令 / 事件)。Node 代表一个物理设备整体,比如一盏灯、一个温控器;Endpoint 是节点内部可独立寻址的功能单元,编号从 0 开始;Cluster 是功能的集合,是规范定义的最小功能单元;Attribute、Command、Event 则是 Cluster 内部真正承载数据和行为的成员。理解这棵树的关键在于:寻址路径永远是“Endpoint + Cluster + 成员”三级定位,控制器发一条命令,报文里一定带着目标 Endpoint ID 和 Cluster ID。
Endpoint 0 是特殊端点,称为根端点,它承载基础信息簇(Basic Information,0x0028)、网络调试簇、通用描述簇等所有节点都必须具备的功能。业务功能通常从 Endpoint 1 开始编号。一个节点可以有多个同类型 Endpoint,例如双路开关的 Endpoint 1 和 Endpoint 2 都是 On/Off 灯,控制器通过不同的 Endpoint ID 区分它们。这就是为什么在 ZAP 里配置设备时,第一步永远是规划 Endpoint 的数量和用途,而不是急着勾 Cluster。
Cluster 是规范定义的功能单元,每个 Cluster 有唯一的 16 位 ID。On/Off 是 0x0006,Level Control 是 0x0008,Temperature Measurement 是 0x0402。Cluster 分为服务器端(Server)和客户端(Client):服务器端是功能的提供者,持有属性和事件、接收命令;客户端是功能的使用者,发送命令、接收属性报告。一盏灯在 Endpoint 1 上实现 On/Off Server,而它的遥控器则在某个 Endpoint 上实现 On/Off Client。ZAP 配置时必须明确每个 Cluster 的方向,方向搞反,代码里就不会生成对应的命令处理函数。
Attribute 是 Cluster 的状态数据,有明确的数据类型和访问权限。以 On/Off Cluster 为例,OnOff 属性 ID 为 0x0000,类型是布尔,权限为可读、可报告、可订阅。Attribute 还分“必需”和“可选”:OnOff 是必需的,而 OnTime、StartUpOnOff 是可选属性。ZAP 里勾选可选属性会直接增加 RAM 占用和代码体积,因此原则是“只勾真正需要的”。Command 是 Cluster 的行为,On/Off 定义了 Off、On、Toggle 三个命令,其中 Toggle 是必需的。Event 是 Cluster 在特定时刻产生的通知,例如 Switch Cluster 的 SwitchLatched 事件,它和 Attribute 的区别在于:Attribute 表达“现在是什么状态”,Event 表达“刚刚发生了什么”。
理解了模型,ZAP 的配置流程就顺理成章。ZAP(ZCL Advanced Platform)是 Silicon Labs 提供的图形化配置工具,它把数据模型配置和代码生成串在一起。典型流程是:在 Simplicity Studio 中打开工程的 .zap 文件,先创建 Endpoint,再为每个 Endpoint 添加 Cluster,然后逐个 Cluster 勾选 Attribute、Command、Event,最后点击 Generate 生成代码。生成的核心产物包括:zap-generated/endpoint_config.h(端点与簇的静态配置)、zap-generated/attribute-size.h、zap-generated/gen_config.h,以及各 Cluster 的回调函数声明。开发者需要实现的是回调函数体,而不是手写属性表。
下面是一段典型的 ZAP 配置片段,描述一个灯设备在 Endpoint 1 上实现 On/Off Server 与 Level Control Server:
Endpoint 1: "Light"
Device Type: On/Off Light (0x0100)
Clusters:
- Descriptor (0x001D) Server [必需]
- Identify (0x0003) Server [必需]
- Groups (0x0004) Server [必需]
- Scenes (0x0005) Server [可选]
- On/Off (0x0006) Server [必需]
Attribute: OnOff (0x0000) bool R P S
Command: Off / On / Toggle
- Level Control (0x0008) Server [可选]
Attribute: CurrentLevel (0x0000) uint8 R P S
Attribute: MinLevel (0x0002) uint8 R
Attribute: MaxLevel (0x0003) uint8 R
Command: MoveToLevel / Step / Stop
生成代码后,属性读写由框架统一处理,开发者只需在回调里响应命令。例如 On/Off Server 的 Toggle 命令,ZAP 会生成 emberAfOnOffClusterToggleCallback 的声明,实现时通常先翻转本地状态,再调用 emberAfWriteServerAttribute 更新 OnOff 属性,最后通过 emberAfReportAttribute 或订阅机制通知控制器。这里有一个容易踩的坑:如果只改了本地变量而没有写回 Attribute,控制器订阅到的值不会变化,表现为“灯亮了但 App 显示还是关”。
src/light_onoff.c。配置完成后如何判断是否正确?可以从三个层面验证。第一,编译后检查 endpoint_config.h 中 Endpoint 1 的 Cluster 列表是否与 ZAP 勾选一致;第二,设备上线后用 chip-tool 读取属性,例如 chip-tool onoff read on-off 1 1,其中第一个 1 是 Endpoint,第二个 1 是节点 ID,能读到值说明 Attribute 路径正确;第三,发送命令 chip-tool onoff toggle 1 1,观察设备动作和属性回读是否同步。如果读属性返回 UNSUPPORTED_CLUSTER,通常是 Cluster 方向配反或 Endpoint 编号写错;如果命令无响应,检查回调函数是否被正确注册。
最后强调一个工程习惯:在 ZAP 里配置之前,先用一张表把 Endpoint、Cluster、Attribute 的规划写清楚,包括每个 Endpoint 的设备类型、每个 Cluster 的方向、需要暴露的属性和命令。这份规划表既是配置依据,也是后期排障的对照基准。Matter 数据模型的价值不在于记住多少个 Cluster ID,而在于建立“任何一次访问都能被三级路径唯一定位”的思维,ZAP 只是把这套模型翻译成代码的工具。