How to set Multichannel Associations to endpoints of a device

i searched all that i could in the documentation but it looks as if SmartThings implemented only singlechannel associations in the class physicalgraph.zwave.commands.multichannelassociationv2.MultiChannelAssociationSet

According to the Z-Wave public specs A-M document that command class should have the option to be able to associate not only nodeId’s, but a combination of a multichannel nodeId and endpoint.

Did anyone have any luck setting multichannel associations on endpoints? I’d really love to avoid having to implement a polling mechanism since the devices i’m integrating fully support multichannel unsolicited reports.


Just wondering, how long do you guys have to wait for support answers to tickets in general?

Under 24 hours.

You seem to be right. Unfortunately all i got as an answer was a precompiled reposnse linking me to the developer documentation on github.

This is getting ridicolous to be honest. I try to set up Multichannel Lifeline associations to specifically avoid polling the device for data, since it reports in unsolicited reports if those associations are set (note that this is the ideal mechanism to ensure low network congestion since no polling is needed). Why even list as supported the Multichannel Association command class, that can do only what the plain Association command class can do.

Now i see there’s no way to set them up so i move on to a polling approach but find out that polling has been broken for 2 years now already.

As it looks now ST is the worst z-wave controller on the market.

1 Like

Hah! Looks like it can be hacked to work with unimplemented command classes also. For future reference, it is possible to set a Multichanel Association Lifeline association (with RAW Z-Wave bytes) on a device via it’s Device Handler if you use Configuration capability and make the configure method like this:

def configure() {
	def assocCmds = []
	assocCmds << zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId).format()
	assocCmds << new physicalgraph.device.HubAction("8E0101000101")
	return delayBetween(assocCmds, 1000)

In the string passed to HubAction “8E0101000101” you can modify the last two byte values in the string 8E0101000101 to fit your controller setup. My example is for Multichannel NodeId 1 with endpointId 1. For Multichannel NodeId 2 and endpointId 3 the string would look like “8E0101000203”.

Does anyone know how the zwaveHubNodeId could be concatenated into that string? I tried the generic “8E010100”+zwaveHubNodeId+“01” way but that caused the command not to be sent anymore.

Now just to test if it’s reliable for multiple inclusions and over a couple of days.

Much thanks to Arcaneshark’s post for the solution:


Using the multichannel app doesn’t work for you?

What multichannel app are you referring to?

If you’r thinking of the ZW Multichannel device handler then yes, it doesn’t work because ST doesn’t allow you to set any associations to endpoints due to it’s partial MultiChannel Association V2 implementation.

And since polling with z-wave commands didn’t work for me either setting a multi channel Lifeline association was the only way to get the reports from endpoints.

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:

  • 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…


1 Like

Just to follow-up on this, I’ve just released a device handler for the Fibaro Dimmer 2, which fully supports configuring Multi-channel Associations from the GUI, as well as a sync manager for ensuring the configuration is synced with the physical device.

Full info here: [RELEASE] Fibaro Dimmer 2 (FGD-212) - Advanced DTH (V2)


Further follow up. I’ve just released my Z-Wave Tweaker DTH which can be used to set Multi-channel Associations for any Z-Wave device.


@zcapr17 Thanks a million for this information. I was trying to stick the raw data into the payload variable of the constructor which didn’t really work, but it didn’t occur to me to use format() to reverse engineer how the raw commands get structured :relieved:

SmartThings staff, if you are reading this, just copy/paste David’s post into your documentation as it’s the most complete answer regarding this topic you’ll ever get!

If i ever run into you in the flesh David, tea and biscuits are on me!


I am attempting to get a Neo Coolcam switch to work and have come across the problem with the Z-Wave Device Multi Channel issue.

I have read through this read and other documentation, but unfortunately am not a developer and am still stuck. I have installed the Z-Wave Tweaker and run off the reports, but do not see how I can use it to set the Multi Channel associations.

Will setting the associations in Z-Wave Tweaker enable the standard device handler to work as it is meant to or do I need a re-written device handler?

Any pointers would be much appreciated.

Thank you

This is the snippet i used for setting a multichannel lifeline association from inside one of my handlers. This function executes every time the device is included. It removes the singlechannel lifeline association that is automatically set by ST upon inclusion and replaces it with a multichannel lifeline so each device’s endpoints are allowed to send data to ST.

If your handler supports the Configuration capability (you should see this line inside the tile definition brackets):

capability "Configuration" //Needed for configure() function to set MultiChannel Lifeline Association Set

Then you need to just copy/paste the following below to your handler (if the handler doesn’t support Configuration capability then just add the line inside the definition(…) function). A reinclusion of the device is necessary in this case:

 * Configuration capability command handler that executes after module inclusion to remove existing singlechannel association Lifeline and replace it
 * with a multichannel Lifeline association setting for node id 1 and endpoint 1, which enables modules to report multichannel encapsulated frames.
 * @param void
 * @return List of commands that will be executed in sequence with 500 ms delay inbetween.
def configure() {
	log.debug "Qubino Weatherstation: configure()"
	/** In this method we first clear the association group 1 that is set by SmartThings automatically.
	* Afterwards we set a MultiChannel LifelineAssociation, so the device can report it's data MC Encapsulated.
	def assocCmds = []
	assocCmds << zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId).format()
	assocCmds << zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 1, nodeId: [0,zwaveHubNodeId,1]).format()
	return delayBetween(assocCmds, 500)

NOTE: If your handler doesn’t expect multichannel encapsulated data it most likely won’t work, since it needs to de-encapsulate multichannel encapsulation frames to get the actual device data contained within.

1 Like

I’ll be playing with the tweaker next weekend. I have a lot of multichannel switches and dimmers all over my house…

One question - I’d like to be able to target specific endpoints with either (a) switches on the smartthings app; or (b) automated sequences - how can I do that?

Many thanks,

For this you can check my Qubino RGBW Dimmer handler available below for more in-depth end point handling. Here’s a small snippet that sends a Switch Multilevel Set command to various end points, queued inside the result object (you basically use the normal command, BUT need to encapsulate them inside Multichannel Cmd Encapsulation frames):

result << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: r)).format()
result << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: g)).format()
result << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:3).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: b)).format()
result << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:4).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: w)).format()

See here for the complete handler: