5.2 ZCL 开关命令收发 API
一句话理解
发送开关命令,不用自己拼报文——ZCL 已经封装好 3 个现成 API:开(CmdOn)、关(CmdOff)、反转(CmdToggle)。它们最终都调用 zcl_SendCommand() 发命令。
发送命令 API:现成的"开关遥控器"
在 ZCL 通信过程中,我们以**网关(协调器)→ 智能插座(终端/路由器)**为例。
On/Off 命令是 On/Off Cluster(开关簇)的簇限定命令。打开 Profile/zcl_general.h,可以找到 3 个现成的发送 API:
#ifdef ZCL_ON_OFF
// 发送"关闭"命令
#define zclGeneral_SendOnOff_CmdOff(a,b,c,d) \
zcl_SendCommand( (a), (b), ZCL_CLUSTER_ID_GEN_ON_OFF, COMMAND_OFF, \
TRUE, ZCL_FRAME_CLIENT_SERVER_DIR, (c), 0, (d), 0, NULL )
// 发送"打开"命令
#define zclGeneral_SendOnOff_CmdOn(a,b,c,d) \
zcl_SendCommand( (a), (b), ZCL_CLUSTER_ID_GEN_ON_OFF, COMMAND_ON, \
TRUE, ZCL_FRAME_CLIENT_SERVER_DIR, (c), 0, (d), 0, NULL )
// 发送"反转"命令
#define zclGeneral_SendOnOff_CmdToggle(a,b,c,d) \
zcl_SendCommand( (a), (b), ZCL_CLUSTER_ID_GEN_ON_OFF, COMMAND_TOGGLE, \
TRUE, ZCL_FRAME_CLIENT_SERVER_DIR, (c), 0, (d), 0, NULL )
#endif // ZCL_ON_OFF这 3 个 API 都是 #define 宏,最终都调用 zcl_SendCommand()。
参数速记
zclGeneral_SendOnOff_CmdOn( a, b, c, d );
// a = 源端点号(谁发的)
// b = 目标设备地址(发给谁)
// c = 是否关闭默认响应(通常 TRUE)
// d = 数据包序号(自己维护,每次 +1)核心函数:zcl_SendCommand()
它是 ZCL 层发送命令的总入口(定义在 zcl.h):
extern ZStatus_t zcl_SendCommand(
uint8 srcEP, // 源端点号(发送者的端点)
afAddrType_t *dstAddr, // 目标设备地址
uint16 clusterID, // Cluster ID(发给哪个簇)
uint8 cmd, // 命令 ID(什么命令)
uint8 specific, // 是否为簇限定命令(TRUE=是)
uint8 direction, // 通信方向(Client→Server / 反向)
uint8 disableDefaultRsp, // 是否关闭默认响应
uint16 manuCode, // 厂商代码(非厂商扩展填 0)
uint8 seqNum, // 数据包标识号(自增)
uint16 cmdFormatLen, // 命令数据长度
uint8 *cmdFormat ); // 命令数据内容以 zclGeneral_SendOnOff_CmdOff 为例,看它如何"翻译"成 zcl_SendCommand:
zcl_SendCommand(
(a), // 源端点号
(b), // 目标地址
ZCL_CLUSTER_ID_GEN_ON_OFF, // Cluster ID = 开关簇
COMMAND_OFF, // 命令 = 关闭
TRUE, // TRUE = 簇限定命令
ZCL_FRAME_CLIENT_SERVER_DIR, // 方向:Client → Server
(c), // 是否关闭默认响应
0, // manuCode = 0(非厂商扩展)
(d), // 数据包序号
0, // 命令格式长度 = 0(On/Off 命令无数据)
NULL ); // 命令格式 = 空为什么命令数据是空的?
On/Off 命令本身不需要携带数据——命令 ID(COMMAND_OFF / COMMAND_ON)已经表达了一切。所以长度填 0、内容填 NULL。
接收命令
接收 On/Off 命令很简单:在命令处理函数列表 zclSampleSw_CmdCallbacks 的对应位置填上处理函数即可。
static zclGeneral_AppCallbacks_t zclSampleSw_CmdCallbacks =
{
zclSampleSw_BasicResetCB, // Basic Cluster Reset
NULL, // Identify Trigger Effect
zclSampleSw_OnOffCB, // ← On/Off 命令处理函数(填在这里)
...
};设备收到命令 → 协议栈查回调表 → 调用 zclSampleSw_OnOffCB() 处理。具体的处理函数怎么写,下一节实验揭晓。
小结
发送 = 调现成 API(CmdOn / CmdOff / CmdToggle),它们内部都走 zcl_SendCommand(); 接收 = 在回调表 zclSampleSw_CmdCallbacks 里挂上处理函数。
内容来源:紫甲 IoT《ZigBee 3.0 开发指南》第四部分·5.2 ZCL 开关命令收发 API,原站链接
本章自测
一、单项选择题(每题 4 分,共 40 分)
On/Off 命令是哪个簇的簇限定命令(A. 基础簇 Basic Cluster B. On/Off Cluster(开关簇) C. 组簇 Groups Cluster D. 场景簇 Scenes Cluster) 答案:B
下列不属于 ZCL 现成开关发送 API 的是(A.
zclGeneral_SendOnOff_CmdOnB.zclGeneral_SendOnOff_CmdOffC.zclGeneral_SendOnOff_CmdToggleD.zclGeneral_SendOnOff_CmdDim) 答案:DzclGeneral_SendOnOff_CmdOn / CmdOff / CmdToggle这三个 API 最终都调用(A.zcl_SendRead()B.zcl_SendCommand()C.AF_DataRequest()D.zcl_registerForMsg()) 答案:BzclGeneral_SendOnOff_CmdOn(a, b, c, d)中参数b表示(A. 源端点号(谁发的) B. 目标设备地址(发给谁) C. 是否关闭默认响应 D. 数据包序号) 答案:Bzcl_SendCommand()的specific参数取TRUE表示(A. 通用命令(Global Command) B. 簇限定命令 C. 厂商扩展命令 D. 广播命令) 答案:B发送 On/Off 命令时,
cmdFormatLen和cmdFormat分别填(A. 长度 1,数据为开关状态字节 B. 长度 0、NULL——On/Off 命令本身不携带数据 C. 长度 2,数据为目标短地址 D. 长度等于厂商代码) 答案:Bzcl_SendCommand()中manuCode参数填 0 表示(A. 广播地址 B. 非厂商扩展命令 C. 保留字段必须为 1 D. 命令发送失败) 答案:B智能插座端要接收并处理 On/Off 命令,需要做的是(A. 在
event_loop()中处理ZCL_INCOMING_MSGB. 在回调表zclSampleSw_CmdCallbacks的对应位置填上处理函数(如zclSampleSw_OnOffCB) C. 开启ZCL_READ宏 D. 调用zcl_SendCommand()) 答案:B发送开关命令时,
direction参数通常设置为(A.ZCL_FRAME_CLIENT_SERVER_DIR(Client → Server) B. Server → Client 反向 C. 广播方向 D. 任意方向均可) 答案:AzclGeneral_SendOnOff_CmdOn这三个 API 在代码中的实现形式是(A. 普通 C 函数 B.#define宏,内部展开为对zcl_SendCommand()的调用 C. 中断服务程序 D. OSAL 任务事件) 答案:B
二、问答题(每题 20 分,共 60 分)
- 题干:以网关(协调器)向智能插座发送"打开"命令为例,简述从发送端调用 API 到接收端执行动作的完整过程。 参考答案要点:
- 发送端调用
zclGeneral_SendOnOff_CmdOn(源端点, &目标地址, TRUE, 序号++); - 该宏内部展开为
zcl_SendCommand(),簇 ID 填ZCL_CLUSTER_ID_GEN_ON_OFF,命令 ID 填COMMAND_ON,specific=TRUE(簇限定命令),方向为 Client→Server,manuCode=0,命令数据长度 0、内容 NULL; - 命令经无线网络发到插座;
- 插座协议栈收到命令后查回调表
zclSampleSw_CmdCallbacks,找到 On/Off 处理函数zclSampleSw_OnOffCB()并调用; - 在
zclSampleSw_OnOffCB()中根据命令 ID(COMMAND_ON/COMMAND_OFF)执行打印屏幕、点亮/熄灭 LED 等动作。
- 题干:为什么 On/Off 命令在
zcl_SendCommand()中命令数据长度填 0、命令内容填 NULL? 参考答案要点:
- On/Off 命令本身不需要携带附加数据;
- 命令 ID(
COMMAND_OFF/COMMAND_ON/COMMAND_TOGGLE)本身已经完整表达了"关/开/反转"的含义; - 因此
cmdFormatLen=0、cmdFormat=NULL即可。
- 题干:列出
zcl_SendCommand()的主要参数及其含义(至少写出 6 个)。 参考答案要点:
srcEP:源端点号(发送者的端点);dstAddr:目标设备地址(afAddrType_t *);clusterID:命令发给哪个簇;cmd:命令 ID(什么命令);specific:是否为簇限定命令(TRUE=是);direction:通信方向(Client→Server 或反向);disableDefaultRsp:是否关闭默认响应;manuCode:厂商代码(非厂商扩展填 0);seqNum:数据包标识号(自增);cmdFormatLen/cmdFormat:命令数据长度与内容。