I don’t know the routing details within the Thread mesh or once it’s on Ethernet. I’ve never dug into that layer.
Note that a device using bindings could as well subscribe to the bound / target device to receive changes so it actually depends on how the “from” device is implemented since it’s the one initiating the interaction.
Here are three examples of a motion sensor turning on a light.
-
With a hub automation, the hub subscribes for changes in the occupancy state so the motion sensor tells the hub there’s someone and the hub runs its automation and sends the “switch on” command to the light.
-
With a binding from the sensor to the light, the motion sensor will send a “switch on” command to the light when it detects someone. Note that the light doesn’t even know it’s a motion sensor and the motion sensor doesn’t care at all if the light was on or off.
-
With a binding from the light to the motion sensor. The light subscribes to the occupancy state in the motion sensor, the motion sensor will tell the light that there’s someone and the light will say “oh, there’s someone, I’ll switch on”. Note the sensor doesn’t even know it’s a light, it just reports its occupancy state instead of controlling the light.
Case 2 depends on the motion sensor supporting bindings to the OnOff cluster (I believe Eve supports it) and case 3 depends on the light supporting bindings to the Occupancy Sensing cluster (I believe there’s none in the market).
Hello once again,
to make sure, to have a fresh start I reset the devices and brought them back to home assistant. They received new node IDs (bulb 37, switch 38).
I also have to mention, that after a restart of my Mac I had to rerun all 3 lines you provided:
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install websocket-client
After verifying, that I could switch the light on/off through Home Assistant I tried to do the binding:
That is what I typed / received:
(.venv) markus@MacBook-Pro-Markus PythonScript % python3 matter-binding.py --from 38 --to 37
Connection successful to ws://homeassistant.local:5580/ws
Fabric ID: 2
Updating ACL…
ACL updated
Creating binding…
An error occurred: ‘str’ object has no attribute ‘items’
Tried suggested :1 subset of switch, but it seems this did not cause the error to come up:
(.venv) markus@MacBook-Pro-Markus PythonScript % python3 matter-binding.py --from 38:1 --to 37
Connection successful to ws://homeassistant.local:5580/ws
Fabric ID: 2
Updating ACL…
ACL updated
Creating binding…
An error occurred: ‘str’ object has no attribute ‘items’
So I am some steps further but have not managed a binding yet.
Cheers,
Session
Evidently my script falls on its face for your device. DM sent so we can debug it.
script seems to be running but getting error below. Does this mean it can’t find a match? the devices are a nanoleaf bulb and a arre button. They both only have endpoints 0,1. I tried with and without specifying endpoint.
python3 matter-binding.py --from 167 --to 166
File “/home/bigdvette/matter-binding.py”, line 124
“attribute_path”: f"{sender[“endpoint”]}/30/0"
^^^^^^^^
SyntaxError: f-string: unmatched ‘[’
Indeed, you can’t bind those. Arre button -just like most buttons- does not implement the On/Off cluster so it doesn’t know how to send on/off commands to the light.
Most buttons will just report their state like pressed, held, etc. so you need an automation to actually perform an action.
Well, I unwrapped an inovelli dimmer and tried to bind and get teh same error. Any ideas? I used the :2 endpoint for the dimmer.
Was getting the same error. The error was double quotes inside of double quotes. I changed the code to use single quotes around endpoint and it worked. Has no-one else had this problem?
Good question. Not sure why that wasn’t blowing up more.
Anyway, fixed (was it just the single line 124 that you bumped into?)
Yes that was only syntax error message.
Is it possible to use this to bind 2 inovelli white dimmers together as a 3way setup?
@Mactalla, thanks a lot for starting this! A few questions.
- Is it possible to configure 3 or 4-way binding so that two or three switches control a single load? What will happen if I configure the tool like this?
python3 matter-binding.py --from 10 --to 20
python3 matter-binding.py --from 20 --to 10
Will it cause infinite loop?
-
If the answer is yes for above, will this work for dimmers? Is there a mechanism that would prevent the relayed messages from overwriting the more up-to-date dimmer values?
-
You mentioned that the un-binding is not supported. Is it just a limitation of the switch, or the problem is more fundamental? Will the binding be removed if the newly created entry is removed from the
binding_entries
array and the messages is pushed to the web socket service?
@Mactalla, I played around with the code. Trying to make baby steps. Managed to read the ACL data, but I’m getting errors when trying to read bindings. The error is:
{'message_id': '2', 'result': {'1/30/0': {'TLVValue': None, 'Reason': 'InteractionModelError: UnsupportedCluster (0xc3)'}}}
Honestly: no idea. But there’s one way to find out! Try it out on something that you’re okay factory resetting, just in case.
My limited understanding of Matter Binding is that it’s simply a publish mechanism. I have not stumbled on anything that layers logic on top like “only update if…”
I just mean the script only ADDs a new binding. It doesn’t do anything to REMOVE a binding. Nothing would prevent doing so, only time/effort/need.
Yes. But for a full ‘cleanup’ you would also want to remove the ACL entry from the receiver. That’s more of a security best practice rather than any change in behaviour for the day-to-day.
Huh. Someone else was also seeing an error like this. What device is giving that error? AFAICT 0xc3 is the Commissioning cluster. If true, then I would think all devices would need to support that. At the same time I don’t know how that’s getting involved when reading the binding table.
Is this error coming from device or HA?
I’m using Inovelli White Smart Dimmers. I could query ACLs, but not bindings.
Where did you get documentation for the websocket protocol? How did you know what the “magic” values should be to query and update the bindings?
I assume the device. We’re asking the Matter server to send a message to the device and get the reply back. I don’t know how/why HA would interject in that. Of course I could be wrong.
Then we have a bigger mystery. That’s exactly what I use. I only have two and they’re both in use, so I’m not really inclined to go mucking with them especially if I won’t be able to re-bind them if that error is coming from a newer version of HA or HA’s Matter server. I can say that Inovelli Whites worked fine with the script using HA that was current at the time that I published that script.
This thread is where I was hacking my way through binding in general. That was using chip-tool which wraps the raw commands for easier use. That let me know roughly the steps required. Later I found this information which let me tickle the websocket in just the right way. But I don’t know where @lboue figured out those details.
@Mactalla, I ran a program to extract all attributes and here are the results. My fabricID is ‘2’. Do you see any valuable information there below? Any chance the 2/30/0 is the correct attribute for bindings?
Attribute [1/3/0] = 0
Attribute [2/3/0] = 0
Attribute [3/3/0] = 0
Attribute [4/3/0] = 0
Attribute [5/3/0] = 0
Attribute [6/3/0] = 0
Attribute [1/4/0] = 128
Attribute [6/4/0] = 128
Attribute [1/6/0] = True
Attribute [6/6/0] = False
Attribute [1/8/0] = 254
Attribute [6/8/0] = 128
Attribute [0/29/0] = [{'0': 18, '1': 1}, {'0': 22, '1': 1}]
Attribute [1/29/0] = [{'0': 257, '1': 1}]
Attribute [2/29/0] = [{'0': 260, '1': 1}]
Attribute [3/29/0] = [{'0': 15, '1': 1}]
Attribute [4/29/0] = [{'0': 15, '1': 1}]
Attribute [5/29/0] = [{'0': 15, '1': 1}]
Attribute [6/29/0] = [{'0': 269, '1': 1}]
Attribute [2/30/0] = []
Attribute [0/31/0] = [{'254': 1}, {'1': 5, '2': 2, '3': [112233], '4': None, '254': 2}]
Attribute [0/40/0] = 1
Attribute [0/42/0] = []
Attribute [0/48/0] = 0
Attribute [0/49/0] = 1
Attribute [0/51/0] = [{'0': 'ha-thread-0d17', '1': True, '2': None, '3': None, '4': 'FOkAIDFECBY=', '5': [], '6': [], '7': 4}]
Attribute [0/53/0] = 15
Attribute [3/59/0] = 2
Attribute [4/59/0] = 2
Attribute [5/59/0] = 2
Attribute [0/60/0] = 0
Attribute [0/62/0] = [{'254': 1}, {'1': 'xxxxx==', '2': 'xxxxx', '254': 2}]
Attribute [0/63/0] = []
Attribute [0/64/0] = [{'0': 'Vendor', '1': 'Inovelli'}, {'0': 'Product', '1': 'VTM31-SN'}]
Attribute [1/64/0] = [{'0': 'DeviceType', '1': 'DimmableLight'}]
Attribute [2/64/0] = [{'0': 'DeviceType', '1': 'DimmableSwitch'}]
Attribute [3/64/0] = [{'0': 'Button', '1': 'Up'}]
Attribute [4/64/0] = [{'0': 'Button', '1': 'Down'}]
Attribute [5/64/0] = [{'0': 'Button', '1': 'Config'}]
Attribute [6/64/0] = [{'0': 'DeviceType', '1': 'DimmableLight'}, {'0': 'Light', '1': 'LED Bar'}]
Attribute [1/80/0] = Switch Mode
Attribute [2/80/0] = Smart Bulb Mode
Attribute [3/80/0] = Dimming Edge
Attribute [4/80/0] = Dimming Speed
Attribute [5/80/0] = Relay
Attribute [6/80/0] = LED Color
Yes, the Binding Cluster is 0x001e (section 9.6.4 here: https://csa-iot.org/wp-content/uploads/2022/11/22-27349-001_Matter-1.0-Core-Specification.pdf ), which will be on endpoint 0. I think 2/30/0 would be fabric 2, cluster 30 (0x1e), on endpoint 0.
In that doc I just linked it says “The existence of the Binding
cluster on the client endpoint, allows the creation of one or more binding entries (bindings) in the Binding cluster.” which makes it sound like the existence can’t be assumed. Not sure where each cluster is listed as Mandatory or Optional, though.
In your code you had:
"attribute_path": f"{sender['endpoint']}/30/0"
looks like the first number was not the fabric but the endpoint.
I’m not much familiar with the terminology. What is the difference between cluster, fabric and endpoint? I guess the node just identifies the device.
wow, this spec is something…
Can you swap those and see what happens? It’s blind leading the blind here. I made lots of assumptions with magic numbers.
That said, I thought one couldn’t even access “other” fabrics. So why would we even need to specify the fabric when sending commands? But, hey, whatever works, right?
Ignore that and read lower down. A lightbulb lit up as I was replying.
A fabric is a network. Think of a VLAN or similar. It’s a neighbourhood that cannot see/interact with other neighbourhoods even though they share the same roads (Thread network).
An endpoint is a virtual ‘device’ on a piece of hardware. Endpoint 0 is dedicated to be the control endpoint – basic stuff like ‘who am I’ and access control and such. Most devices are simply “one” thing. In which case they have one other endpoint and that is the “thing” (maybe a button, maybe a light, maybe a thermostat). Some pieces of hardware are actually more than one things (maybe a set of 4 buttons, maybe a Dimmer Switch and also a dimmable light, which is what the Inovelli White is). In this case they’ll have an endpoint for each logical device.
Finally a cluster is a grouping of commands/attributes/stuff. There’s an On/Off cluster. A light and a switch and such will all implement this On/Off cluster which defines “turn on”, “turn off”, “am I on or off?”, etc. Then there’s a Level Cluster which has “raise the level” and such. A button will only implement the On/Off, but a Dimmer Switch will implement both On/Off and the Level.
And on that topic of Endpoints, it reminds me that the endpoint you want to bind on the Inovelli switch is actually EP2, not EP1. That would explain the 2/30/0. Are you telling the script to use endpoint 2? Quoting from OP:
- Run ./matter-binding.py --from (source node) --to (dest node)
- For endpoints other than 1, specify it with
:#
. eg: Inovelli switches have the Dimmer Switch that we can bind on Endpoint 2./matter-binding.py --from 17:2 --to 21