Skip to content

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:

c
#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()。

参数速记 ​

c
zclGeneral_SendOnOff_CmdOn( a, b, c, d );
// a = 源端点号(谁发的)
// b = 目标设备地址(发给谁)
// c = 是否关闭默认响应(通常 TRUE)
// d = 数据包序号(自己维护,每次 +1)

核心函数:zcl_SendCommand() ​

它是 ZCL 层发送命令的总入口(定义在 zcl.h):

c
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:

c
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 的对应位置填上处理函数即可。

c
static zclGeneral_AppCallbacks_t zclSampleSw_CmdCallbacks =
{
  zclSampleSw_BasicResetCB,   // Basic Cluster Reset
  NULL,                       // Identify Trigger Effect
  zclSampleSw_OnOffCB,        // ← On/Off 命令处理函数(填在这里)
  ...
};

设备收到命令 → 协议栈查回调表 → 调用 zclSampleSw_OnOffCB() 处理。具体的处理函数怎么写,下一节实验揭晓。

📡
网关
zclGeneral_SendOnOff_CmdOn / CmdOff 发命令
→ 无线 →
🔌
智能插座
协议栈查回调表 → zclSampleSw_OnOffCB() 执行开关

小结

发送 = 调现成 API(CmdOn / CmdOff / CmdToggle),它们内部都走 zcl_SendCommand(); 接收 = 在回调表 zclSampleSw_CmdCallbacks 里挂上处理函数。

内容来源:紫甲 IoT《ZigBee 3.0 开发指南》第四部分·5.2 ZCL 开关命令收发 API,原站链接


本章自测 ​

一、单项选择题(每题 4 分,共 40 分) ​

  1. On/Off 命令是哪个簇的簇限定命令(A. 基础簇 Basic Cluster B. On/Off Cluster(开关簇) C. 组簇 Groups Cluster D. 场景簇 Scenes Cluster) 答案:B

  2. 下列不属于 ZCL 现成开关发送 API 的是(A. zclGeneral_SendOnOff_CmdOn B. zclGeneral_SendOnOff_CmdOff C. zclGeneral_SendOnOff_CmdToggle D. zclGeneral_SendOnOff_CmdDim) 答案:D

  3. zclGeneral_SendOnOff_CmdOn / CmdOff / CmdToggle 这三个 API 最终都调用(A. zcl_SendRead() B. zcl_SendCommand() C. AF_DataRequest() D. zcl_registerForMsg()) 答案:B

  4. zclGeneral_SendOnOff_CmdOn(a, b, c, d) 中参数 b 表示(A. 源端点号(谁发的) B. 目标设备地址(发给谁) C. 是否关闭默认响应 D. 数据包序号) 答案:B

  5. zcl_SendCommand() 的 specific 参数取 TRUE 表示(A. 通用命令(Global Command) B. 簇限定命令 C. 厂商扩展命令 D. 广播命令) 答案:B

  6. 发送 On/Off 命令时,cmdFormatLen 和 cmdFormat 分别填(A. 长度 1,数据为开关状态字节 B. 长度 0、NULL——On/Off 命令本身不携带数据 C. 长度 2,数据为目标短地址 D. 长度等于厂商代码) 答案:B

  7. zcl_SendCommand() 中 manuCode 参数填 0 表示(A. 广播地址 B. 非厂商扩展命令 C. 保留字段必须为 1 D. 命令发送失败) 答案:B

  8. 智能插座端要接收并处理 On/Off 命令,需要做的是(A. 在 event_loop() 中处理 ZCL_INCOMING_MSG B. 在回调表 zclSampleSw_CmdCallbacks 的对应位置填上处理函数(如 zclSampleSw_OnOffCB) C. 开启 ZCL_READ 宏 D. 调用 zcl_SendCommand()) 答案:B

  9. 发送开关命令时,direction 参数通常设置为(A. ZCL_FRAME_CLIENT_SERVER_DIR(Client → Server) B. Server → Client 反向 C. 广播方向 D. 任意方向均可) 答案:A

  10. zclGeneral_SendOnOff_CmdOn 这三个 API 在代码中的实现形式是(A. 普通 C 函数 B. #define 宏,内部展开为对 zcl_SendCommand() 的调用 C. 中断服务程序 D. OSAL 任务事件) 答案:B

二、问答题(每题 20 分,共 60 分) ​

  1. 题干:以网关(协调器)向智能插座发送"打开"命令为例,简述从发送端调用 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 等动作。
  1. 题干:为什么 On/Off 命令在 zcl_SendCommand() 中命令数据长度填 0、命令内容填 NULL? 参考答案要点:
  • On/Off 命令本身不需要携带附加数据;
  • 命令 ID(COMMAND_OFF / COMMAND_ON / COMMAND_TOGGLE)本身已经完整表达了"关/开/反转"的含义;
  • 因此 cmdFormatLen=0、cmdFormat=NULL 即可。
  1. 题干:列出 zcl_SendCommand() 的主要参数及其含义(至少写出 6 个)。 参考答案要点:
  • srcEP:源端点号(发送者的端点);
  • dstAddr:目标设备地址(afAddrType_t *);
  • clusterID:命令发给哪个簇;
  • cmd:命令 ID(什么命令);
  • specific:是否为簇限定命令(TRUE=是);
  • direction:通信方向(Client→Server 或反向);
  • disableDefaultRsp:是否关闭默认响应;
  • manuCode:厂商代码(非厂商扩展填 0);
  • seqNum:数据包标识号(自增);
  • cmdFormatLen / cmdFormat:命令数据长度与内容。

aioteer · 物联网专业课程群

💬AI 伴学配置