Display device bindings

So I’ve been playing with binding my Aqara multi-button remotes to light groups for quicker response and redundancy and all appears to be going smoothly… except… I can’t seem to find a place where I can display what I have previously bound (binded?).
Any ideas?

1 Like

I’m wondering this too. This is the only thing I miss from the deConz/phoscon installation I started with - phoscon has a really good UI for manipulating and displaying bindings. The ZHA UI is a horrible mess unfortunately.

Is everyone using automations for managing the connections between remotes and lights perhaps?

Unfortunately, I don’t know where you can see the binding either.

So I always use automations for this. I didn’t know that this would also work with binding. A question about this:
Would bound devices still work when HA is shut down?

Yes, and that is the main point of using bindings. Binding remotes directly to devices/groups work even without the Zigbee controller available. It’s the same thing that happens when you pair a remote directly to a bulb or other device.

I’d like to avoid the situation where I can’t turn off the kitchen lights because there was a bug in the latest Node-Red update, or because of a failure in the USB-C power adapter for the rPi4 where HA is running :slight_smile:

3 Likes

ZHA support for bind grouping of lights, switches, and fans (i.e. support for commanding device groups as entities). At least two entities must be added to a group before the group entity is created. As well as support for binding/unbinding (i.e. bind a remote to a lightbulb or group).

https://www.home-assistant.io/integrations/zha#binding-and-unbinding

Binding a remote directly to a bulb or group has the benefit of faster response time and smoother control. This greatly improves user feedback experience functions like dimming as the remote then directly dims the lightbulb and thus does not have to make the software roundtrip via the ZHA coordinator.

1 Like

Has anyone found a solution to this? I noticed that the ZHA UI for managing bindings has changed in the recent updates.

Just found same issue. Did anyone resolve this after?

I don’t think so, at least I never found a way to query the zigbee network for information on bindings.

Any news on this?

You can find out what a device is bound to using the ZHA Toolkit from HACS.

This gives you a suite of services which you can run from Developer Tools. Get Binding Table returns a report containing the IEEE addresses of the devices your switch is bound to (they’re right at the bottom - make sure you scroll all the way down).

  • src is the device you’re checking (probably a switch)

  • dst_ieee is the device it’s bound to (probably a lightbulb)

There are likely to be several clusters involved, so the information will be repeated several times with different cluster_ids.

The device you’re checking will probably be battery-powered, so make sure it’s awake before you run the service (press the button a few times if it’s a switch).

1 Like

Is there any better way to do this? It seems like such a straightforward thing to want to see what a device is bound to, but it’s fairly time consuming to do it manually by getting the binding table.

I got fed up with not having an easy way to view this and hacked together something useful to me that runs nightly or whenever I decide to invoke it manually. (This was helpful recently after a firmware update that required me to re-pair some devices).

In configuration.yaml:

shell_command:
  open_zha_bindings: ./zha-bindings-cmd.sh open
  write_zha_bindings: ./zha-bindings-cmd.sh write '{{ id }}' '{{ bindings }}'
  close_zha_bindings: ./zha-bindings-cmd.sh close
alias: Store ZHA Bindings
description: ""
trigger:
  - platform: time
    at: "00:00:00"
condition: []
action:
  - variables:
      ids: |
        {% set zha_entities = integration_entities('zha')|sort|list %}
        {% set ns = namespace(ids={}) %}
        {% for entity_id in zha_entities -%}
          {% set ieee = (device_attr(entity_id, 'identifiers')|list).0.1 -%}
          {% set id = device_attr(entity_id, 'name_by_user')
            |lower|regex_replace('[^a-z]', '_') -%}
          {% set ns.ids = dict(ns.ids, **{ ieee: id }) -%}
        {% endfor %}
        {{ ns.ids }}
  - alias: Open bindings file
    service: shell_command.open_zha_bindings
    data: {}
    response_variable: command_response
  - alias: Check open result was successful
    if:
      - condition: template
        value_template: "{{ command_response['returncode'] != 0 }}"
    then:
      - service: persistent_notification.create
        data:
          title: Failure to write ZHA bindings
          message: "{{ command_response['stderr'] }}"
  - repeat:
      for_each: "{{ ids.keys()|list }}"
      sequence:
        - alias: Define variables
          variables:
            ieee: "{{ repeat.item }}"
        - alias: Get binds
          service: zha_toolkit.binds_get
          data:
            ieee: "{{ ieee }}"
          response_variable: binds
        - alias: Write bindings file
          service: shell_command.write_zha_bindings
          data:
            id: "{{ ids[ieee] }}"
            bindings: |
              {% set ns = namespace(bindings=[]) %}
              {% if binds.result -%}
                {% for _, value in binds.result.items() -%}
                  {% if 'group' in value.dst -%}
                    {% set ns.bindings = ns.bindings + [{
                      ("group_" ~ value.dst.group): {
                        "cluster": value.cluster_id|default(none),
                        "src": value.src_ep|default(none),
                      }
                    }] %}
                  {% else -%}
                    {% set ns.bindings = ns.bindings + [{
                      ids[value.dst.dst_ieee]: {
                        "cluster": value.cluster_id|default(none),
                        "src": value.src_ep|default(none),
                        "dst": value.dst.dst_ep|default(none),
                      }
                    }] %}
                  {% endif -%}
                {% endfor %}
              {% else -%}
                {% set ns.bindings = "unavailable" %}
              {% endif -%}
              {{ ns.bindings|to_json(pretty_print=true) }}
          response_variable: command_response
        - alias: Check write result was successful
          if:
            - condition: template
              value_template: "{{ command_response['returncode'] != 0 }}"
          then:
            - service: persistent_notification.create
              data:
                title: Failure to write smart switch settings
                message: "{{ command_response['stderr'] }}"
  - alias: Close bindings file
    service: shell_command.close_zha_bindings
    data: {}
    response_variable: command_response
  - alias: Check close result was successful
    if:
      - condition: template
        value_template: "{{ command_response['returncode'] != 0 }}"
    then:
      - service: persistent_notification.create
        data:
          title: Failure to write ZHA bindings
          message: "{{ command_response['stderr'] }}"
mode: single

And a script file at /config/zha-bindings-cmd.sh:

#!/bin/bash

if [[ "$1" = "open" ]]; then

cat > ./zha-bindings.json <<EOF
# serialized zha bindings automatically written daily this file contains a
# header can be read, for instance with:
#
#     sed '/^#/d' zha-bindings.json | jq
#     sed '/^#/d' zha-bindings.json | jq -f zha-bindings-brief.jq
{
EOF

fi

if [[ "$1" = "write" ]]; then
cat >> ./zha-bindings.json <<EOF
"$2": $3,
EOF
fi

if [[ "$1" = "close" ]]; then
sed -i '$ s/,$//' ./zha-bindings.json
cat >> ./zha-bindings.json <<EOF
}
EOF
fi

Lastly for viewing with jq, a little helper file at /config/zha-bindings-brief.jq:

.
| to_entries 
| .[] 
| select(.value != "unavailable")
| {
    key: (.key),
    value: (.
        | .value 
        | map(to_entries
            | .[]
            | select(.key != "coordinator"))
            | map(
                (.key) + " " +
                (.value.cluster) + " (" + 
                (.value.src|tostring) + ":" + 
                (.value.dst|tostring) + ")"
            )
        )
    }
| select(.value | length > 0)
| { (.key): .value }

I wish there were something easier, and it seems like the ZHA integration has added some new UI recently to make some stuff easier to see, but this also allows me to see if I accidentally changed something because the file will change (and I version control my /config dir).