JN-SW-4170: How does direct Zigbee binding work?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

JN-SW-4170: How does direct Zigbee binding work?

2,410 Views
grafalex
Contributor II

I created a simple light switch device that is supposed to work with zigbee2mqtt server as a coordinator. So far my device can join the network, and report on/off attribute change. Everything looks clear so far.

Currently I am trying to understand how binding works, and have a lot of questions. My use case is pretty straightforward: I want my device (which is basically a switch) to send On/Off commands to a bound device (another switch).

First off, I am not using BDB Find and Bind procedures. The coordinator (zigbee2mqtt) sends my device a very specific ZPS_EVENT_ZDO_BIND message, that explicitly requests 'please bind device endpoint #1 OnOff cluster to the other device 0x0123456789ABCDEF endpoint #2'. From what I see in BDB API there is no such API to bind 2 specific devices - instead it runs find and bind procedures on initiator and some target, without providing a possibility to specify which target and which cluster I would like to bind.

I tried to play with binding functions provided by a low level zigbee stack, such as using ZPS_eAplZdoBind(). My first confusion is that ZPS_EVENT_ZDO_BIND message does not deliver ClusterID to my code, while I clearly see clusterID in the Bind Request I am seeing in the sniffer.

Anyhow, My code currently looks like this (I hardcoded the cluster ID):

void handleZdoBindEvent(ZPS_tsAfZdoBindEvent * pEvent)
{
uint16 shortAddr = pEvent->u8DstAddrMode == ZPS_E_ADDR_MODE_IEEE ?
ZPS_u16AplZdoLookupAddr(pEvent->uDstAddr.u64Addr) :
pEvent->uDstAddr.u16Addr;
uint64 ieeeAddr = pEvent->u8DstAddrMode == ZPS_E_ADDR_MODE_IEEE ?
pEvent->uDstAddr.u64Addr :
ZPS_u64AplZdoLookupIeeeAddr(pEvent->uDstAddr.u16Addr);

ZPS_teStatus status = ZPS_eAplZdoBind(GENERAL_CLUSTER_ID_ONOFF,
pEvent->u8SrcEp,
shortAddr,
ieeeAddr,
pEvent->u8DstEp);
DBG_vPrintf(TRUE, "Binding SrcEP=%d to DstEP=%d Status=%d\n", pEvent->u8SrcEp, pEvent->u8DstEp, status);
}

void handleZdoEvents(ZPS_tsAfEvent* psStackEvent)
{
...
switch(psStackEvent->eType)
...
case ZPS_EVENT_ZDO_BIND:
handleZdoBindEvent(&psStackEvent->uEvent.sZdoBindEvent);
break;

The ZPS_eAplZdoBind() function returns success code. I see a record in binding table

Binding table (size=16)
AddrOrLkUp=0001 ClusterID=0006 addrMode=3 SrcEP=2 DstEP=1

Unfortunately, despite binding was ok, my device does not trigger any target device actions. Moreover the only thing I see in the sniffer is that device just reports its status change to the coordinator, but no other messages to any other devices

Just to be clear, my device reports switch state change as follows:

void reportStateChange()
{
// Destination address - 0x0000 (coordinator)
tsZCL_Address addr;
addr.uAddress.u16DestinationAddress = 0x0000;
addr.eAddressMode = E_ZCL_AM_SHORT;

DBG_vPrintf(TRUE, "Reporting attribute EP=%d value=%d... ", getEndpointId(), sSwitch.sOnOffServerCluster.bOnOff);
PDUM_thAPduInstance myPDUM_thAPduInstance = hZCL_AllocateAPduInstance();
teZCL_Status status = eZCL_ReportAttribute(&addr,
GENERAL_CLUSTER_ID_ONOFF,
E_CLD_ONOFF_ATTR_ID_ONOFF,
getEndpointId(),
1, myPDUM_thAPduInstance);
PDUM_eAPduFreeAPduInstance(myPDUM_thAPduInstance);
DBG_vPrintf(TRUE, "status: %02x\n", status);
}

What am I doing wrong here? Maybe I should explicitly report state change to all bound devices somehow? From what I see eZCL_ReportAttribute() just packs the report to a PDU instance and send to the coordinator - there is no code that is processing binding table and sending bound devices any other reports.

Any other recommendations?

My code is here, if this helps

Labels (1)
0 Kudos
5 Replies

2,360 Views
mario_castaneda
NXP TechSupport
NXP TechSupport

Hi @grafalex,

I hope you are doing great.

I have been reading about the issue that you are facing. 

Could you please provide the sniffer log that you have about this behavior?

What is the AN that you are working on?

Regards,

Mario

0 Kudos

2,324 Views
grafalex
Contributor II

Hello, @mario_castaneda,

Thank you for your reply. I have some progress on this, and already solved a few issues in this code over the last couple weeks:

- My switch should send OnOff commands to control other devices, not reports. This is vaguely mentioned in the documentation, but without an accent. 

- The switch should have a client OnOff cluster to be able to send commands to other devices

- Commands should be sent with E_ZCL_AM_BOUND addressing mode, and not E_ZCL_AM_SHORT

After these changes my device is now able to control other OnOff device on the network (smart switch, relay, or light).

 

I am using JN-UG-3113, JN-UG-3114, and JN-UG-3115 as a source of information, as well as Zigbee Specifications. Perhaps this is described in some AN document - I'll appreciate if you could point me to the one.

 

 

At the same time I am still confused with NXP Zigbee API. Here is a dump of Bind Request the coordinator is sending to my device

grafalex_0-1625127300426.png

 

In this request you can clearly see Cluster ID field. And this ID should be eventually passed to ZPS_eAplZdoBind(). Unfortunately Zigbee Stack does not deliver this cluster ID to the ZDO handler. There is simply no such a field in ZPS_tsAfZdoBindEvent structure

typedef struct {
ZPS_tuAddress uDstAddr;
uint8 u8DstAddrMode;
uint8 u8SrcEp;
uint8 u8DstEp;
} ZPS_tsAfZdoBindEvent;

Is there a way to obtain ClusterID value included in the Bind Request message?

0 Kudos

2,259 Views
mario_castaneda
NXP TechSupport
NXP TechSupport

Hi @grafalex,

I am not sure if I am following your request.

You are looking for the Bind Request Cluster ID? Am I right? This will be 0x0021 by the spec.

Regards,

Mario

0 Kudos

2,235 Views
grafalex
Contributor II

Hi @mario_castaneda !

Let me rephrase. I am talking about ID of the cluster to bind. E.g. My device may implement various clusters - On/Off, thermometer, OTA, but I would like to bind specifically On/Off one.

As per Zigbee specification Bind request message looks like this

grafalex_0-1626514258388.png

 

As you clearly see, there is ClusterID field. In the sniffer screenshot you can see this field as well (set to 0x0006 On/Off). From what I see this low level zigbee message is converted to ZPS_tsAfZdoBindEvent structure, that has everything, except for Cluster ID.

I even disassembled the stack code, and looks like parsing low level Bind request message and converting it to ZPS_tsAfZdoBindEvent happens in bAplZdoBindUnbindServerProcessApdu(). Unfortunately this function comes without sources, so I cannot fix it myself.

 

So the question is: would it be possible to add ClusterID field to ZPS_tsAfZdoBindEvent? You have all needed information for this already.

 

0 Kudos

2,211 Views
mario_castaneda
NXP TechSupport
NXP TechSupport

Hi @grafalex,

Please look at the next event you could get the Cluster Id that you are looking for.

        case BDB_EVENT_FB_CHECK_BEFORE_BINDING_CLUSTER_FOR_TARGET:
            DBG_vPrintf(TRACE_APP_BDB,"APP-BDB: Check For Binding Cluster %04x\n",
                        psBdbEvent->uEventData.psFindAndBindEvent->uEvent.u16ClusterId);
            break;

Regards,

Mario

0 Kudos