"zha-toolkit" - a big set of Zigbee commands on top of ZHA/zigpy

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
data:
  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.

2 Likes

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

https://community.home-assistant.io/t/showing-basic-rssi-prometheus-exporter/390632

There is already a ZHA WS API interface ā€˜get_devicesā€™ used by zha-network-card.js like so:

    hass
      .callWS({
        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.

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

why?

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

Hi
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
logs:
  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
data:
  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.

Hi,
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": [
                            "0x30",
                            "enum8",
                            "Discrete"
                        ],
                        "access": "REPORT|WRITE|READ",
                        "access_acl": 7,
                        "attribute_value": 0

Next step Iā€™ll try to figure out how to set it ā€¦

Apparently this is an attribute handled by a quirk.

You can see some relevant code in zigpy/zha-device-handlers.

So you can see that you san set it to Off, On or Laststate after power up, and from the excerpt of the scan_device that you shared you can see that it is set to 0 (Off).

Now you just need to do a zha_toolkit.attr_write with the attr_val of 1 or 2 - you may need to set the manufacturer value (it either works with or without).

By default attr_write does a erad - write - read so that you can see the value before and after the write which is by default performed only when the value is not the one that will be written.

Again thx for the great support.
Just tried
service: zha_toolkit.attr_write
data:
ieee: 54:0f:57:ff:fe:7f:e9:29
cluster: 6
attribute: 8002
attr_type: 10
attr_val: ā€˜1ā€™
read_before_write: true
read_after_write: true
and got

2022-02-26 11:13:20 DEBUG (MainThread) [custom_components.zha_toolkit] running default command: <ServiceCall zha_toolkit.attr_write (c:dc07fdcbec4f8126b066203cc4d544b8): ieee=54:0f:57:ff:fe:7f:e9:29, cluster=6, attribute=8002, attr_type=10, attr_val=1, read_before_write=True, read_after_write=True>

2022-02-26 11:13:20 DEBUG (MainThread) [custom_components.zha_toolkit.default] Trying to import custom_components.zha_toolkit.zcl_attr to call attr_write

2022-02-26 11:13:20 DEBUG (MainThread) [custom_components.zha_toolkit.utils] Endpoint 1 found for cluster ā€˜6ā€™

2022-02-26 11:13:20 DEBUG (MainThread) [custom_components.zha_toolkit.zcl_attr] Request attr read [8002]

2022-02-26 11:13:20 DEBUG (MainThread) [custom_components.zha_toolkit.zcl_attr] Reading attr result (attrs, status): ({}, {8002: <Status.UNSUPPORTED_ATTRIBUTE: 134>})

2022-02-26 11:13:20 DEBUG (MainThread) [custom_components.zha_toolkit.zcl_attr] Request attr write [Attribute(attrid=8002, value=)]

2022-02-26 11:13:20 DEBUG (MainThread) [custom_components.zha_toolkit] event_data {ā€˜zha_toolkit_versionā€™: ā€˜v0.7.19ā€™, ā€˜zigpy_versionā€™: ā€˜0.43.0ā€™, ā€˜zigpy_rf_versionā€™: None, ā€˜ieee_orgā€™: 54:0f:57:ff:fe:7f:e9:29, ā€˜ieeeā€™: ā€˜54:0f:57:ff:fe:7f:e9:29ā€™, ā€˜commandā€™: None, ā€˜command_dataā€™: None, ā€˜start_timeā€™: ā€˜2022-02-26T10:13:20.718703+00:00ā€™, ā€˜errorsā€™: [ā€˜AttributeError("ā€˜NoneTypeā€™ object has no attribute ā€˜serializeā€™")ā€™], ā€˜paramsā€™: {ā€˜cluster_idā€™: 6, ā€˜attr_idā€™: 8002, ā€˜attr_typeā€™: 10, ā€˜attr_valā€™: 1, ā€˜dirā€™: 0, ā€˜manfā€™: bā€™ā€™, ā€˜triesā€™: 1, ā€˜expect_replyā€™: True, ā€˜argsā€™: [], ā€˜read_before_writeā€™: True, ā€˜read_after_writeā€™: True}, ā€˜compare_valā€™: 1, ā€˜write_is_equalā€™: False, ā€˜read_beforeā€™: ({}, {8002: <Status.UNSUPPORTED_ATTRIBUTE: 134>}), ā€˜successā€™: False}

Youā€™ll need to set the manufacturer value (manf: )

Also, the value type is incorrect - the can indicates 0x30 - you indicated 10 which is 0x0A so a 24bit, while 0x30 is the enumeration type.

Types have to match as well. When the attribute is defined in a quirk or the default definition, you should be able to omit the attr_type parameter.

Hi, you lost meā€¦
Iā€™m affraid I could not find the right values to put for manf or attr_type

service: zha_toolkit.attr_write
data:
ieee: 54:0f:57:ff:fe:7f:e9:29
cluster: 6
attr_val: ā€˜2ā€™
attribute: 8002
manf: 2
attr_type: 0x30 or 30
neither worksā€¦
Can I send you the complete scan?

You can, I suppose that you can attach it to your post.