How to set Multichannel Associations to endpoints of a device

Hi @Kjamsek, I’ve been working though the code for a couple of my device handlers that I’m cleaning up, and began looking at sending and receiving MultiChannelAssociation commands last night.

I haven’t used MultiChannelAssociation commands before, so I share your annoyance that the SmartThings zwave library documentation is appallingly scant. Any SmartThings Staff reading, please urgently provide usage examples for ALL Z-Wave command classes, as well as fully defining the attributes. I’m fed up with having to spend so much time reverse engineering things. :angry:

Meanwhile, I think I have made some headway with MultiChannelAssociation this morning…

If we compare the raw command string you posted above “8E0101000101” (which is six bytes) to the COMMAND_CLASS_MULTI_CHANNEL_ASSOCIATION definition in the Z-Wave Public Spec doc [SDS12657-12]

…we can determine the meaning of each byte:

  • 0x8E = COMMAND_CLASS_MULTI_CHANNEL_ASSOCIATION
  • 0x01 = MULTI_CHANNEL_ASSOCIATION_SET
  • 0x01 = Grouping Identifier for Assoc Group #1
    [there are no nodeIDs]
  • 0x00 = MULTI_CHANNEL_ASSOCIATION_SET_MARKER, this is confirmed in [SDS13740]
  • 0x01 = Node #1
  • 0x01 = BitAddress of 0 and EndPoint #1.

Now if we look at the raw output of a command built using multiChannelAssociationSet:

// Add nodes #3, #4, and #5 to assocation group #2:
zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 2, nodeId: [3,4,5]).format() // == "8E0102030405".

We can see that each node added to the nodeId value corresponds to another byte on the end of the raw command. So the solution is simple, the nodeId attribute needs to be list of nodeIds, followed by a zero (the marker), and then pairs of nodeIds and EndpointIds :joy: E.g.:

// Add node #3 and endpoints [node:4,endpoint5] and [node:6,endpoint7] to assocation group #2:
cmds << zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 2, nodeId: [3,0,4,5,6,7]).format() // == "8E0102030004050607".
cmds << zwave.multiChannelAssociationV2.multiChannelAssociationGet(groupingIdentifier: 2)
// Returns: MultiChannelAssociationReport(groupingIdentifier: 2, maxNodesSupported: 8, nodeId: [3, 0, 4, 5, 6, 7], reportsToFollow: 0)

To check it’s working, we can add some endpoints for the smartThings hub itself to an association group. E.g. assuming zwaveHubNodeId = “1”:

// Add node #1 and endpoints [node:1,endpoint3] and [node:1,endpoint5] to assocation group #2:
cmds << zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 2, nodeId: [1,0,1,3,1,5]).format() // == "8E0102010001030105".
cmds << zwave.multiChannelAssociationV2.multiChannelAssociationGet(groupingIdentifier: 2)
// Returns: MultiChannelAssociationReport(groupingIdentifier: 2, maxNodesSupported: 8, nodeId: [1, 0, 1, 3, 1, 5], reportsToFollow: 0)

Now when the association group is triggered, the device should send one instance of the relevant command(s) (e.g. a BASIC_SET) that is not encapsulated, plus another two instances of the command(s), each encapsulated within a MultiChannelCmdEncap() wrapper to the appropriate endpoint destination. All of these should be received by the device handler code running on the hub. Note, you wouldn’t want to do this in normal operation as you’ll flood your z-wave network with duplicate command frames!

I’ve also tested this by associating a double dimmer switch to a double relay and it works!

Some other points:

  • It’s important to note that the second byte of each ‘endpoint pair’ is a _1-bit BitAddress and a 7-bit EndpointId, which is defined elsewhere in the z-wave documentation. It’s my understanding that by setting the BitAddress to 1, you can do something like this:

    // Add node endpoints [node:3,endpoint1 thru endpoint7] to assocation group #2:
    zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 2, nodeId: [0,3,255]).format() // == “8E01020003FF”.

  • A normal associationGet command will only retreive the nodes in the association group and not any endpoints. E.g. : zwave.associationV2.associationGet(groupingIdentifier: 2)

  • However, a normal associationRemove command with empty nodeId will remove all nodes and all endpoints from the group. E.g. : zwave.associationV2.associationRemove(groupingIdentifier:2, nodeId: []) // completely empty association group 2 (nodes and endpoints).

  • Also, for completeness, the reason this is not working …

…is because zwaveHubNodeId is almost certainly “1” and it’s creating the string “8E010100101” which is corrupt as it’s 5 1/2 bytes! The solution is to format the zwaveHubNodeId as a hex byte. I.e. "8E010100" + String.format("%02X",zwaveHubNodeId) + "01", which would give “8E0101000101”.

However you shouldn’t need to use raw commands now, as hopefully I’ve shown how the zwave.multiChannelAssociationV2.multiChannelAssociationSet() does support setting associations for nodes and endpoints. :slight_smile:

Time for tea and biscuits…

HTH, Z.

1 Like