欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

[silicon][EmberZnet]router响应write attribute命令并读取存储的attribute值

程序员文章站 2021-11-30 12:11:02
前言最近在研究芯科平台zigbee cluster的扩展,之所以要扩展标准的cluster,是因为我司的zigbee开关需要做一些定制的功能,扩展的方案大致如下:clusterattributenametypeRangeAccessDefaultreset Keep0x00060x8000Modeuint80x00-0xffRW0x00yesMode attribute用来描述继电器是否跟随开关动作的值:0 = 继电器模式(按下开关,控制继电器...

前言

最近在研究芯科平台zigbee cluster的扩展,之所以要扩展标准的cluster,是因为我司的zigbee开关需要做一些定制的功能,扩展的方案大致如下:

cluster attribute name type Range Access Default reset Keep
0x0006 0x8000 Mode uint8 0x00-0xff RW 0x00 yes

Mode attribute

  • 用来描述继电器是否跟随开关动作的值:

    0 = 继电器模式(按下开关,控制继电器,然后上报状态)

    1 = 遥控模式(按下开关,继电器不工作(保持闭合),只上报状态)

熟悉zigbee cluster的同学应该知道,上述是基于on/off这个cluster进行扩展的,添加了一个新的attribute,attribute ID为0x8000。这个attribute主要用来描述开关的模式,0代表按下开关的时候,通过继电器控制连接的灯;1代表按下开关后,只上报当前开关按键的状态值,不再控制继电器的闭合。

其实这个扩展是基于以下这种场景的一个开发需求:

假如一个开关(router)通过继电器控制一个同样支持zigbee的灯(router),然后这两个设备都通过zigbee的方式连接了coordinator。一般情况下,我们都是习惯通过开关来控制灯的亮灭。但是现在这种场景下,如果把开关闭合了,那么相当于直接把灯断电了,这时候coordinator就以为灯是离线了,而不会觉得这个是关闭的状态,所以coordinator上看到的状态就不对。

所以如果灯是支持zigbee的话,开关就不再通过继电器来控制灯,而是简单的上报一个状态值告诉coordinator,由coordinator去控制相应的灯,这样各个设备的状态值就正常了。

就是基于以上的需求,我们的开关需要一个attribute来记录此时处于一个什么模式,这个模式值由coordinator来下发一个write attribute命令来改变。

正文

1、扩展标准cluster

其实扩展标准的cluster,芯科官方有给出指导:

https://github.com/MarkDing/IoT-Developer-Boot-Camp/wiki/Zigbee-Custom-Clusters-CN

在完全按照指导文档来扩展的文件如下:

<configurator>
  <domain name="Test" />
  
  <!-- Use the cluster extension Extend the on/off cluster -->
  <clusterExtension code="0x0006"> 
    <attribute side="server" code="0x8000" 
      define="SWITCH_Mode" 
      type="INT8U" min="0x0000" max="0xFFFF" writable="true" 
      default="0x0000" optional="true" 
      manufacturerCode="0x128e">Mode</attribute>
  </clusterExtension>
  
</configurator>

[silicon][EmberZnet]router响应write attribute命令并读取存储的attribute值

但是升级完后,每次coordinator下发一个write attribute的命令,router都无法正常响应:

write attribute:

命令类似如下

  • zcl global write 0x06 0x8000 0x20 {01}
  • send 0x7F07 1 1

[silicon][EmberZnet]router响应write attribute命令并读取存储的attribute值

response:

[silicon][EmberZnet]router响应write attribute命令并读取存储的attribute值

每次都响应一个"[0x86] unsupported attribute"的错误码,在芯科的论坛咨询后,如果想用通用的命令就不能定义私有的manufactureCode:

<configurator>
  <domain name="Test" />
  
  <!-- Use the cluster extension Extend the on/off cluster -->
  <clusterExtension code="0x0006"> 
    <attribute side="server" code="0x8000" 
      define="SWITCH_Mode" 
      type="INT8U" min="0x0000" max="0xFFFF" writable="true" 
      default="0x0000" optional="true" >Mode</attribute>
	  
	<command source="client" code="0x00" 
      name="ModeChange" optional="true" manufacturerCode="0x128e">
      <description>Change the switch mode. 0=switch mode, 1=remote control mode.</description>
    </command>
  </clusterExtension>
  
</configurator>

之后router就能正常respond了:

[silicon][EmberZnet]router响应write attribute命令并读取存储的attribute值

2、读取自身的attribute值

既然coordinator下发了一个attribute值到router,那么router怎么能读到这个值呢?SDK的代码肯定也是提供了相应的接口给开发者使用的。在我们的开关代码中,当按下开关我们就会去读取一下Mode这个attribute值,来判断此时处于什么模式下:

void emberAfHalButtonIsrCallback(uint8_t button, uint8_t state)
{
	uint8_t  readLength;

	if (button == BSP_BUTTON1_PIN) {
		if (state == PRESS) {
			emberAfReadAttribute(1,ZCL_ON_OFF_CLUSTER_ID,ZCL_SWITCH_Mode_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, &readLength, sizeof(readLength), NULL);
		}
	}
}

其实就是一个简单的接口,把读取到的数据保存到定义的变量readLength中:

EmberAfStatus emberAfReadAttribute(uint8_t endpoint,
                                   EmberAfClusterId cluster,
                                   EmberAfAttributeId attributeID,
                                   uint8_t mask,
                                   uint8_t *dataPtr,
                                   uint8_t readLength,
                                   EmberAfAttributeType *dataType);

结语

说实话,扩展标准的cluster来定制自己的私有协议并不是一个很好的方案,毕竟私有的协议只有你自己家的产品能用,并不通用。这也是zigbee到现在都不是很流行的原因,因为各大厂家都是自己玩自己的,不过这是其它的话题了,这里不详细展开。

本文地址:https://blog.csdn.net/lee_jimmy/article/details/109647514