Arda Xi

Zigbee Binding, or when 6 > 10

· Arda Xi

For a while I’ve been looking into making my lighting at home slightly smarter. Really, I just wanted to have white-spectrum lights in the living room, and to be able to move an inconveniently placed light switch without pulling wires. One hard requirement is that I really want everything to keep working even if the controller goes down. That’s how I ended up with Zigbee, specifically IKEA’s TRADFRI offering. Zigbee lets you bind devices, meaning they will work as long as the switch and the light are both working, even if the controller is missing. Setting this up in practice was surprisingly difficult however.

Zigbee Protocol

To understand what’s going on it helps to know a little bit about how Zigbee actually works. This is going to be a gross oversimplification, but it should be enough for our purposes. Zigbee is a wireless mesh protocol that operates in the 2.4GHz band. A network consists of one coordinator, routers and end devices. Generally speaking, any device with a mains connection like a light or a relay will act as a router. Any battery-powered devices like most switches will be end devices. A router can pass messages between devices, an end device can’t.

A coordinator is in charge of adding devices to the network, making sure they’re provisioned with the network key. It’s also what you use to issue or receive commands from outside of the network. This is what lets you schedule timers, or control lights from your phone. Many people will be using a hub of some kind, but you can also buy USB adapters that can turn any computer into a coordinator.

Functionally, a device (router or end device) is divided up into one or more endpoints, and each endpoint has one or more clusters. Endpoints logically divide a single device. A smart power strip may have an endpoint per socket, for example, so they can be addressed individually. Most devices have only one (useful) endpoint.


Clusters are where things get interesting. A cluster is a collection of attributes and commands. A light, for example, will have at least an On/Off cluster. This cluster has attributes like OnOff that tell you whether the light is currently on or off, and commands like Off, On and Toggle.

What’s interesting is that a light switch will also have the same clusters. For the light, this would be an input cluster (it can receive commands) but the light switch will have On/Off as an output cluster. When the on button is pressed, the switch will generate an On command from the On/Off cluster.

This can be used to bind devices together. If you bind the On/Off cluster of the switch to a light, then the switch will remember the light’s address, and send On/Off commands to the light when a button on the switch is pressed. This happens without any involvement of the coordinator. Naturally, there’s a limit to how many devices you can link to a given device. We’ll get to that later.

Attempt 0 - IKEA

This part is not especially enlightening, but I want to include it for completion’s sake. When I first got these lights I wasn’t really looking forward to figuring everything out, so I figured I’d just get IKEA’s DIRIGERA hub to start with. I could always replace it later. Unfortunately I could not actually get the thing to work. I had it connected properly, the app found it, but it would not update its firmware or move beyond that point. According to customer service, this is a common issue.

Fortunately the lights can work without any hub at all. You just have to get the remote really close to the light while holding the pair button and it’ll connect directly without a mesh network. Not ideal, but it would do for now. I connected the six spots in the living room to one remote and a couple of bulbs in the kitchen to another, and I’d at least fixed the primary issue.

Attempt 1 - ZHA

By now I’d acquired a Sonoff ZBDongle-E adapter. As I’d been running Home Assistant anyway, it seemed like a logical fit to use ZHA. This worked pretty well. It’s a matter of resetting the bulbs by turning them off and on 6 times until they start flashing, then telling the coordinator to permit joining. A short while later, the light shows up in HA. Same thing with the remote, by using the pairing button. ZHA also supports binding, although the option is hidden away slightly under Zigbee settings.

I bound the lights to my remote one by one, and it all worked fine, right up until the sixth (and last) one. No matter what I did, no matter what order, the sixth to be bound would always fail. It took me quite a while to figure out what was actually going on. Remember when I said there’s a limit to how many devices you can bind to a switch? Well, for this particular switch, it’s 10.

I figured 6 was less than 10, but as it turns out, that’s counting clusters, not devices. It was binding both the OnOff cluster and the Level Control cluster. By the fifth light, it had reached its limit of 10 clusters and refused any new binds.

I did manage to fix this. Using zha-toolkit it’s possible to send a manual bind command with only the OnOff cluster. It’s quite unwieldy to have to copy the address and find the cluster though. It also caused an additional issue where the state of the light wasn’t always reflected in HA, because the command had made it to the light but the updated state of the light didn’t get reported to the coordinator. I fixed this with an automation that polled the lights after receiving a button press on the switch, but it wasn’t pretty. You could also fix this by hand with zha-toolkit, but at this point I was kind of fed up with it. Especially since the binding requires pressing a button on the switch to wake it up each time.

Attempt 2 - Z2M

By now, I’d decided to start over with Zigbee2MQTT. It does require setting up an MQTT server and hooking it up to Home Assistant, but beyond that it’s just as easy to get going. Crucially however, Z2M lets you click each cluster you want to bind. So I could simply select just the OnOff cluster, and it just worked. This didn’t impact the ability to dim the lights by holding the button by the way, which you’d think is what Level Control would do.

Z2M also sets up reporting automatically when binding a cluster. This means it tells the light to send a message to the coordinator whenever its attributes change. That way, it would automatically update the view in HA without any polling needed. I also kind of like decoupling the Zigbee part from the HA part.

I have no idea if ZHA is going to implement these things and render this obsolete, but for now I’m just writing down what I wished I’d known about a month before I got all this set up.