Skip to content

6.1 ZCL 属性读写 API ​

一句话理解

属性就是设备的数据项。要远程读/写它,只需要:① 在属性列表里定义好属性 → ② 用 zcl_SendRead() / zcl_SendWrite() 发命令 → ③ 在 ZCL_INCOMING_MSG 事件里处理响应。

添加属性:在属性列表里"建档" ​

设备用到的所有属性都要在属性列表中定义。打开 zcl_samplesw_data.c,属性列表 zclSampleSw_Attrs 里有这样一个元素:

c
{
  ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG,   // 添加到的 Cluster
  {                                          // Attribute record(属性记录)
    ATTRID_ON_OFF_SWITCH_ACTIONS,            // 属性 ID:开关动作
    ZCL_DATATYPE_ENUM8,                      // 数据类型:8 位枚举
    ACCESS_CONTROL_READ | ACCESS_CONTROL_WRITE, // 访问权限:可读可写
    (void *)&zclSampleSw_OnOffSwitchActions   // 属性值存储位置
  }
}

以属性 ATTRID_ON_OFF_SWITCH_ACTIONS 为例:

  • 数据类型是 8 位枚举(ZCL_DATATYPE_ENUM8);
  • 权限是可读可写(ACCESS_CONTROL_READ | ACCESS_CONTROL_WRITE);
  • 它被添加进 ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG 这个簇。

类比

属性列表就像员工档案柜:每个档案注明"属于哪个部门(Cluster)、叫什么(属性ID)、什么类型、谁能看谁能改(权限)"。

属性读写命令 API ​

打开 zcl.h,找到属性读写 API:

c
#ifdef ZCL_READ
// 发送一个"读取属性"命令
extern ZStatus_t zcl_SendRead(
  uint8 srcEP,           // 源端点号
  afAddrType_t *dstAddr, // 目标设备地址
  uint16 realClusterID,  // Cluster ID(属性属于哪个簇)
  zclReadCmd_t *readCmd, // "读"信息(读哪些属性)
  uint8 direction,       // 通信方向
  uint8 disableDefaultRsp, // 是否关闭默认响应
  uint8 seqNum );        // 数据包序号(自增)
#endif // ZCL_READ

#ifdef ZCL_WRITE
// 发送一个"写入属性"命令
#define zcl_SendWrite(a,b,c,d,e,f,g) \
  (zcl_SendWriteRequest( (a), (b), (c), (d), ZCL_CMD_WRITE, (e), (f), (g) ))
#endif // ZCL_WRITE

注意:使用前要开启宏 ZCL_READ 和 ZCL_WRITE(工程 Options → Defined symbols)。

命令处理:响应来了怎么办 ​

客户端发命令后,服务端会返回响应,并产生系统事件 ZCL_INCOMING_MSG。在 zclSampleSw_event_loop() 中:

c
case ZCL_INCOMING_MSG:
  // Incoming ZCL Foundation command/response messages
  zclSampleSw_ProcessIncomingMsg( (zclIncomingMsg_t *)MSGpkt );
  break;

zclSampleSw_ProcessIncomingMsg() 里按命令 ID 分流:

c
static void zclSampleSw_ProcessIncomingMsg( zclIncomingMsg_t *pInMsg )
{
  switch ( pInMsg->zclHdr.commandID )
  {
#ifdef ZCL_READ
    case ZCL_CMD_READ_RSP:    // 读命令响应
      zclSampleSw_ProcessInReadRspCmd( pInMsg );
      break;
#endif
#ifdef ZCL_WRITE
    case ZCL_CMD_WRITE_RSP:   // 写命令响应
      zclSampleSw_ProcessInWriteRspCmd( pInMsg );
      break;
#endif
    case ZCL_CMD_DEFAULT_RSP: // 默认响应
      zclSampleSw_ProcessInDefaultRspCmd( pInMsg );
      break;
    default:
      break;
  }
  if ( pInMsg->attrCmd )
    osal_mem_free( pInMsg->attrCmd );  // 释放消息内存
}

三种响应:搞懂"回执"的含义 ​

📨
默认响应
发送命令时可指定是否需要。客户端据此确认"服务端确实收到了命令"
📖
读响应(READ_RSP)
服务端返回读取结果:属性是否读成功 + 属性值
✍️
写响应(WRITE_RSP)
服务端返回写入结果:属性值是否写入成功

小结

属性读写三步走:

  1. 建档:属性列表里定义属性(Cluster + 属性ID + 类型 + 权限);
  2. 发令:zcl_SendRead() / zcl_SendWrite();
  3. 收据:在 ZCL_INCOMING_MSG 里处理读/写响应。

内容来源:紫甲 IoT《ZigBee 3.0 开发指南》第四部分·6.1 ZCL 属性读写 API,原站链接


本章自测 ​

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

  1. 在属性列表 zclSampleSw_Attrs 中定义一个属性时,不需要给出的信息是(A. 属性所属的 Cluster B. 属性 ID 与数据类型 C. 访问权限与属性值存储位置 D. 发送命令的周期) 答案:D

  2. 示例属性 ATTRID_ON_OFF_SWITCH_ACTIONS 的数据类型是(A. ZCL_DATATYPE_UINT8 B. ZCL_DATATYPE_ENUM8(8 位枚举) C. ZCL_DATATYPE_CHAR_STR D. ZCL_DATATYPE_BOOLEAN) 答案:B

  3. 示例属性的访问权限设置为(A. 只读 ACCESS_CONTROL_READ B. 只写 ACCESS_CONTROL_WRITE C. ACCESS_CONTROL_READ | ACCESS_CONTROL_WRITE(可读可写) D. 不可访问) 答案:C

  4. 示例属性被添加进哪个簇(A. ZCL_CLUSTER_ID_GEN_ON_OFF B. ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG C. ZCL_CLUSTER_ID_GEN_BASIC D. ZCL_CLUSTER_ID_GEN_LEVEL_CTRL) 答案:B

  5. 客户端要远程读取设备属性,使用哪个 API(A. zcl_SendWrite() B. zcl_SendRead() C. zcl_SendCommand() D. zcl_registerAttrList()) 答案:B

  6. 宏 zcl_SendWrite(a,b,c,d,e,f,g) 展开后最终调用的函数与命令字是(A. zcl_SendReadRequest B. zcl_SendWriteRequest(),命令字为 ZCL_CMD_WRITE C. zcl_SendCommand() D. zclGeneral_RegisterCmdCallbacks()) 答案:B

  7. 客户端发出属性读写命令后,服务端返回响应时在客户端产生哪个系统事件(A. ZDO_CB_MSG B. ZCL_INCOMING_MSG C. AF_DATA_CONFIRM_CMD D. SYS_EVENT_MSG) 答案:B

  8. 在 zclSampleSw_ProcessIncomingMsg() 的 switch 中,读命令响应对应哪个 case(A. ZCL_CMD_WRITE_RSP B. ZCL_CMD_READ_RSP C. ZCL_CMD_DEFAULT_RSP D. ZCL_CMD_REPORT) 答案:B

  9. 使用属性读/写 API 前,工程预编译宏中必须开启(A. ZCL_READ 和 ZCL_WRITE B. ZCL_ON_OFF C. ZCL_GROUPS D. ZCL_SCENES) 答案:A

  10. 关于三种"回执",下列说法错误的是(A. 默认响应用于让客户端确认服务端确实收到了命令 B. 读响应返回属性是否读成功以及属性值 C. 写响应返回属性值是否写入成功 D. 写响应中必须携带属性当前值) 答案:D

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

  1. 题干:请按页面"小结"列出 ZCL 属性读写的三步流程,并说明每一步做什么。 参考答案要点:
  • 第一步"建档":在属性列表 zclSampleSw_Attrs(zcl_samplesw_data.c)中定义属性,注明所属 Cluster、属性 ID、数据类型、访问权限和属性值存储位置;
  • 第二步"发令":客户端用 zcl_SendRead() 发读命令、用 zcl_SendWrite() 发写命令;
  • 第三步"收据":响应到达时产生 ZCL_INCOMING_MSG 事件,在 zclSampleSw_ProcessIncomingMsg() 中按 commandID 分流到 zclSampleSw_ProcessInReadRspCmd() / zclSampleSw_ProcessInWriteRspCmd() 处理;处理完释放 pInMsg->attrCmd 内存。
  1. 题干:一条属性记录(Attribute record)包含哪些关键信息?请以 ATTRID_ON_OFF_SWITCH_ACTIONS 为例说明。 参考答案要点:
  • 所属 Cluster:ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG;
  • 属性 ID:ATTRID_ON_OFF_SWITCH_ACTIONS(开关动作);
  • 数据类型:ZCL_DATATYPE_ENUM8(8 位枚举);
  • 访问权限:ACCESS_CONTROL_READ | ACCESS_CONTROL_WRITE(可读可写);
  • 属性值存储位置:(void *)&zclSampleSw_OnOffSwitchActions。
  1. 题干:默认响应、读响应(READ_RSP)、写响应(WRITE_RSP)三者各自的含义是什么? 参考答案要点:
  • 默认响应:发送命令时可指定是否需要,客户端据此确认"服务端确实收到了命令";
  • 读响应(READ_RSP):服务端返回读取结果,包括属性是否读成功以及读到的属性值;
  • 写响应(WRITE_RSP):服务端返回写入结果,即属性值是否写入成功。

aioteer · 物联网专业课程群

💬AI 伴学配置