1.Zigbee分布式联动功能介绍
Zigbee分布式联动功能将原本存储在云端的联动规则下放到各个Zigbee子设备中进行存储,下发成功后,不再依赖Zigbee网关可以脱离外网进行联动触发,可以降低对网关和云端的依赖,提高联动触发的稳定性。
分布式联动设备分为条件设备和执行设备两种,条件设备作为联动的触发端,当条件设备的dp发生变化的时候它会广播自身的dp值发生了变化。
当相关的执行设备接收到这条广播,会检查自身存储的联动规则中条件是否包括了该设备的该dp,并且该dp变化恰好导致了条件被满足。如果联动规则条件满足,则会触发动作执行。
比如我们配置了一条分布式联动规则,当门磁触发打开时(dp1=1时)灯执行开灯动作。那么当门磁本地触发打开时,门磁会向外广播一条命令通知网络中的设备当前它的dp1已经变成了1,当网络中的灯收到了这条命令发现其配置的联动规则中条件恰好满足,那么它会执行开启的动作。
另外,联动规则条件除了dp外,还支持日期定时和周期定时,可以更加灵活的周期性操作设备。
此外,我们还支持无条件联动,类似于原本的一键执行,用户可以通过点击app上的联动标识直接触发该联动。
同时可以通过设备绑定某个联动规则,可以通过该设备本地按键来操作某个联动规则,类似于原来的场景开关功能。
点击下列链接,查看zigbee分布式联动演示视频:
https://images.tuyacn.com/rms-static/95 ... %A4%BA.mp4
2.Zigbee分布式联动子设备应用开发
版本要求:
Zigbee子设备:Tuyaos 3.11.0版本及以上
网关版本:有线网关8196 1.26.x版本及以上
需要特定的APP支持,同时产品pid需要开通分布式能力标位,具体请联系涂鸦产品经理
2.1 应用需要使用分布式联动能力时需要配置相关的能力值
目前能力值已经扩展到 11个 4bits,如上图中 TZ30001000000 其中第5个字符 (不包括TZ字符) 的bit0表示分布式能力
当作为动作设备时,网关会来查询存储的分布式联动,存储的联动较多时需要使用分包组件,sdk已经默认支持分包组件,但需要用户开启分包能力bit
如上图中 TZ32801000000
2.2 应用需要使用分布式联动能力时,需要引用tal_zigbee_local_init.h 头文件。
在
Code: Select all
OPERATE_RET tuya_init_first(VOID_T)
中调用
Code: Select all
VOID_T tal_zigbee_local_auto_func_enable(VOID_T);
2.3 默认强电设备只支持动作设备,低功耗设备只支持条件设备
用户可以重新定义以下函数进行修改支持动作设备还是条件设备,但注意低功耗设备由于休眠原因,作为动作设备时需要格外注意数据是否都可以正常接收及执行
Code: Select all
BOOL_T __tal_inner_local_auto_action_device_enable(VOID_T)
{
#ifdef TUYA_ZG_ROUTER
return TRUE;
#else
return FALSE;
#endif
}
Code: Select all
BOOL_T __tal_inner_local_auto_condition_device_enable(VOID_T)
{
#ifdef TUYA_ZG_ROUTER
return FALSE;
#else
return TRUE;
#endif
}
2.4 当调用 tal_zigbee_local_auto_func_enable 后相关cluster会自动注册,应用无需额外添加。
由于内置关联了属性注册 所以
Code: Select all
tal_zigbee_local_auto_func_enable
必须早于
Code: Select all
tal_zg_endpoint_register
调用
2.5 作为动作设备时设备会自动向网关获取时区属性用于执行日期定时和周期定时
作为条件设备时会自动向网关获取pub address属性用于标记自身地址。
当获取成功后将不再获取,伴随自恢复机制,只有在远程离网或配网到另一个网关后才会再次获取。
为了减少大规模网络下由于上述无线包发送而导致的无线碰撞,我们加入了随机延时。
用户可以重新定义以下函数进行修改上电第一次的发送时间和在网持续获 取的延时时间。
Code: Select all
TIME_MS __tal_inner_first_query_pubaddress_time_get(VOID_T)
{
#ifdef TUYA_ZG_ROUTER
return 10000+tal_system_get_random(20000);
#else
return 10000+tal_system_get_random(20000);
#endif
}
Code: Select all
TIME_MS __tal_inner_usually_query_pubaddress_time_get(VOID_T)
{
#ifdef TUYA_ZG_ROUTER
return 10000+tal_system_get_random(20000);
#else
return (5*60*1000);
#endif
}
Code: Select all
TIME_MS __tal_inner_first_query_timezone_time_get(VOID_T)
{
#ifdef TUYA_ZG_ROUTER
return 10000+tal_system_get_random(20000);
#else
return 10000+tal_system_get_random(20000);
#endif
}
Code: Select all
TIME_MS __tal_inner_usually_query_timezone_time_get(VOID_T)
{
#ifdef TUYA_ZG_ROUTER
return 10000+tal_system_get_random(20000);
#else
return (5*60*1000);
#endif
}
2.6 作为动作设备时 当有动作需要执行时会调用下列函数
Code: Select all
VOID_T tal_local_auto_action_callback(UINT16_T autoid, UINT8_T dpid, UINT8_T dpkind, UINT8_T op ,UINT8_T *datas, UINT8_T datas_len)
其中autoid是本次触发的联动规则id,一般不需要用到
dpid是本次需要动作的dp值,应用需要进行dpid与zigbee中cluster下attribute和command的转换处理
dpkind是下表中的dp类型
op为下表中的动作运算符
*datas和datas_len组合表示了下表中的参数
下面为一个处理的demo:
Code: Select all
VOID_T tal_local_auto_action_callback(UINT16_T autoid, UINT8_T dpid, UINT8_T dpkind, UINT8_T op ,UINT8_T *datas, UINT8_T datas_len)
{
TAL_PR_DEBUG("tal_local_auto_action_callback \r\n");
TAL_PR_DEBUG("autoid :%x, dpid :%x, dpkind :%x, op :%x \r\n",autoid, dpid, dpkind, op);
TAL_PR_HEXDUMP_DEBUG("tal_local_auto_action_callback ",datas, datas_len);
switch(dpid){
case 1://开关 bool类型
if(1==datas_len && 1==op){//赋值操作
if(1==datas[0]){//on
//app_onoff_cluster_handler(CMD_ON_COMMAND_ID, datas, datas_len, ZIGBEE_CMD_GROUP, TRUE);
//需要注意的是分布式联动触发方式都是广播,建议无线数据回复加上一定的随机延时,避免大规模网络下的数据碰撞导致面板同步失败
}
else if(0==datas[0]){//off
/* code */
}
}
else if(0==datas_len && 0==op){//取反操作
/* code */
}
break;
case 2://模式 enum类型
if(1==datas_len && 1==op){//赋值操作
/* code */
}
break;
case 3://白光亮度 value类型
if((0 == dpkind) && (2==datas_len)){//类型判断
switch (op)
{
case 1://赋值操作
/* code */
break;
case 2://累加操作
/* code */
break;
case 3://累减操作
/* code */
break;
default:
break;
}
}
break;
case 4:
break;
default:
break;
}
}
2.7 作为条件设备时 当子设备的dp发生变化,需要通知给别的设备时需要调用:
Code: Select all
OPERATE_RET tal_broadcast_local_dp_value_func(UINT8_T num,UINT8_T *datas,UINT8_T datas_len,BOOL_T loopback,UINT16_T delay_time,UINT16_T random_time);
其中num表示本地执行了多少个动作,也就是具体有多少个dp变化了
datas是从下列数据结构的DPID开始,比如{0x01,0x11,0x00} 表示dp1,bool类型赋值为0
loopback是处理设备本身没有无线包回环功能设计的,TRUE时是发送广播包并回环传给自己一份,用以本身即是条件设备又是动作设备时,自己触发自己
delay_time+random_time是固定延时+随机延时,单位是ms
实际的报文格式如下所示:
其中条件类型固定为DP类型,发布地址sdk会自动补充
下面为一个处理的demo:
Code: Select all
TAL_WRITE_RET_E tal_zg_post_write_attribute_callback(UINT8_T ep_id, UINT16_T cluster_id, TAL_ATTR_REC_T *attr_rec)
{
TAL_PR_DEBUG("tal_zg_post_write_attribute_callback ep_id:%x,cluster_id:%x\r\n",ep_id,cluster_id);
TAL_PR_DEBUG("attr_id:%x,data_type:%x\r\n",attr_rec->attr_id,attr_rec->data_type);
TAL_PR_HEXDUMP_DEBUG("params: \r\n",attr_rec->attr_data,attr_rec->data_len);
if((1==ep_id) && (CLUSTER_ON_OFF_CLUSTER_ID == cluster_id) && (ATTR_ON_OFF_ATTRIBUTE_ID == attr_rec->attr_id)){
TAL_PR_DEBUG("tal_zg_post_write_attribute_callback ep_id:%x,cluster_id:%x\r\n",ep_id,cluster_id);
TAL_PR_DEBUG("attr_id:%x,data_type:%x\r\n",attr_rec->attr_id,attr_rec->data_type);
TAL_PR_HEXDUMP_DEBUG("params: \r\n",attr_rec->attr_data,attr_rec->data_len);
if((1==ep_id) && (CLUSTER_ON_OFF_CLUSTER_ID == cluster_id) && (ATTR_ON_OFF_ATTRIBUTE_ID == attr_rec->attr_id)){
if(1 == attr_rec->data_len){
UINT8_T test_buf[10] = {0x01,0x11,0x00};//dp1,bool类型赋值为0,并触发回环
test_buf[2] = attr_rec->attr_data[0];
tal_broadcast_local_dp_value_func(1,test_buf,3,TRUE,500,500);
}
}
else if ((1==ep_id) && (CLUSTER_COLOR_CONTROL_CLUSTER_ID == cluster_id) && (TY_ATTR_LIGHT_MODE_ATTRIBUTE_ID == attr_rec->attr_id)){
if(1 == attr_rec->data_len){
UINT8_T test_buf[10] = {0x02,0x21,0x00};//dp2,enum类型赋值为0,并触发回环
test_buf[2] = attr_rec->attr_data[0];
tal_broadcast_local_dp_value_func(1,test_buf,3,TRUE,500,500);
}
}
else if ((1==ep_id) && (CLUSTER_LEVEL_CONTROL_CLUSTER_ID == cluster_id) && (TY_ATTR_CURRENT_BRIGHT_ATTR_ID == attr_rec->attr_id)){
if(2 == attr_rec->data_len){
UINT8_T test_buf[10] = {0x03,0x01,0x00};//dp3,value类型赋值为0,并触发回环
test_buf[2] = attr_rec->attr_data[1];
test_buf[3] = attr_rec->attr_data[0];
tal_broadcast_local_dp_value_func(1,test_buf,4,TRUE,500,500);
}
}
return WRITE_RET_SUCCESS;
}
}
需要注意的是,上述之所以在tal_zg_post_write_attribute_callback中处理dp值变化,是为了统一收口,只在一处进行函数处理方便程序设计;
在收到命令后进行write attribute时,需要注意tal_zg_write_attribute函数不会触发 tal_zg_pre_write_attribute_callback和tal_zg_post_write_attribute_callback回调。
需要调用下列函数
Code: Select all
/**
* @brief write zigbee attribute
* NOTE: only for server clusters attributes;
* Note that this function triggers callbacks for tal_zg_post_write_attribute_callback and tal_zg_pre_write_attribute_callback
*
* @param[in] endpoint: endpoint id
* @param[in] cluster: cluster id
* @param[in] attr_id: attribute id
* @param[in] data: point to attribute data to be write
* @param[in] type: type of attribute
* @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
*/
OPERATE_RET tal_zg_write_attribute_with_callback(UINT8_T endpoint,
UINT16_T cluster,
UINT16_T attr_id,
VOID_T* data,
ZG_ATTR_TYPE_E type);
上述仅为处理demo,具体实现和接口处理按照实际进行设计。
2.8 支持设备作为触发开关,直接进行联动id的操作
下面是操作联动规则时需要调用的函数:
Code: Select all
OPERATE_RET tal_local_auto_control_with_broadcast(UINT8_T action,UINT16_T auto_id,BOOL_T loopback,UINT16_T delay_time,UINT16_T random_time)
其中 action:0x00 禁用
0x01 启用
0x02 执行
auto_id是需要通过app和网关下发下来的,类似与场景开关的绑定功能,回调函数如下:
Code: Select all
BOOL_T tal_local_auto_bind_callback(UINT8_T endpoint,UINT16_T auto_id, UINT8_T auto_action)
{
return TRUE;
}
auto_action:0x00 绑定
0x01 解绑
比如6路绑定开关,配置1路开关绑定的联动id时,下发的endpoint为1,以此类推
loopback 与发送自身dp时类似,也是为回环作用,为TRUE时通知对自身的联动规则进行同步操作
delay_time+random_time是固定延时+随机延时,单位是ms