Zigbee - Full format for sending Commands Using "he raw"

I need to use some "he raw" commands and plan to create a library file / library functions that I'll post to the community for handling.

The "he raw" command isn't well documented, so I've been looking through code to figure out the full set of fields.

Here's a request to anybody else with some knowledge in this area - can anybody confirm that this is the "full" correct format of the "he raw" commands (i.e., are any of the fields wrong, or are there other fields that might be included):

he raw $deviceNetworkId $sourceEndpointId $deviceEndpointId $clusterId { $frameControl $mfrCode $transactionSequenceNo $commandId 
 $commandPayload } { $profileId }

where:

deviceNetworkId is the destination address represented as a 4 octet string, not octet reversed, not preceded by 0x

sourceEndpointId is the source endpoint represented as an integer value (or hex using 0x prefix); not a two octet character. Usually 1 (This endpoint generally represents the hub; I have not seen another value used).

  • Thus, for example, if you want to send from endpoint 15, the field would get the value 15, not 0F. (confirm?)

deviceEndpointId is the destination endpoint represented as an integer value (or hex using 0x prefix); not a two octet character.

  • Thus, for example, if you want to send to endpoint 15, the field would get the value 15, not 0F. (confirm?)

Is the ordering of sourceEndpointId and deviceEndpointID correct? I would have thought that the destination EndpointId might directly follow the deviceNetworkID address? They are both usually 1, so it was a little hard for me to confirm correctness.

clusterId is the cluster of interest represented as an integer value (or hex using 0x prefix); not a four octet character string.

  • Thus, for example, if you wanted to send to cluster "ABCD" (hex), you could use the integer value 43981 or 0xABCD but not ABCD as a character string. (confirm?)

The following values and their settings are detailed in Zigbee Cluster Library Specification, Document 07-5123 Revision 8 ("ZCL")

frameControl is the frame control field from ZCL section 2.4.1.1 represented as a two octet character string

mfrCode is the manufacturer code represented as a 4 octet character string with octet pairs reversed. I.e., code 0x1234 is included as 3412. Field is optional depending on frameControl bit settings.

transactionSequenceNo is the sequence no. field from ZCL section 2.4.1.3 represented as a two octet character string. As a practical matter, I noticed that the responses from devices don't seem to expose the transaction sequence no., so the practical effect is it doesn't matter what this is set to (correct?).

  • If anybody knows of a way of getting the sequence No from a device's response, please clarify what that is (I actually had a use for it to correlate command responses with specific transmissions -- if I could get the info -- but took a different approach when I couldn't access it. Maybe it could be added to the parseDescriptionAsMap response? ).

commandId is the command represented as a two octet character string. Either a cluster global ("isClusterSpecific: false) or cluster-specific command ("isClusterspecific: true") , depending on a bit setting in the frameControl field.

commandPayload is the payload for the command, if any. Octets will need to be reversed on an element-by-element basis for payload elements that are greater than two octets. So, for example, if the command payload is the list of attributes 1234 ABCD, they would be put in the commandPayload section as 3412 CDAB.

profileId is the profile ID represented as an integer or hex value. Not an octet string / not octet reversed. So profileID 0101 could be 0x0104 or its Integer equivalent 260 (confirm?)

And spacing within the payload doesn't matter -- it all gets joined together. I.e., 00 12 3456 00 is the same as 0012345600

Thank you for your help.

2 Likes

Thank you for posting this. I've bookmarked it for future reference. I've always had challenges understanding the zigbee commands. I've got the zwave stuff down but don't have many zigbee devices anymore to play with.

1 Like

@gavincampbell @kkossev

Since you've both provided help on this and/or expressed some interest, you might find this next stage of what I'm doing interesting / helpful to you.

I'm working to solve this complex "raw" formatting problem by creating several library functions that will do all the formatting for you. My Zigbee repository on github (still very much a work-in-progress) is here:

You'll want to look at the library file: Hubitat-Zigbee/zigbeeTools.sendZigbeeAdvancedCommands.groovy at main · jvmahon/Hubitat-Zigbee · GitHub

There are 2 basic command in this library:

  1. sendZCLAdvanced. This is used to send Zigbee Cluster Library (profile 0x0104) commands.

  2. sendZDOAdvanced. This is used to send Zigbee Device Object (profile 0x0000) commands.

These are detailed below. The parameters are all "named" parameters and pretty carefully type checked using asserts. I only started coding this yesterday, so I'm guessing I have a week or two more of testing before its "done done."

If you're so inclined and want to give these functions a try, I would welcome further testing / checking and suggestions (post issues to github). Or wait a week or so until they are done (at which time, I'll give the library a 1.0.0 version number)

Note that you don't need to provide the sequenceNo for the sendZCLAdvanced command. If you don't provide it, its automatically generated by the getNextTransactionSequenceNo() function (which uses Java AtomicInteger function to ensure its concurrency safe if two events try to grab a sequence number at the same time).

void sendZCLAdvanced(Map inputs = [
			destinationNetworkId: null ,  // specified as a two-octet pair length 4 string.
			destinationEndpoint: null ,  // specified as an Integer. Unsure of order!
			sourceEndpoint: 1 ,         // specified as an Integer
			clusterId: null ,             // spedified as an Integer
			isClusterSpecific: false ,     // specified as a boolean. Determines whether ZCL header sets a global or local command.
			mfrCode: null ,             // specified as an Integer or Hex string (not octet reversed)
			direction: 0 ,                 // Integer. Rarely anything but 0
			disableDefaultResponse: false , 
			sequenceNo: null ,         // Sequence between 0 - 255. Should change for each transaction. Generate using getNextTransactionSequenceNo()
			commandId: null,             // The command ID as an integer
			commandPayload: null     // String representing the payload for the command ID. Can be trick to format! Watch out for octet reversing.
       ] ) {
void sendZDOAdvanced(Map inputs = [
			destinationNetworkId: null ,  // specified as a two-octet pair length 4 string.
			destinationEndpoint: null ,  // specified as an Integer. Unsure of order!
			sourceEndpoint: 1 ,         // specified as an Integer
			clusterId: null ,             // spedified as an Integer
			profileId: 0x0000 ,         // specified as an Integer. Only 0x0104 is supported
			commandId: null,             // The command ID as an integer
			commandPayload: null     // String representing the payload for the command ID. Can be trick to format! Watch out for octet reversing.
      ] ) {

And here's an example of using sendZDOAdvanced to get a simple descriptor payload:

String getSimpleDescriptorPayload = (zigbee.swapOctets(device.deviceNetworkId) + "01")
sendZDOAdvanced(
     destinationNetworkId: device.deviceNetworkId,
     destinationEndpoint: 0 , 
     sourceEndpoint: 1, 
     clusterId: 0x0004,
     profileId: 0x0000,
     commandId: 0x00,
     commandPayload: getSimpleDescriptorPayload
     )   
7 Likes

Thank you for OP and library from @jvm33.

How do you find the mfrCode for a device?

I use this :