"zha-toolkit" - Toolkit providing low and high level Zigbee commands through ZHA/zigpy


The attr_write requires the attribute type (an unsigned 8 bit number).
In your case it an uint8 - which is cod 0x20 or 32 in decimal.

service: zha_toolkit.execute
  command: attr_write
  # You could replace this with the entity name if you like:
  ieee: cc:86:ec:ff:fe:d8:43:b6
  # Endpoint can be omitted if there is only 1 cluster of the given type on the device
  endpoint: 1
  # A bit suprised that cluster 0 is used for enabling/disabling a siren, but that's the doc.
  cluster: 0
  # Ok, you could also write this directly as 0x400a
  attribute: 16394
  # Ok, you cuould also omit the quotes
  attr_val: '1'
  # The type is required when writing
  attr_type: 0x20
  # The attribute is manufacturer specific - fill in th emanufacturer id.
  manf: 0x????
  # Optioinal, setting an event to get an idea of what happened from the UI.
  # You can "Listen" to the 'my_write_event' from Developer Tools > Events
  event_done: my_write_event

ZHA Toolkit sounds good, but may I suggest perhaps check what the ZHA and zigpy devs think about it:


Most other ZHA tools and libraries are hosted by the zigpy developers who work on some together:



Same devs sometimes also host new experimental tools/libraries under zha-ng (ZHA Next-Generation):



The only exceptions that I know about are, or rather, have been:






@hedda Thank you for the feedback.

I went forward with the setup of “zha-tookit” using the “zha_toolkit” domain.

I am updating the initial post.

1 Like

Hi guys, please bear with me as new to HA.

I did the install with HACS, and updated configuration.yaml. However when i run the backup command as in the documentation I get an error below

websocket_api script: Error executing script. Unexpected error for call_service at pos 1: znp_backup() got an unexpected keyword argument ‘params’

Any hints?

My fault: some function signatures did not get updated as they should for adding global options.

I updated the zha-toolkit code and published it.

1 Like

I tentatively added ezsp_backup - it’s untested.

service: zha_toolkit.execute
  command: ezsp_backup
  # Optional command_data, string added to the basename.
  # With this example the backup is written to `nwk_backup_20220105.json`
  command_data: _20220105

The core of the backup “wrapper” in the toolkit is in ezsp.py/function ezsp_backup . It may need adjustments.

1 Like

I am trying the same thing with the same device, but i keep getting this response

    "event_type": "my_write_event",
    "data": {
        "ieee_org": "cc:86:ec:ff:fe:d8:46:e1",
        "ieee": "cc:86:ec:ff:fe:d8:46:e1",
        "command": "attr_write",
        "start_time": "2022-01-24T23:19:58.433075+00:00",
        "errors": [
            "DeliveryError('[0xae9a:1:0x0000]: Message send failure')"
        "params": {
            "cmd_id": null,
            "endpoint_id": 1,
            "cluster_id": 0,
            "attr_id": 16394,
            "attr_type": 32,
            "attr_val": 1,
            "min_interval": null,
            "max_interval": null,
            "reportable_change": null,
            "dir": null,
            "manf": 4,
            "tries": 1,
            "expect_reply": true,
            "args": [],
            "state_id": null,
            "state_attr": null,
            "allow_create": false,
            "event_success": null,
            "event_fail": null,
            "event_done": "my_write_event",
            "read_before_write": true,
            "read_after_write": true,
            "write_if_equal": false
        "success": false
    "origin": "LOCAL",
    "time_fired": "2022-01-24T23:19:58.437786+00:00",
    "context": {
        "id": "ba82fcc4da5ff92a090d65aaa4200f2e",
        "parent_id": null,
        "user_id": null

here is my snippet

service: zha_toolkit.execute
  command: attr_write
  ieee: cc:86:ec:ff:fe:d8:46:e1
  endpoint: 1
  cluster: 0
  attribute: 16394
  attr_val: '1'
  attr_type: 32
  manf: 4
  event_done: write_leak_led

Any insight is appreciated

I think that the ‘manf’ value is incorrect. A manf of 4 would be Philips in a RF4CE context: wireshark/packet-zbee.h at 5f29a00814897a5552b4d7f46bf3419066ed2fbd · wireshark/wireshark · GitHub.

As you’re writing to a non standard attribute 0x400a in cluster 0x0000 you’ld in principle need a manufacturer code, but some manufacturers do not follow the rule.

The destination is invalid and the device should have replied with a standard error, but not all devices follow the specification.

So IMHO you need to set the correct manufacturer code - or not set the manufacturer code which will likely give the expected result.

You can also perform a ‘scan_device’ - you can just replace ‘attr_write’ with ‘scan_device’ and leave the other parameters in place - they are ignored, this allows you to come back to ‘attr_write’ more easily. The result of the scan gives the list of parameters and the current values.

I added some options to write zigbee attributes to whera CSV file - available with attr_read and attr_write (where an attribute is by default read before and after a write).

In my case this will be usefull in a script/automation where I want to evaluate the effect of a setpoint of an entity on measurements.

1 Like

zha-toolkit now has a service for each internal command. zha_toolkit.execute is still available - it’s handy if you want to keep most parameters while changing commands.
So now there is an individual service for zha_toolkit.attr_read, zha_toolkit.attr_write, zha_toolkit.backup and more.
The attr_read and attr_write have been fully specified in services.yaml - that way the UI proposes only the appropriate options for these commands and also which ones are required.

Further you can add your own commands in local/user.py . I guess that’s very much like pyscript, but you’ll get ieee address resolution for free (i.e. entity name to ieee address conversion), and more.
As local/user.py is reloaded on each call, you can easily adjust it until it works without having to restart HA.
:warning: If you add your user.py, not that thelocal directory is not under version control, so you might want to add one of your own for that subdirectory.

Behind the scenes new commands can be added without requiring new methods in __init__.py - module resolution and method resolution is done in a more dynamic way.


FYI, here is by the way example of someone exporting RSSI or LQI to Prometheus for troubleshooting:


There is already a ZHA WS API interface ‘get_devices’ used by zha-network-card.js like so:

        type: "zha/devices",

I added zha_devices to zha-toolkit to write to a CSV file using the method that is behind this API call.
See the documentation for that. There is more information in the event as some of the data correspond to tables.

I installed zha toolkit from Hacs, but then when I go to add in configuration.yaml the written
the configuration check goes into a loop,
but if I remove zha_toolkit: or I just comment it #, the check is positive.


I would like to backup my cc2530 usb to migrate to the new sonoff

Very strange, just restart my HAOS to check this and no issue.
What version are you using?

Can you enable debugging.
My logger.yaml:

default: warning
  custom_components.zha_toolkit : debug

Referenced in configuration.yaml:

logger: !include logger.yaml

You should see a line for each service added at startup :

2022-02-10 19:55:54 DEBUG (MainThread) [custom_components.zha_toolkit] Add service zha_toolkit.execute

i have Home Assistant OS 7.4 with supervisor-2022.01.1

@mighel I’ld need some more information, especially what we can see in the log.
Also, issues like that are more a topic for github issues. Usage recommendations and use cases are a good topic for this forum.
Also, I was referring to the zha_toolkit version (you can find in the manifest.json).

With regards to the export of Devices and their zigbee characteristics (RSSI. LQI, IEEE Address), …: sorting is now possible by using the csvlabel parameter of the service: zha_toolkit.zha_devices.

Most of the time an update of zha_toolkit does not require a restart, and that seems to be working well for the latest versions.

To ensure that you service definitions are up to date, call upon service: zha_toolkit.register_services. It reloads all service parameter configurations, and the services.yaml as well which is used to setup the UI parameters.

If you want to interrupt a script, an automation, … , the parameter ‘fail_exception’ allows you to have zha_toolkit raise an exception in cases where zha/zigpy do not raise one. For instance, the attr_write service by default reads back the value after writing it. Both operations could be a success for zigpy, but the toolkit will set ‘success: False’ when the read value is different from the written value.

Raising an exception stops a script/automation. So you can require a validated write (through the read back) before continuing.

1 Like

Hi, I wondered if this tool can be used for the following.
My Blitzzwolf power plugs stay ‘off’ after a power outage. Zigbee2MQTT has a toggle for them to change that state between on/off/current state.
ZHA doesn’t have this capability currently.
I guess I could ‘fire’ off such a command using this tool… but would need more pointers on where to look…

You can use a cluster command towards the power plug to control them.

ZHA natively has the service: zha.issue_zigbee_cluster_command .

zha-toolkit has zha_toolkit.zcl_cmd.
This offer the following possibilities over the standard implementation:

  • specify a number of tries,
  • provide the entity name rather than the IEEE address,
  • possiblity to omit the endpiont id (zha-toolkit will find it),
  • event generation, exception;
  • no need to specify the direction (autodetected).

You can see an example on switching a device on.
Currently there is an easier method to do it: zha_toolkit.zcl_cmd as a service which would be

service: zha_toolkit.zcl_cmd
  ieee: entity.actual_name
  cmd: 1
  cluster: 6

Sending command ‘1’ to cluster ‘6’ (of an endpoint) is sending an On command to the OnOff cluster of the endpoint, which sets the endpoint on.

Generally there is only one “OnOff” cluster in the device, so zha-toolkit can determine the endpoint without error by finding the endpoint that has cluster 6.

There are more commands in cluster 6. and you can see them here: https://github.com/zigpy/zigpy/blob/2f8f841a2444bac97e0aa38fa6c4859072096c44/zigpy/zcl/clusters/general.py#L634-L653 .

Your device may not support them all. The zha_toolkit.scan_device command may help you determine which ones are supported.

You could:

  • trigger on the powerup/start event,
  • get the expected state and use a template {{ … }} to set the command id (0 or 1);
  • Send he command to the cluster.

You can find an example here where values to the service call depend on templates.

Thx very much for the comprehensive answer!
A run from zha_toolkit.scan_device got me this.

                    "0x8002": {
                        "attribute_id": "0x8002",
                        "attribute_name": "power_on_state",
                        "value_type": [
                        "access": "REPORT|WRITE|READ",
                        "access_acl": 7,
                        "attribute_value": 0

Next step I’ll try to figure out how to set it …