{"id":13585546,"url":"https://github.com/mdeweerd/zha-toolkit","last_synced_at":"2026-03-08T00:02:03.640Z","repository":{"id":38163724,"uuid":"448980525","full_name":"mdeweerd/zha-toolkit","owner":"mdeweerd","description":"🧰 Zigbee Home Assistant Toolkit - service for \"rare\" Zigbee operations using ZHA on Home Assistant","archived":false,"fork":false,"pushed_at":"2026-01-01T21:43:25.000Z","size":1718,"stargazers_count":273,"open_issues_count":19,"forks_count":38,"subscribers_count":8,"default_branch":"main","last_synced_at":"2026-01-07T07:49:32.689Z","etag":null,"topics":["home-assistant","home-assistant-component","home-assistant-hacs","zha","zigbee","zigpy"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mdeweerd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"Contributing.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-01-17T17:07:59.000Z","updated_at":"2026-01-05T21:40:30.000Z","dependencies_parsed_at":"2023-02-19T02:31:28.896Z","dependency_job_id":"bdf64262-479d-4ca0-859b-8884fb0fa48a","html_url":"https://github.com/mdeweerd/zha-toolkit","commit_stats":{"total_commits":802,"total_committers":22,"mean_commits":36.45454545454545,"dds":0.2194513715710723,"last_synced_commit":"458ba500fe52fe2f30f0e9933e665060b2f6c884"},"previous_names":[],"tags_count":125,"template":false,"template_full_name":null,"purl":"pkg:github/mdeweerd/zha-toolkit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdeweerd%2Fzha-toolkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdeweerd%2Fzha-toolkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdeweerd%2Fzha-toolkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdeweerd%2Fzha-toolkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mdeweerd","download_url":"https://codeload.github.com/mdeweerd/zha-toolkit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdeweerd%2Fzha-toolkit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30238087,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T23:52:25.683Z","status":"ssl_error","status_checked_at":"2026-03-07T23:52:25.373Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["home-assistant","home-assistant-component","home-assistant-hacs","zha","zigbee","zigpy"],"created_at":"2024-08-01T15:05:00.439Z","updated_at":"2026-03-08T00:02:03.629Z","avatar_url":"https://github.com/mdeweerd.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"[![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg)](https://github.com/hacs/integration)\n![hacs_installs](https://img.shields.io/badge/dynamic/json?label=Installs%28Reported%29\u0026query=%24.zha_toolkit.total\u0026url=https%3A%2F%2Fanalytics.home-assistant.io%2Fcustom_integrations.json)[![zha_installs](https://img.shields.io/badge/dynamic/json?label=vs.ZHA%20Installs\u0026query=%24.current.integrations.zha\u0026url=https%3A%2F%2Fanalytics.home-assistant.io%2Fdata.json)](https://analytics.home-assistant.io/integrations)\n[![Version](https://img.shields.io/github/v/release/mdeweerd/zha-toolkit)](https://github.com/mdeweerd/zha-toolkit/releases/latest)\n![Downloads latest](https://img.shields.io/github/downloads/mdeweerd/zha-toolkit/latest/total.svg)\n![Downloads](https://img.shields.io/github/downloads/mdeweerd/zha-toolkit/total)\n[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\u0026logoColor=white)](https://github.com/pre-commit/pre-commit)\n[![Open ZHA-Toolkit inside your Home Assistant Community Store (HACS).](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=mdeweerd\u0026repository=zha-toolkit\u0026category=integration)\n\n[ZHA Toolkit](https://github.com/mdeweerd/zha-toolkit) (Zigbee Home\nAssistant Toolkit) helps go beyond some limitations when using the\n[ZHA integration component](https://www.home-assistant.io/integrations/zha)\nin [Home Assistant](https://www.home-assistant.io/) (an open source home\nautomation software). It does so by providing extra methods to execute\nZigbee requests and helps bridge between ZHA functionality and Home\nAssistant.\n\nYou can\n[add ZHA Toolkit to Home Assistant](https://my.home-assistant.io/redirect/hacs_repository/?owner=mdeweerd\u0026repository=zha-toolkit\u0026category=integration)\nusing [HACS (Home Assistant Community Store)](https://hacs.xyz/). ZHA\nToolkit is available in HACS' default repository list.\n\n## Purpose\n\nThe purpose of ZHA Toolkit and its Home Assistant 'Services' feature, is to\nprovide direct control over low-level zigbee commands provided in ZHA or\nZigpy that are not otherwise available or too limited for some use cases.\n\nZHA Toolkit can also:\n\n- Serve as a framework to do local low-level coding. ZHA Toolkit applies\n  code changes immediately by reloading its python modules on each call,\n  including the user custom modules.\n\n- Provide access to some higher-level commands such as ZNP backup (and\n  restore).\n\n- Make it easier to perform one-time operations where (some) Zigbee\n  knowledge is sufficient and avoid the need to understand the inner\n  workings of ZHA or Zigpy (methods, quirks, etc).\n\n- Download Firmware referenced in\n  [Koenkk/zigbee-OTA](https://github.com/Koenkk/zigbee-OTA).\n\n### Highlights\n\n- Reads Zigbee attributes into Home Assistant states/attributes\n- Daily ZNP Coordinator backup (See blueprint)\n- Provides \"Low level\" access to most Zigbee commands\n  (read/write/(un)bind/report/cmd/discover)\n\n# Table of Contents\n\n\u003c!-- mdformat-toc start --slug=github --no-anchors --maxlevel=4 --minlevel=1 --\u003e\n\n- [Purpose](#purpose)\n  - [Highlights](#highlights)\n- [Table of Contents](#table-of-contents)\n- [Setup](#setup)\n  - [\"Downloading\" zha-toolkit to the `custom_components` directory](#downloading-zha-toolkit-to-the-custom_components-directory)\n  - [Enabling zha-toolkit](#enabling-zha-toolkit)\n  - [Setting permanent logging verbosity](#setting-permanent-logging-verbosity)\n  - [Setting logger verbosity dynamically](#setting-logger-verbosity-dynamically)\n- [Automations](#automations)\n- [Using `zha-toolkit`](#using-zha-toolkit)\n- [General recommendations](#general-recommendations)\n- [Zigbee crash course](#zigbee-crash-course)\n  - [Zigbee, ZHA, zha-device-handlers, zigpy, ZHA-toolkit](#zigbee-zha-zha-device-handlers-zigpy-zha-toolkit)\n- [Common options](#common-options)\n  - [`ieee`: A reference to the device](#ieee-a-reference-to-the-device)\n  - [Response data](#response-data)\n  - [Events](#events)\n  - [Raise an exception on failure](#raise-an-exception-on-failure)\n  - [Tries](#tries)\n- [Service commands](#service-commands)\n  - [`attr_read`: Read an attribute value](#attr_read-read-an-attribute-value)\n    - [Example: attribute read with write to CSV file](#example-attribute-read-with-write-to-csv-file)\n    - [Example of CSV output](#example-of-csv-output)\n    - [Example, read attribute value from cache in HA state](#example-read-attribute-value-from-cache-in-ha-state)\n  - [`attr_write`: Write(/Read) an attribute value](#attr_write-writeread-an-attribute-value)\n  - [Binding related](#binding-related)\n    - [`bind_ieee`: Bind matching cluster to another device](#bind_ieee-bind-matching-cluster-to-another-device)\n    - [`binds_get`: Get binding table from the device](#binds_get-get-binding-table-from-the-device)\n    - [`binds_remove_all`: Remove all device to device bindings](#binds_remove_all-remove-all-device-to-device-bindings)\n    - [`unbind_coordinator`: Remove all bindings to the coordinator](#unbind_coordinator-remove-all-bindings-to-the-coordinator)\n  - [`conf_report`: Configure reporting](#conf_report-configure-reporting)\n  - [`conf_report_read`: Read configured reporting](#conf_report_read-read-configured-reporting)\n  - [`scan_device`: Scan a device/Read all attribute values](#scan_device-scan-a-deviceread-all-attribute-values)\n  - [`zdo_scan_now`: Do a topology scan](#zdo_scan_now-do-a-topology-scan)\n  - [Join \u0026 Network presence related](#join--network-presence-related)\n    - [`handle_join`: Handle join - rediscover device](#handle_join-handle-join---rediscover-device)\n    - [`misc_reinitialize`: Reinitialize device](#misc_reinitialize-reinitialize-device)\n    - [`leave`](#leave)\n    - [`rejoin`](#rejoin)\n    - [`zdo_join_with_code`](#zdo_join_with_code)\n  - [`zcl_cmd`: Send a Cluster command](#zcl_cmd-send-a-cluster-command)\n    - [`zcl_cmd` Example: Send `on` command to an OnOff Cluster.](#zcl_cmd-example-send-on-command-to-an-onoff-cluster)\n    - [`zcl_cmd` Example: Send `off` command to an OnOff Cluster:](#zcl_cmd-example-send-off-command-to-an-onoff-cluster)\n    - [`zcl_cmd` Example: \"Store Scene\"](#zcl_cmd-example-store-scene)\n    - [`zcl_cmd` Example: \"Recall Scene\"](#zcl_cmd-example-recall-scene)\n    - [`zcl_cmd` Example: \"Add Scene\"](#zcl_cmd-example-add-scene)\n    - [`zcl_cmd` Example: Pass keyword arguments](#zcl_cmd-example-pass-keyword-arguments)\n  - [Group related services](#group-related-services)\n    - [`add_group`](#add_group)\n    - [`get_groups`](#get_groups)\n    - [`remove_group`](#remove_group)\n    - [`remove_all_groups`](#remove_all_groups)\n    - [`add_to_group`](#add_to_group)\n    - [`remove_from_group`](#remove_from_group)\n    - [`get_zll_groups`](#get_zll_groups)\n  - [EZSP/Bellows](#ezspbellows)\n    - [`ezsp_backup`: Backup ezsp/bellows network data](#ezsp_backup-backup-ezspbellows-network-data)\n  - [ZNP related (TI Zigbee Radio)](#znp-related-ti-zigbee-radio)\n    - [`znp_nvram_backup`: Backup ZNP NVRAM data](#znp_nvram_backup-backup-znp-nvram-data)\n    - [`znp_nvram_restore`: Restore ZNP NVRAM data](#znp_nvram_restore-restore-znp-nvram-data)\n    - [`znp_nvram_reset`: Reset ZNP NVRAM data](#znp_nvram_reset-reset-znp-nvram-data)\n    - [`znp_backup`: Backup ZNP network data](#znp_backup-backup-znp-network-data)\n    - [`znp_restore`: Restore ZNP network data](#znp_restore-restore-znp-network-data)\n  - [Miscellaneous](#miscellaneous)\n    - [`backup`: Backup the coordinator](#backup-backup-the-coordinator)\n    - [`misc_settime`: Set attributes of a Time Cluster](#misc_settime-set-attributes-of-a-time-cluster)\n    - [`ota_notify` - Download/Trigger Device FW update](#ota_notify---downloadtrigger-device-fw-update)\n    - [`zha_devices`: Device Information to Event or CSV or Script variable](#zha_devices-device-information-to-event-or-csv-or-script-variable)\n    - [`register_services`: Reregister ZHA-Toolkit services](#register_services-reregister-zha-toolkit-services)\n    - [`ha_set_state` - Update HA state](#ha_set_state---update-ha-state)\n    - [`misc_energy_scan`: Perform an energy scan](#misc_energy_scan-perform-an-energy-scan)\n  - [User method](#user-method)\n  - [Manufacturers](#manufacturers)\n    - [Tuya](#tuya)\n      - [`tuya_magic` - Tuya Magic spell](#tuya_magic---tuya-magic-spell)\n- [Credits/Motivation](#creditsmotivation)\n- [License](#license)\n- [Contributing](#contributing)\n\n\u003c!-- mdformat-toc end --\u003e\n\n# Setup\n\n## \"Downloading\" zha-toolkit to the `custom_components` directory\n\nZHA Toolkit uses the well-known HACS installation mechanism. It is\nrecommended to use HACS which facilitates the installation of many other\ncustom components as well.\n\nIf you already have [HACS](https://hacs.xyz/docs/setup/prerequisites)\n([Tutorial](https://codingcyclist.medium.com/how-to-install-any-custom-component-from-github-in-less-than-5-minutes-ad84e6dc56ff)),\nsimply look for \"ZHA Toolkit\" under Integrations or\n[click this redirection](https://my.home-assistant.io/redirect/hacs_repository/?owner=hacs\u0026repository=integration)\nto add it.\n\n![image](https://user-images.githubusercontent.com/1504752/156879928-e81560e1-1c10-4daf-8c17-c1f0bba0828f.png)\n\nIf you are not using HACS, you need add the files in\n`custom_components/zha_toolkit`. See\n[installNoHacsFromZip.sh](scripts/installNoHacsFromZip.sh) and\n[installNoHacsWithGit.sh](scripts/installNoHacsWithGit.sh) for possible\nprocedures.\n\n## Enabling zha-toolkit\n\nIn all cases (HACS or manual), the ZHA Toolkit integration is only active\non your Home Assistance instance after adding next line to\n`configuration.yaml`, and restarting Home Assistant.\n\n```yaml\nzha_toolkit:\n```\n\n## Setting permanent logging verbosity\n\nBefore restarting, you may also want to enable debug verbosity.\n`zha-toolkit` isn't verbose when you use it occasionnaly. As it's a\nservice, there is no really good way to inform the user about errors other\nthan the log.\n\n\u003ca id=\"logging\" /\u003eLogging will help verify that the commands you send have\nthe desired effect.\n\nAdd/update the logger configuration (in the `configuration.yaml` file):\n\n```yaml\nlogger:\n  # The next line sets the default logging level, for all python modules.\n  # It seems \"recommended\" to set it to avoid too much logging.\n  default: warning\n  logs:\n    custom_components.zha_toolkit: debug\n```\n\n## Setting logger verbosity dynamically\n\nYou can also change the log configuration dynamically by calling the\n`logger.setlevel` service. Example that sets the debug level for this\n`zha_toolkit` component and for `zigpy.zcl` (which helps to see some\ninformation about actual ZCL frames sent). This method allows you to enable\ndebug logging only for a limited duration :\n\n```yaml\nservice: logger.set_level\ndata:\n  custom_components.zha_toolkit: debug\n  zigpy.zcl: debug\n```\n\n# Automations\n\nThis is a list (of 1) automation:\n\n- DAILY BACKUP OF ZNP DONGLE:\n  [![Open your Home Assistant instance and show the Daily Backup Blueprint pre-filled.](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fraw.githubusercontent.com%2Fmdeweerd%2Fzha-toolkit%2Fdev%2Fblueprints%2Fbackup_znp.yaml)\n- :warning: Under test DAILY BACKUP OF ZNP/EZSP(Bellows) DONGLE TYPE :\n  [![Open your Home Assistant instance and show the Daily Backup Blueprint pre-filled.](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fraw.githubusercontent.com%2Fmdeweerd%2Fzha-toolkit%2Fdev%2Fblueprints%2Fbackup.yaml)\n\n# Using `zha-toolkit`\n\nThis component provides a single service (`zha_toolkit.execute`) that\nprovides several commands (`command` parameter) providing access to\nZHA/Zigbee actions that are not otherwise available.\n\nYou can use a service as an action in automations. So you can send the\ncommands according to a schedule or other triggers. For instance, you could\nplan a daily backup of your TI-ZNP USB Key configuration.\n\nIt will be more common to send a Zigbee command only once: for instance\nbind one device to another, set a manufacturer attribute, ... .\\\nYou can perform them using the developer tools.\\\nThe developer tools are handy to test the service first before adding them\nto an automation.\n\nGo to Developer Tools \u003e Services in your instance :\n[![Open your Home Assistant instance and show your service developer tools.](https://my.home-assistant.io/badges/developer_services.svg)](https://my.home-assistant.io/redirect/developer_services/).\n\nChoose the generic service `zha_toolkit.execute` or - more convenient - the\nspecific `zha_toolkit.\u003cCOMMAND\u003e` as the service.\\\nMost parameters can be set using the UI, there are some cases where you may\nwant to enable Yaml entry - you'll have some more flexibility and all\nparameters fit in your browser view. On the other hand, the UI interface\nmakes it easier to select the entity. You can switch back and forth!\n\nThere are several examples below for different commands. You can copy/paste\nthem to start from.\n\nNot all available commands are documented. The undocumented ones were in\nthe original repository.\\\nSome of these undocumented commands seem to be very specific trials from\nthe original authors.\\\nFeel free to propose documentation updates.\n\n# General recommendations\n\n- Check this README.\n- Use [`scan_device`](#scan_device-scan-a-deviceread-all-attribute-values)\n  to find out more about your device.\n- Use the Service Response to see what happens.\n- Use Events to see what happens (if you can't use the service Response).\n- Use `home-assistant.log` to see what happened.\n- Set the log level to debug\n  ([See Setup](#setting-logger-verbosity-dynamically) to get more facts.\n- Check the\n  [Github open and closed issues](https://github.com/mdeweerd/zha-toolkit/issues?q=is%3Aissue)\n- Check the\n  [Home Assistant Forum](https://community.home-assistant.io/search?q=zha_toolkit)\n- Check the [examples directory](examples)\n- Check\n  [zhaquirks](https://github.com/zigpy/zha-device-handlers/tree/dev/zhaquirks)\n  for hints about available attributes (available ones, meaning of their\n  values)\n- Wake up sleepy devices (generally devices on a battery) just after\n  sending a command so that they can receive it. It's also recommended to\n  set the `tries` parameter to a fairly high number for these devices (in\n  some cases over a 100 tries (more than 10 minutes) are needed to\n  successfully communicate with a sleepy device).\n\n# Zigbee crash course\n\nNote: this crash course's wording may deviate from Zigbee's wording.\n\nZigbee is a wireless communication protocol used for creating networks of\ndevices. To understand Zigbee, we can look at it from two perspectives: the\nnetwork-oriented view and the device-oriented view.\n\nFrom a network perspective, there is a coordinator, which is the main\ndevice controlling the network (often your Home Assistant instance), and\nthere are other devices categorized as routers and end devices.\\\nRouters are permanently powered devices that store and forward messages,\nwhile end devices can be any type of device. End devices can reply to\nrequests and communicate autonomously if they have reporting configurations\nand bindings set up. Reporting configurations determine when a device\nshould communicate attribute changes, and bindings specify which device or\ngroup should receive these changes.\\\nCommands, such as those triggered by a button press, can also be bound to\nspecific devices or groups.\n\nFrom a device perspective, devices are organized into endpoints.\\\nAn endpoint represents a function or feature of the device. For example, a\ndevice with two switches would have an endpoint for each switch function,\nand a device with a temperature and humidity sensor may have an endpoint\nfor each sensor.\\\nEndpoints can also represent Zigbee-specific functionalities like Over The\nAir (OTA) updates or Green Power functionality.\n\nEach endpoint has attributes associated with it.\\\nAttributes allow you to control the configuration of the device or retrieve\nvalues for its current state, such as on/off status or temperature\nreadings.\\\nAttributes are grouped into clusters, which are reusable sets of features.\\\nClusters represent things like on/off state, color control, temperature\nmeasurement, energy metering, and more.\n\nIn practice, clusters are defined on endpoints, and each attribute has a\nunique address consisting of the IEEE address (a 64-bit number), the\nendpoint ID (a byte), the cluster ID (a two byte word), and the attribute\nID (a two byte word as well).\n\nAttributes have different types, such as boolean, unsigned and signed byte,\narrays, timestamps, and more. In most cases, the attribute type can be\ndetermined automatically by tools like zha-toolkit and ZHA.\n\nThe Zigbee Cluster Library (ZCL) document defines standard attributes and\ntheir organization in clusters. Manufacturers also have the freedom to add\ntheir own attributes that are not defined in the ZCL.\n\nCommands and attribute read/write operations are typically initiated from\nthe coordinator. However, Zigbee devices can also send commands to other\ndevices, like a switch instructing a light bulb to turn on or off.\n\nTo avoid excessive network traffic caused by constantly polling devices for\ntheir internal state, devices can be configured to report their state\nchanges to other devices in the network.\\\nThis reporting is accompanied by bindings, which specify the devices or\ngroups that should receive the data.\n\nBinding can also make an endpoint on a device respond to commands sent to a\nspecific group.\\\nFor example, if you add a switch's endpoint and multiple light bulbs to a\ngroup, the switch can control all the bulbs in that group.\n\nWhen a new device is added to a Zigbee network through Home Assistant's ZHA\nintegration, an initial configuration is sent to the device. This\nconfiguration sets up reporting and binding settings to ensure that the\ndevice notifies the coordinator about its state changes or any relevant\ndata changes, such as energy consumption metrics or simply informing that a\nlight has been switched on.\n\nZigbee routers play an important role in the network by relaying messages\nbetween devices, bridging longer distances, and temporarily storing\nmessages for battery-powered devices that wake up periodically. Messages\nare typically stored for around 6 seconds.\n\nBattery-powered devices are considered \"sleepy\" devices because they\nconserve energy by sleeping most of the time. However, this can lead to\ndata requests and commands being lost if the device is asleep when they are\nsent. To ensure successful communication, requests may need to be actively\nrepeated until the sleepy device wakes up and responds.\n\nIn some cases, it is necessary to provide the manufacturer ID to access a\nmanufacturer-specific attribute or execute a manufacturer-specific command\nto use features or functionalities specific to the device manufacturer,\n\n## Zigbee, ZHA, zha-device-handlers, zigpy, ZHA-toolkit\n\n[ZHA](https://github.com/home-assistant/core/tree/dev/homeassistant/components/zha)\nand\n[zha-device-handlers](https://github.com/zigpy/zha-device-handlers/tree/dev/zhaquirks)\nand [zigpy](https://github.com/zigpy/zigpy) intend to wrap the zigbee\nattribute operations and commands so that the Zigbee device features are\nimmediately usable in Home Assistant. The quality of these integrations and\nlibraries are ensured through unit tests.\n\n- `zigpy` is a library/gateway that bridges the gap between python and the\n  zigbee coordinator hardware.\n- ZHA interfaces zigpy with Home Assistant.\n- The zha-device-quirks library is delivered at the same time as ZHA and\n  adapts \"quirky\" device behavior to interface with Home Assistant through\n  ZHA. \"Quirky\" device behavior means that a device is providing\n  functionality not or not as anticipated in the Zigbee specifications.\n- ZHA-Toolkit is there to help with using device functionalities that are\n  not fully supported yet in ZHA, or help implement scripts and automations\n  that are not part of the main focus of the ZHA integration. There\n  currently are no test cases - so there is less quality assurance and a\n  function might accidentally drop at some point. It is not autonomously\n  listening in on Zigbee messages to generate Home Assistant events for\n  instance, but you can use it to poll devices and update state values\n  directly, or send commands you can't send through ZHA. ZHA-Toolkit can\n  help with diagnostics and device configurations.\n\n# Common options\n\n## `ieee`: A reference to the device\n\nIn almost all commands you need to provide a reference to the device that\nyou want to control.\n\nEasiest, use an entity name:\n\n```yaml\naction: zha_toolkit.SOME_SERVICE\ndata:\n  # entity name (one of them)\n  ieee: light.tz3000_odygigth_ts0505a_12c90efe_level_light_color_on_off\n```\n\nHarder, find and use the IEEE address:\n\n```yaml\naction: zha_toolkit.SOME_SERVICE\ndata:\n  # Valid possibilities for the ieee address\n  # The full IEEE address:\n  ieee: 00:12:4b:00:24:42:d1:dc\n```\n\nEven more difficult, find and use the devices' short address, which may\nchange over time.\n\n```yaml\naction: zha_toolkit.SOME_SERVICE\ndata:\n  # The short network address\n  ieee: 0x2F3E\n```\n\nThe `ieee` address can be the IEEE address, the short network address\n(0x1203 for instance), or the entity name (example:\n`light.tz3000_odygigth_ts0505a_12c90efe_level_light_color_on_off`). Be\naware that the network address can change over time but it is shorter to\nenter if you know it.\n\nThere is no universal \"best\" way of selecting the device.\n\n- The IEEE address is the only reference that does not change over time.\n- The entity name is surely easiest to find. While as a user you can change\n  it, it is also somewhat stable when you replace a device - you could keep\n  the same entity name for a difference device.\n- The short address might be shorter to type if you already know it, but do\n  not rely on it if you scripts needs to continue to work over time.\n\nSometime the `command_data` field provides a reference to a device (for\ninstance, when binding one device to another). It has the same flexibility\nas the `ieee` argument.\n\n## Response data\n\nThe zha-toolkit services return their results as\n[response data](https://www.home-assistant.io/blog/2023/07/05/release-20237/#services-can-now-respond)\nfor Home Assistant installations that have at least version 2023.7 .\n\nThis response is available in automations and script by adding\n`response_variable: VAR_NAME` to the `zha_toolkit` service call. That will\nmake the data available under VAR_NAME inside the automation or script.\\\nAn example using the response data can be found in\n[script_use_zha_devices_response.yaml](examples/script_use_zha_devices_response.yaml).\n\nThe response data feature of Home Assistant also makes the response\navailable when calling the service interactively.\\\nThe image below shows a an interactive attribute read using the zha-toolkit\nservice attr_read. The response data is shown in Yaml format when the call\nfinishes.\n\n![Service Response Example](images/ServiceResponse.png)\n\n## Events\n\nEvents in Home Assistant are a way to trigger or proceed in automations and\nscripts, and convey data.\n\nAll zha-toolkit commands support setting event names that are fired at the\nend of the command execution.\n\nYou can interactively listen for events in the Developer Tools\u003eEvents page\nwhich is a good way to check the result of a zha-toolkit service that you\nstart in another tab of your browser.\n\nYou can set the event names as follows:\n\n```yaml\naction: zha_toolkit.SERVICE_NAME\ndata:\n  # You can set the next events to use as a trigger.\n  # The event data has the result of the command\n  event_success: my_read_success_trigger_event\n  event_fail: my_read_fail_trigger_event\n  event_done: my_read_done_trigger_event\n```\n\nIt's recommended to use the `event_done` event during interactive use. You\ncan use `Developer Tools \u003e Events \u003e Listen to events` to see the result of\nthe service call. You need to use `Listen to events` in a separate\nnavigator tab, `START LISTENING` and leave it open to see the data of the\nevents.\n\nBy listening for the event, you can see the list of groups that is found\nwhen using `zha_toolkit.get_groups` for instance.\\\nOtherwise you need to [set the debug level](#logging) and watch the\n`home-assistant.log`. That can be useful if you do a lot of service calls\nin sequence and you want to look back what happened.\n\nYou can also simply always enable debugging for `zha_toolkit` if you use it\nsporadically - it is quite verbose and tends to fill up the logs if you use\nit often.\n\n## Raise an exception on failure\n\n```yaml\naction: zha_toolkit.SERVICE_CALL\ndata:\n  fail_exception: true\n```\n\nBy default, the result of a zigbee transaction is \"ignored\" for the end\nresult of the service call: it will appear as if it succeeds (unless you\nhave the parameters wrong).\n\nSo, if you want the `Developer Tools \u003e Services \u003e CALL SERVICE` button to\nturn red in case the zigbee transaction result is not `SUCCESS`, then add\n`fail_exception: true` to the options\n\n## Tries\n\n```yaml\naction: zha_toolkit.SERVICE_CALL\ndata:\n  tries: 10\n```\n\nTries indicates how many times a zigbee transaction is repeated until it\nsucceeds. An individual zigbee transaction may fail because of radio\ninterference or because the device is sleeping.\n\nSo by setting `tries: 100` you'll request that zigbee requests are repeated\nup to 100 times.\n\nThis is not applied everywhere, but it's applied for attribute reading,\nwriting and report configuration. It's handy when you want to change the\nreport configuration of your battery powered thermometer for instance.\n\nYou may still need to wake them up just after sending the command so that\nthey can receive it.\n\n# Service commands\n\nServices are easy to called once or tested through Developer Tools \u003e\nServices . And you can also use them in scripts, automations, etc. .\n\nQuite a few services can be configured from the UI. And you can also start\nusing the UI (to select the ieee/entity for instance), and then Go To YAML\nmode to add the other parameters.\n\nEmpty UI example: ![image](images/service-config-ui.png)\n\nAn example of event data is shown below. The `data\u003eerrors` field can be\nuseful to understand what went wrong. The `ieee_org` fields take the\noriginal value of the \"ieee\" parameter, and the `ieee` field is the actual\nIEEE address found.\n\n```json\n{\n  \"event_type\": \"my_write_done_trigger_event\",\n  \"data\": {\n    \"ieee_org\": \"sensor.test_smartenergy_metering\",\n    \"ieee\": \"00:12:4b:00:24:42:d1:dc\",\n    \"command\": \"attr_write\",\n    \"start_time\": \"2022-01-17T21:51:50.416725+00:00\",\n    \"errors\": [],\n    \"params\": {\n      \"cmd_id\": null,\n      \"endpoint_id\": 1,\n      \"cluster_id\": 0,\n      \"attr_id\": 16,\n      \"attr_type\": 66,\n      \"attr_val\": \"BureauTest\",\n      \"min_interval\": 60,\n      \"max_interval\": 300,\n      \"reportable_change\": 1,\n      \"dir\": null,\n      \"manf\": null,\n      \"tries\": 1,\n      \"expect_reply\": true,\n      \"args\": [],\n      \"state_id\": \"sensor.test\",\n      \"state_attr\": null,\n      \"allow_create\": true,\n      \"event_success\": \"my_write_success_trigger_event\",\n      \"event_fail\": \"my_write_fail_trigger_event\",\n      \"event_done\": \"my_write_done_trigger_event\",\n      \"read_before_write\": true,\n      \"read_after_write\": true,\n      \"write_if_equal\": false\n    },\n    \"str\": \"BureauTest\",\n    \"read_before\": [\n      {\n        \"16\": \"Bureau\"\n      },\n      {}\n    ],\n    \"result_write\": [\n      [\n        {\n          \"status\": 0,\n          \"attrid\": null\n        }\n      ]\n    ],\n    \"result_read\": [\n      {\n        \"16\": \"BureauTest\"\n      },\n      {}\n    ],\n    \"success\": true\n  },\n  \"origin\": \"LOCAL\",\n  \"time_fired\": \"2022-01-17T21:52:02.066310+00:00\",\n  \"context\": {\n    \"id\": \"c5d4d0d14f7801fda3b9ad471dcbd83b\",\n    \"parent_id\": null,\n    \"user_id\": null\n  }\n}\n```\n\nHome Assistant evolved and now shows the event data as a yaml structure.\n\nServices that are not documented in the sections that follow below (not\nincluding undocumented ezsp commands):\n\n- `all_routes_and_neighbours`\n- `bind_group`\n- `get_routes_and_neighbours`\n- `ieee_ping`\n- `unbind_group`\n- `zdo_flood_parent_annce`\n- `zdo_update_nwk_id`\n\n## `attr_read`: Read an attribute value\n\nRead a zigbee attribute value, optionally write to a state.\n\n```yaml\naction: zha_toolkit.attr_read\ndata:\n  ieee: sensor.zigbee_sensor\n  # The endpoint is optional - when missing tries to find endpoint matching the cluster\n  # endpoint: 1\n  # Cluster Id - Can be omitted if attribute is unique string.\n  cluster: 0xb04\n  # Attribute Id or String - Example \"pi_heating_demand\"\n  attribute: 0x50f\n  # Optional, read the value from memory cache, do not make a zigbee read request.\n  # Can be false, true, 0, 1 or 2 where '2' requests to fallback to a real read\n  # if the value is not in cache.\n  use_cache: true\n  # Optional, state to write the read value to\n  state_id: sensor.test\n  # Optional, state attribute to write the value to, when missing: writes state itself\n  state_attr: option\n  # Optional, when true, allows creating the state (if not the state must exist)\n  allow_create: true\n  # The manufacturer should be set only for manufacturer attributes\n  manf: 0x1212\n  # Write read value to CSV file\n  # Can be useful in automation/script\n  # Format: \u003ctimestamp\u003e,\u003cname|attr_id\u003e,\u003cvalue\u003e,\u003cattr_id\u003e,\u003ccluster_id\u003e,\u003cep_id\u003e,\u003cieee\u003e,\u003cmanf_id\u003e\n  # Optional: CSV file to write attribute to - located in /config/csv/...\n  csvout: testcsv.csv\n  # optional: csvlabel (default label = name from zigpy or attribute id)\n  csvlabel: MyAttributeLabel\n```\n\n### Example: attribute read with write to CSV file\n\n```yaml\naction: zha_toolkit.attr_read\ndata:\n  ieee: light.texasinstruments_ti_samplelight_d77add01_level_light_color_on_off\n  event_done: zha_done\n  attribute: 0\n  cluster: 0\n  csvout: testcsv.csv\n```\n\n### Example of CSV output\n\nBelow is the result in `/config/csv/testcsv.csv` produced by the\n`attr_read` shown above.\n\n```csv\n2022-02-01T00:10:50.202707+00:00,zcl_version,1,0x0000,0x0000,11,00:12:4b:00:01:dd:7a:d7,,0x20\n```\n\nFields in this output:\n\n```csv\nISO8601_Timestamp,cluster_name,attribute_name,value,attr_id,cluster_id,endpoint_id,IEEE,manf,attr_type\n```\n\n### Example, read attribute value from cache in HA state\n\nThis example reads the raw temperature value from cache into a home state\nattribute value.\n\nThe purpose of this example is to get the unrounded reported value from a\ntemperature sensor.\n\nA battery powered temperature sensor is often sleepy and doing a real\nattribute read may need many tries.\n\nSo this technique allows reading the value from the attribute cache. It\ndoes not use the attribute cache database table, but tries to get the value\nfrom the in-memory cache.\n\nWhen `use_cache` is 2, an actual read will be executed if the attribute is\nnot in cache.\n\n```yaml\naction: zha_toolkit.attr_read\ndata:\n  ieee: sensor.temperature_chambre_x_temperature_2\n  cluster: 1026\n  attribute: 0\n  use_cache: true\n  state_id: sensor.temperature_chambre_x_temperature_2\n  state_attr: raw_degc\n  # When defined, the read attribute is converted using this template string\n  # before writing it to the state.\n  # Note that no curly braces should be used here!\n  state_value_template: value/100\n```\n\nFor a real use case, see the example\n[danfoss_ally_remote_temperature_min_delay.yaml](blueprints/danfoss_ally_remote_temperature_min_delay.yaml)\nwhere the automation attempts to read the temperature from the zigbee cache\nto get more precision (0.01°C) as ZHA rounds values to 0.1°C.\n\n## `attr_write`: Write(/Read) an attribute value\n\nWrite an attribute value to any endpoint/cluster/attribute.\n\nYou can provide the numerical value of the attribute id, or the internal\nzigpy name (string).\n\nBefore and after writing, the value is read from the attribute. If debug\nlogging is active, this will be visible in the `home_assistant.log`. The\nlast read this can be written to a state.\n\nNote that the format/typing of the value for `attr_val` depends on the\nattribute type. `uint*`, `int*` and `enum*` types can be specified as\nnumbers, most other types must be specified as an array of bytes or a\nstring. If you are not sure how to represent the value, you could do an\n`attr_read` first while observing the `event_done` event to check how the\n`attr_val` is returned upon read.\n\nIn the yaml example detailing the available parameters to `attr_write` it\nis shown how to specify the value for an `octet_string` as an array/list.\n\n```yaml\naction: zha_toolkit.attr_write\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  # The endpoint is optional,\n  # when missing, attr_write will find the endpoint\n  # by matching the cluster which works if there is\n  # only one endpoint with that cluster.\n  endpoint: 11\n  cluster: 0x1706\n  attribute: 0x0000\n  attr_type: 0x41\n  # Example of octet strings (the length is added because of attr_type)\n  attr_val: [41, 33, 8, 45, 52, 46, 50, 191, 55, 57, 136, 60, 100, 102, 63]\n  # Optional manufacturer Id\n  # - The manufacturer should be set only for manufacturer attributes\n  manf: 0x1021\n  # Optional, state to write the read value to\n  state_id: sensor.test\n  # Optional, state attribute to write the value to, when missing: writes state itself\n  state_attr: option\n  # Optional, when true, allows creating the state (if not the state must exist)\n  allow_create: true\n  # You can set the next events to use as a trigger.\n  # The event data has the result of the command (currently attr_read, attr_write)\n  event_success: my_read_success_trigger_event\n  event_fail: my_read_fail_trigger_event\n  event_done: my_read_done_trigger_event\n  # Settings for attr_write\n  # Read attribute before writing it (defaults to True)\n  read_before_write: true\n  # Read attribute after writing it (defaults to True)\n  read_after_write: true\n  # Write attribute when the read value matches (defaults to False)\n  write_if_equal: false\n```\n\nIn case ZCL Array type needs to be written, `attr_val` needs to be provided\nas a raw sequence of bytes, i.e. user is responsible to generate a sequence\nwhich complies to the ZCL spec.\\\nThe following examples illustrates configuration of Ubisys C4 (see\n[the device manual](https://www.ubisys.de/wp-content/uploads/ubisys-c4-technical-reference.pdf)\n\\- section 7.8.5.2. InputActions Attribute - example):\n\n```yaml\naction: zha_toolkit.attr_write\ndata:\n  ieee: 00:1f:ee:00:00:aa:aa:aa\n  endpoint: 232\n  cluster: 64512\n  attribute: 1\n  attr_type: 0x48\n  # For the array type (type 0x48):\n  #  - The first byte is the type of items.  here 65 or 0x41: octet str.\n  #  - The second and third byte compose the length (little endian)\n  #    So here: `4, 0` is 0x0004, so four octet strings the array.\n  #  - All the octet strings in this example have a length of 6.\n  attr_val: [65, 4, 0, 6, 0, 13, 1, 6, 0, 2, 6, 1, 13, 2, 6, 0, 2, 6, 2, 13, 3, \n        6, 0, 2, 6, 3, 13, 4, 6, 0, 2]\n  read_before_write: false\n  read_after_write: false\n  use_cache: false\n```\n\nSuch a packet decoded using tshark/wireshark, the above results in:\n\n```plaintext\nZigBee Cluster Library Frame, Command: Write Attributes, Seq: 40\n    Frame Control Field: Profile-wide (0x00)\n        .... ..00 = Frame Type: Profile-wide (0x0)\n        .... .0.. = Manufacturer Specific: False\n        .... 0... = Direction: Client to Server\n        ...0 .... = Disable Default Response: False\n    Sequence Number: 40\n    Command: Write Attributes (0x02)\n    Attribute Field\n        Attribute: Unknown (0xfde8)\n        Data Type: Array (0x48)\n        Elements Type: Octet String (0x41)\n        Elements Number: 4\n        Element #1, Octets: 00:0d:01:06:00:02\n            Octet String: 00:0d:01:06:00:02\n        Element #2, Octets: 01:0d:02:06:00:02\n            Octet String: 01:0d:02:06:00:02\n        Element #3, Octets: 02:0d:03:06:00:02\n            Octet String: 02:0d:03:06:00:02\n        Element #4, Octets: 03:0d:04:06:00:02\n            Octet String: 03:0d:04:06:00:02\n\nDecrypted ZigBee Payload (45 bytes) - only Array related data is shown:\n0000                                         48 41 04   @........(...HA.\n0010  00 06 00 0d 01 06 00 02 06 01 0d 02 06 00 02 06   ................\n0020  02 0d 03 06 00 02 06 03 0d 04 06 00 02            .............\n```\n\nUsing the symbolic name of the attribute, and automatic endpoint selection.\n\n```yaml\naction: zha_toolkit.attr_write\ndata:\n  ieee: button.fictious_model_dcd14224_identify\n  cluster: 0\n  attribute: location_desc\n  attr_val: My Location\n```\n\nA more complex example using HA's templating feature can be found below.\\\nEach call will increment the previous target temperature by 0.5 degrees\n(increment by 50 in Zigbee's unit) up to 22.50 degrees and restart from 20\ndegrees.\\\nOn the first call (when the state is not set yet), the setpoint temperature\nis 21.5 degrees.\n\nThe toolkit implements a read after each write (and it is not disabled by a\n`read_after_write` parameter), so it will write the temperature value to\nthe state `sensor.tgt_temperature`.\n\nNote that a template is evaluated before calling the service, so the\n`read_before_write` can't influence the attribute to write during the same\nservice call even though it updates the attribute. The read before write\ncould still be useful if you want to track updates in history graphs for\ninstance.\n\nThis example also uses the attribute name, not the attribute id.\n\nTries is set to 3 to cope with some uncommon communication issues.\n\n```yaml\naction: zha_toolkit.attr_write\ndata:\n  ieee: entity.my_thermostat_entity\n  cluster: 0x201\n  attribute: occupied_heating_setpoint\n  attr_val: \"{% set t = states('sensor.tgt_temperature') %}{{ [(t|int+50) % 2300,2000]|max\n    if is_number(t) else 2150 }}\"\n  state_id: sensor.tgt_temperature\n  allow_create: true\n  read_before_write: false\n  tries: 3\n  fail_exception: true\n```\n\n## Binding related\n\nThe default list of binding clusters is currently as follows:\n\n- in clusters:\n  - 0x0006 - OnOff\n  - 0x0008 - Level\n  - 0x0300 - Color Control\n- out clusters:\n  - 0x0402 - Temperature\n\n### `bind_ieee`: Bind matching cluster to another device\n\nBind all available default and matching clusters from `ieee` to\n`command_data` on all endpoints.\\\nBinds to the coordinator if `command_data` is not set or 0.\\\nBy default only binds cluster types in the internal list, i.e. OnOff, Level\nand Color Control clusters.\n\nThe cluster must exist on both devices, except when the coordinator is the\ntarget.\n\nIf you set the `cluster`, you can bind another cluster type and only that\ncluster will be bound (both in and out clusters).\n\nUse `binds_get` to verify that the configuration worked.\n\nIt's possible to attempt binding specific endpoints between `ieee` and\n`command_data`.\\\nThe endpoint for `ieee` (source) can be provided by `endpoint`.\\\nIf it's not specified then all endpoints on `ieee` are considered.\\\nEndpoint for `command_data` (destination) can be provided by\n`dst_endpoint`. If it's not specified then all endpoints on `command_data`\nare considered\\\nand the first one that matches cluster-wise will be picked.\n\n```yaml\naction: zha_toolkit.bind_ieee\ndata:\n  ieee: entity.my_thermostat_entity\n  # Optional, when not set or 0, bind to the coordinator.\n  command_data: 00:12:4b:00:22:08:ed:1a\n  # Optional, if you want to bind a cluster not internally selected.\n  cluster: 0x0006\n  # Optional: source endpoint (for ieee)\n  endpoint: 2\n  # Optional: destination endpoint (for command_data)\n  dst_endpoint: 3\n```\n\n### `binds_get`: Get binding table from the device\n\nGet the bindings from the device.\\\nListen to the event, or enable debug and check the log to get the\ninformation.\n\n```yaml\naction: zha_toolkit.binds_get\ndata:\n  ieee: 00:15:8d:00:04:7b:83:69\n  # Optional number of tries for each sub-request,\n  # useful for sleepy devices\n  tries: 100\n  event_done: event_binds_get_done\n```\n\n### `binds_remove_all`: Remove all device to device bindings\n\nRemove all bindings from the device.\\\nThis internally fetches all the existing bindings (`binds_get` service) and\nrequests the device to remove them.\n\n```yaml\naction: zha_toolkit.binds_remove_all\ndata:\n  ieee: entity.my_thermostat_entity\n  # Optional - only remove binding to device\n  command_data: 00:12:4b:00:01:6a:41:0c\n  # Optional - name of generated event when done\n  event_done: zhat_event\n  # Optional - Endpoint or list of endpoints for which to remove bindings\n  # endpoint: [20, 30]\n  # Optional - Cluster or list of clusters for which to remove bindings\n  # cluster: [0x0006, 0x0300]\n  # Optional\n  tries: 100\n```\n\n### `unbind_coordinator`: Remove all bindings to the coordinator\n\nRemove all bindings from the device to the coordinator. Typically, on\ndevice initialization Home Assistant sets up bindings with the main\nclusters to that it is informed about state changes.\n\nThis command will use `binds_remove_all` and set the coordinator's ieee\naddress as the `command_data` parameter automatically avoiding that you\nhave to look it up.\n\n```yaml\naction: zha_toolkit.unbind_coordinator\ndata:\n  ieee: entity.my_thermostat_entity\n  # Optional - name of generated event when done\n  event_done: zhat_event\n  # Optional - Endpoint or list of endpoints for which to remove bindings\n  # endpoint: [20, 30]\n  # Optional - Cluster or list of clusters for which to remove bindings\n  # cluster: [0x0006, 0x0300]\n  # Optional\n  tries: 100\n```\n\n## `conf_report`: Configure reporting\n\nSet the minimum and maximum delay between two reports and set the level of\nchange required to report a value (before the maximum delay is expired).\n\nThis example configures Temperature reporting on a SonOff SNZB-02\n(eWeLink/TH01). Note that on some devices you (may) need to press the\nbutton on the thermometer just after requesting the command (it's a sleepy\ndevice and does not wake up often). With a temperature sensor it may be\nmore appropriate to sure a high temperature rise to force it to report the\ntemperature and allow ZHA to send the configuration.\n\nAfter succeeding the configuration, the minimum delay was actually 20s\nwhich is likely the measurement period itself. The changes were reported\nwhen they exceeded 0.10 degrees C.\n\nFor sleepy devices, you can add the parameter 'tries' which will retry\nuntil the devices confirms (with success or error)\n\n```yaml\naction: zha_toolkit.conf_report\ndata:\n  ieee: 00:12:4b:00:23:b3:da:a5\n  # Optional endpoint, when missing will match cluster\n  # endpoint: 1\n  cluster: 0x402\n  attribute: 0x0000\n  min_interval: 60\n  max_interval: 300\n  reportable_change: 10\n  # Optional manufacturer\n  #manf: 0x1204\n  # Optional number of configuration attempts\n  tries: 3\n  # You can set the next events to use as a trigger.\n  # The event data has the result of the command (currently attr_read, attr_write)\n  event_success: my_conf_success_trigger_event\n  event_fail: my_conf_fail_trigger_event\n  event_done: my_conf_done_trigger_event\n```\n\nExample of data available in the event report.\n\n```json\n{\n  \"event_type\": \"my_conf_done_trigger_event\",\n  \"data\": {\n    \"ieee\": \"00:12:4b:00:24:42:d1:dc\",\n    \"command\": \"conf_report\",\n    \"start_time\": \"2022-01-16T21:56:21.393322+00:00\",\n    \"params\": {\n      \"cmd_id\": null,\n      \"endpoint_id\": 1,\n      \"cluster_id\": 513,\n      \"attr_id\": 0,\n      \"attr_type\": null,\n      \"attr_val\": null,\n      \"min_interval\": 60,\n      \"max_interval\": 300,\n      \"reportable_change\": 10,\n      \"dir\": null,\n      \"manf\": null,\n      \"tries\": 3,\n      \"expect_reply\": true,\n      \"args\": [],\n      \"state_id\": \"sensor.test\",\n      \"state_attr\": null,\n      \"allow_create\": true,\n      \"event_success\": \"my_conf_success_trigger_event\",\n      \"event_fail\": \"my_conf_fail_trigger_event\",\n      \"event_done\": \"my_conf_done_trigger_event\",\n      \"read_before_write\": true,\n      \"read_after_write\": true,\n      \"write_if_equal\": false\n    },\n    \"result_conf\": [\n      [\n        {\n          \"status\": 0,\n          \"direction\": null,\n          \"attrid\": null\n        }\n      ]\n    ]\n  },\n  \"origin\": \"LOCAL\",\n  \"time_fired\": \"2022-01-16T21:56:28.248353+00:00\",\n  \"context\": {\n    \"id\": \"596b9ba7b29d76545295881ea73c5708\",\n    \"parent_id\": null,\n    \"user_id\": null\n  }\n}\n```\n\n## `conf_report_read`: Read configured reporting\n\nRead the report configuration of a cluster.\n\n```yaml\naction: zha_toolkit.conf_report_read\ndata:\n  ieee: 00:12:4b:00:23:b3:da:a5\n  # Optional endpoint, when missing will match cluster\n  # endpoint: 1\n  cluster: 0x402\n  attribute: 0x0000\n  # Optional manufacturer\n  #manf: 0x1204\n  event_done: my_conf_read_done_trigger_event\n```\n\nExample result (partial event data) where the min and max reporting\nintervals are provided, as well as the reportable change:\n\n```json\n{\n  \"result_conf\": [\n    {\n      \"cluster\": \"Metering\",\n      \"cluster_id\": \"0x0702\",\n      \"attr_id\": \"0x0000\",\n      \"direction\": 0,\n      \"type\": \"0x25\",\n      \"min_interval\": 1,\n      \"max_interval\": 300,\n      \"reportable_change\": 1,\n      \"status\": 0\n    }\n  ]\n}\n```\n\n## `scan_device`: Scan a device/Read all attribute values\n\n`scan_device` will generated a report the discovered clusters, attributes,\nvalues and commands if the device implements this feature.\n\nThis can help you in discovering what you can configure on your device and\nwhat the values are at some point in time.\n\nIf the device does not fully support the discovery features, you could\nstill write a script that would try to read the attributes that you want to\npoke using `attr_read`.\n\nThe result of the scan is written to the `scan` directory located in the\nconfiguration directory of Home Assistant (`config/scan/*_result.txt`).\n\nThe result is also added to the event data in the `event['data']['scan']`\nfield which is also available in the response data.\n\n```yaml\naction: zha_toolkit.scan_device\ndata:\n  ieee: 00:12:4b:00:22:08:ed:1a\n  # Optional: endpoint to scan, when missing: all known endpoints\n  # endpoint: 1\n  # Optional: endpoints to scan, when missing: all known endpoints\n  endpoint: [1, 2]\n  # Optional: tries  Default:3 higher is useful for sleepy devices\n  tries: 100\n```\n\nScan using the entity name:\n\n```yaml\naction: zha_toolkit.scan_device\ndata:\n  ieee: light.tz3000_odygigth_ts0505a_12c90efe_level_light_color_on_off\n```\n\n## `zdo_scan_now`: Do a topology scan\n\nRuns `topology.scan()`.\n\n```yaml\naction: zha_toolkit.execute\ndata:\n  command: zdo_scan_now\n```\n\n## Join \u0026 Network presence related\n\n### `handle_join`: Handle join - rediscover device\n\nYou may want to try\n[`misc_reinitialize`](#misc_reinitialize-reinitialize-device) as\n`handle_join` will not redo any joining step that already completed.\n\n```yaml\naction: zha_toolkit.execute\ndata:\n  # Address of the device that joined\n  ieee: 00:12:4b:00:22:08:ed:1a\n  command: handle_join\n  # NWK address of device that joined (must be exact)\n  command_data: 0x604e\n```\n\n### `misc_reinitialize`: Reinitialize device\n\n`misc_reinitialize` is a pretty dirty (white-hat) hack to reinitialize a\ndevice by making zigpy think the device is not initialized, and then\nrequesting an initialization.\n\nThis is more than `handle_join` which is not reinitializing much when the\ndevice is already set up in zigpy.\n\n`misc_reinitialize` sets several device attributes to None and False so\nthat the zigpy initialization code will proceed with initialization.\n\n```yaml\naction: zha_toolkit.misc_reinitialize\ndata:\n  # Reference of the device that should be reinitialized\n  ieee: 00:12:4b:00:22:08:ed:1a\n```\n\n### `leave`\n\nSend Leave Request to the device.\n\n```yaml\naction: zha_toolkit.leave\ndata:\n  # Reference of the device that should be reinitialized\n  ieee: 00:12:4b:00:22:08:ed:1a\n  # (Parent ) IEEE address (router) that removes the device (required).\n  command_data: 00:12:4b:00:01:6a:41:0c\n```\n\n### `rejoin`\n\nSend Rejoin Request to the device (=Leave with Rejoin).\n\n```yaml\naction: zha_toolkit.rejoin\ndata:\n  # Reference of the device that should be rejoined\n  ieee: 00:12:4b:00:22:08:ed:1a\n  # Optional, device that will accept joining.\n  command_data: 00:12:4b:00:10:00:1d:1a\n```\n\n### `zdo_join_with_code`\n\nCurrently for \"bellow's\" radio types.\n\n```yaml\naction: zha_toolkit.zdo_join_with_code\ndata:\n  # Reference of the device that allows the join\n  ieee: 00:12:4b:00:22:08:ed:1a\n  # The code to be used in the join\n  code: Joining Code\n```\n\n## `zcl_cmd`: Send a Cluster command\n\nAllows you to send a cluster command. Also accepts command arguments.\n\nNote:\\\nThere is also the official core service `zha.issue_zigbee_cluster_command`.\nYou may want to use that instead if it suits your needs.\\\nThe `zha_toolkit` version allows lists of bytes as arg parameters, and has\na hack to allow \"Add Scene\". It is also easier to adapt than the core that\nhas though release procedures and is not as easily modifiable as a\n`custom_component`.\n\n```yaml\naction: zha_toolkit.zcl_cmd\ndata:\n  # Device IEEE address - mandatory\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  # Command id - mandatory\n  cmd: 0\n  # Cluster id - mandatory\n  cluster: 1006\n  # Endpoint - mandatory\n  endpoint: 111\n  # Optional: direction (0=to in_cluster (default), 1=to out_cluster),\n  dir: 0\n  # Optional: expect_reply  (default=true - false when 0 or 'false')\n  expect_reply: true\n  # Optional: manf - manufacturer - default : None\n  manf: 0x0000\n  # Optional: tries - default : 1\n  tries: 1\n  # Optional (only add when the command requires it): arguments (default=empty)\n  args: [1, 3, [1, 2, 3]]\n\n```\n\n### `zcl_cmd` Example: Send `on` command to an OnOff Cluster.\n\n```yaml\naction: zha_toolkit.zcl_cmd\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  cmd: 1\n  cluster: 6\n  endpoint: 11\n```\n\n### `zcl_cmd` Example: Send `off` command to an OnOff Cluster:\n\n```yaml\naction: zha_toolkit.execute\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  command: zcl_cmd\n  cmd: 0\n  cluster: 6\n  endpoint: 11\n```\n\n### `zcl_cmd` Example: \"Store Scene\"\n\n```yaml\naction: zha_toolkit.execute\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  command: zcl_cmd\n  cmd: 4\n  cluster: 5\n  endpoint: 11\n  args: [2, 5]\n```\n\n### `zcl_cmd` Example: \"Recall Scene\"\n\n```yaml\naction: zha_toolkit.execute\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  command: zcl_cmd\n  cmd: 5\n  cluster: 5\n  endpoint: 11\n  args: [2, 5]\n```\n\nResults in (sniffed):\n\n```raw\nZigBee Cluster Library Frame\n    Frame Control Field: Cluster-specific (0x01)\n        .... ..01 = Frame Type: Cluster-specific (0x1)\n        .... .0.. = Manufacturer Specific: False\n        .... 0... = Direction: Client to Server\n        ...0 .... = Disable Default Response: False\n    Sequence Number: 94\n    Command: Recall Scene (0x05)\n    Payload\n        Group ID: 0x0002\n        Scene ID: 0x05\n```\n\n### `zcl_cmd` Example: \"Add Scene\"\n\nThis example shows that you can provide a list of bytes for an argument:\n\n```yaml\naction: zha_toolkit.execute\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  command: zcl_cmd\n  cmd: 0\n  cluster: 5\n  endpoint: 11\n  args:\n    - 2\n    - 5\n    - 2\n    - Final Example\n    # Two bytes of cluster Id (LSB first), length, attribute value bytes\n    #   repeat as needed (inside the list!)\n    - [0x06, 0x00, 1, 1]\n```\n\nsniffed as:\n\n```raw\nZigBee Cluster Library Frame\n    Frame Control Field: Cluster-specific (0x01)\n        .... ..01 = Frame Type: Cluster-specific (0x1)\n        .... .0.. = Manufacturer Specific: False\n        .... 0... = Direction: Client to Server\n        ...0 .... = Disable Default Response: False\n    Sequence Number: 76\n    Command: Add Scene (0x00)\n    Payload, String: Final Example\n        Group ID: 0x0002\n        Scene ID: 0x05\n        Transition Time: 2 seconds\n        Length: 13\n        String: Final Example\n        Extension Set: 06000101\n```\n\n### `zcl_cmd` Example: Pass keyword arguments\n\n`kwargs` allows passing arbitrary keyword arguments to the underlying ZHA\ncluster command handler. For instance, this enables sending an IR remote\ncode to the cluster command handler in the Tuya TS1201 quirk (see\nhttps://github.com/ferehcarb/zha-device-handlers/blob/fd90c398bd746df22a5cd55e53cd3134fbd7e009/zhaquirks/tuya/ts1201.py#L125).\n\n```yaml\naction: zha_toolkit.zcl_cmd\nmetadata: {}\ndata:\n  ieee: switch.ir_blaster_switch\n  cluster: 57348\n  cmd: 2\n  kwargs:\n    code: BXcjrhE/AuATAQF+BuAVA8AB4Acn4AMBQBvgBwFAE8ADB92ZdyPMCD8C\n```\n\n## Group related services\n\n### `add_group`\n\nAdd a group on the endpoint (or all endpoints).\n\n```yaml\naction: zha_toolkit.add_group\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  # Group Id\n  command_data: 0x0021\n  # Optional endpoint\n  endpoint: 1\n  event_done: zha_done\n```\n\n### `get_groups`\n\nGet the groups defined on the endpoint (or all endpoints)\n\n```yaml\naction: zha_toolkit.get_groups\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  # Optional endpoint\n  endpoint: 1\n  # Optional event\n  event_done: zha_done\n```\n\n### `remove_group`\n\nRemove a group defined on the endpoint (or all endpoints)\n\n```yaml\naction: zha_toolkit.remove_group\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  # Group Id\n  command_data: 0x0021\n  # Optional endpoint\n  endpoint: 1\n  # Optional event\n  event_done: zha_done\n```\n\n### `remove_all_groups`\n\n```yaml\naction: zha_toolkit.remove_all_groups\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  # Optional endpoint\n  endpoint: 1\n  # Optional event\n  event_done: zha_done\n```\n\n### `add_to_group`\n\nSimilar to `add_group` but uses another method internally.\n\n```yaml\naction: zha_toolkit.add_to_group\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  # Group Id\n  command_data: 0x0021\n  # Optional endpoint\n  endpoint: 1\n  # Optional event\n  event_done: zha_done\n```\n\n### `remove_from_group`\n\nSimilar to `remove_group` but uses another method internally.\n\n```yaml\naction: zha_toolkit.remove_from_group\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  # Group Id\n  command_data: 0x0021\n  # Optional endpoint\n  endpoint: 1\n  # Optional event\n  event_done: zha_done\n```\n\n### `get_zll_groups`\n\nGet groups on Zigbee Light Link cluster (uses `get group identifiers`)\n\n```yaml\naction: zha_toolkit.get_zll_groups\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  # Optional endpoint\n  endpoint: 1\n  # Optional event\n  event_done: zha_done\n```\n\n## EZSP/Bellows\n\n`ezsp` refers to `EmberZNet Serial Protocol` proposed by Silicon Labs.\n`bellows` refers to the library providing the interface between `zigpy` and\n`ezsp` compatible zigbee solutions.\n\nThis section lists the commands that are used specifically with the\n`bellows` library.\n\nThe following commands are not documented:\n\n- `ezsp_add_key`\n- `ezsp_clear_keys`\n- `ezsp_get_config_value`\n- `ezsp_get_ieee_by_nwk`\n- `ezsp_get_keys`\n- `ezsp_get_policy`\n- `ezsp_get_token`\n- `ezsp_get_value`\n- `ezsp_set_channel`\n- `ezsp_start_mfg`\n\n### `ezsp_backup`: Backup ezsp/bellows network data\n\n:warning: Under test\n\nUsed to transfer to another coordinator later, backup or simply get network\nkey and other info.\n\nThe output is written to\n`{custom_component_dir}/local/nwk_backup{command_data}.json`.\n\nYou can use the blueprint to setup daily backup:\n[![Open your Home Assistant instance and show the blueprint import dialog with the Daily backup blueprint pre-filled.](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fraw.githubusercontent.com%2Fmdeweerd%2Fzha-toolkit%2Fdev%2Fblueprints%2Fbackup.yaml).\n\nThe name of that backup is according to the format\n\n```yaml\naction: zha_toolkit.ezsp_backup\ndata:\n  # Optional command_data, string added to the basename.\n  # With this example the backup is written to `nwk_backup_20220105.json`\n  command_data: _20220105\n```\n\n## ZNP related (TI Zigbee Radio)\n\nZNP stands for \"Zigbee Network Processor\" and refers to the network layer\nproposed by TI's zigbee solutions. `zigpy-znp` refers to the plugin/library\nthat provides the layer that interfaces `zigpy` with the ZNP radio.\n\nThis section lists the services that specifically target ZNP processors.\n\n### `znp_nvram_backup`: Backup ZNP NVRAM data\n\nThe output is written to the customization directory as\n`local/nvram_backup.json` when `command_data` is empty or not provided.\nWhen `command_data` is provided, it is added just after nvram_backup.\n\nNote: currently under test.\n\n```yaml\naction: zha_toolkit.execute\ndata:\n  command: znp_nvram_backup\n  # Optional command_data, string added to the basename.\n  # With this example the backup is written to `nwk_backup_20220105.json`\n  command_data: _20220105\n```\n\n### `znp_nvram_restore`: Restore ZNP NVRAM data\n\nWill restore ZNP NVRAM data from `local/nvram_backup.json` where `local` is\na directory in the `zha_toolkit` directory.\n\nNote: currently under test.\n\nFor safety, a backup is made of the current network before restoring\n`local/nvram_backup.json`. The name of that backup is according to the\nformat `local/nvram_backup_YYmmDD_HHMMSS.json`.\n\n```yaml\naction: zha_toolkit.znp_nvram_restore\n```\n\n### `znp_nvram_reset`: Reset ZNP NVRAM data\n\nWill reset ZNP NVRAM data from `local/nvram_backup.json` where `local` is a\ndirectory in the `zha_toolkit` directory.\n\nNote: currently under test.\n\nFor safety, a backup is made of the current network before restoring\n`local/nvram_backup.json`. The name of that backup is according to the\nformat `local/nvram_backup_YYmmDD_HHMMSS.json`.\n\n```yaml\naction: zha_toolkit.znp_nvram_reset\n```\n\n### `znp_backup`: Backup ZNP network data\n\nUsed to transfer to another ZNP key later, backup or simply get network key\nand other info.\n\nThe output is written to the customization directory as\n`local/nwk_backup.json` when `command_data` is empty or not provided. When\n`command_data` is provided, it is added just after \"nwk_backup\".\n\nYou can use the blueprint to setup daily backup:\n[![Open your Home Assistant instance and show the blueprint import dialog with the ZNP Daily backup blueprint pre-filled.](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fraw.githubusercontent.com%2Fmdeweerd%2Fzha-toolkit%2Fdev%2Fblueprints%2Fbackup_znp.yaml).\n\nThe name of that backup is according to the format\n`nwk_backup{command_data}.json`.\n\n```yaml\naction: zha_toolkit.znp_backup\ndata:\n  # Optional command_data, string added to the basename.\n  # With this example the backup is written to `nwk_backup_20220105.json`\n  command_data: _20220105\n```\n\n### `znp_restore`: Restore ZNP network data\n\nWill restore network data from `local/nwk_backup.json` where `local` is a\ndirectory in the `zha_toolkit` directory.\n\nNote: currently under test.\n\nFor safety, a backup is made of the current network before restoring\n`local/nwk_backup.json`. The name of that backup is according to the format\n`local/nwk_backup_YYmmDD_HHMMSS.json`.\n\nA typical use for this is when you migrate from one key to another.\n\nThe procedure should be:\n\n1. Backup using the `znp_backup` command in the `zha_toolkit` service.\n   Verify that the `nwk_backup.json` file is generated in the `local`\n   directory.\n2. 1. Remove the original Coordinator from your system (e.g., remove the\n      USB key, ...).\n   2. Insert the new Coordinator.\n   3. *Only when migrating to a Coordinator with different port/serial\n      path/socket.*\\\n      Remove/Disable the ZHA Integration from Home Assistant.\\\n      The alternative is to modify HA’s config file directly to update the\n      current integration’s serial path and baudrate\n   4. Copy the zigbee.db file (for backup).\\\n      Moving/renaming it should not be needed. If you Move or Rename the\n      `zigbee.db` the Entity name are lost after the restore (which impacts\n      your automations, UI, etc).\n3. 1. Restart Home Assistant.\n   2. Enable/Add the ZHA Integration to Home Assistant (needed if you\n      disabled or removed the ZHA integration in step 2.iii.)\n4. Restore using the `znp_restore` command.\\\n   (If you used a custom file name for the backup then make sure you copy\n   it to `nwk_backup.json`).\n5. Check the logs (currently the `pre_shutdown` call failed for the first\n   successful test, but that is not critical).\n6. Restart HA\n7. Check that everything is ok.\n\n**NOTES :**\n\n- Devices may take a while to rejoin the network as the Zigbee\n  specification requires them to \"back-off\" in case of communication\n  problems.\n- You may speed up the process by power cycling devices.\n- Devices may not be instantly responsive because the zigbee mesh needs to\n  be recreated (try the `zdo_scan_now` command to speed that up).\n\n(See the\n[Home Assistant Community Forum](https://community.home-assistant.io/t/zha-custom-service-to-send-custom-zha-commands-extra-functions/373346/33)\nfor a success story.)\n\n```yaml\naction: zha_toolkit.execute\ndata:\n  command: znp_restore\n  # Optional:\n  #  command_data = Counter_increment (for tx).\n  #                 defaults to 2500\n  command_data: 2500\n```\n\n## Miscellaneous\n\n### `backup`: Backup the coordinator\n\nThe backup service starts a backup of the coordinator by calling upon\n`znp_backup` or `ezsp_backup`.\n\nIt provides a radio independent service for backups.\n\n```yaml\naction: zha_toolkit.backup\ndata:\n  # Optional command_data, string added to the basename.\n  # With this example the backup is written to `nwk_backup_20220105.json`\n  command_data: _20220105\n```\n\n### `misc_settime`: Set attributes of a Time Cluster\n\nSets the time and DST configuration for a Time Cluster from HA's current\ntime and default timezone.\n\nThe TimeStatus attribute is not set. You likely need to set it to 2\n(synchronized).\n\nBefore and after writing, the attributes are read from the cluster and\navailable in the event data, unless options disable these reads.\n\n```yaml\naction: zha_toolkit.misc_settime\ndata:\n  ieee: 5c:02:72:ff:fe:92:c2:5d\n  # The endpoint is optional - by default the endpoint containing the Time Cluster\n  endpoint: 11\n  # You can set the next events to use as a trigger.\n  # The event data has the result of the command (currently attr_read, attr_write)\n  event_success: my_read_success_trigger_event\n  event_fail: my_read_fail_trigger_event\n  event_done: my_read_done_trigger_event\n  # Settings for attr_write\n  # Read attribute before writing it (defaults to True)\n  read_before_write: true\n  # Read attribute after writing it (defaults to True)\n  read_after_write: true\n```\n\n### `ota_notify` - Download/Trigger Device FW update\n\n`ota_notify` helps you update the firmware of a zigbee device without\nrestarting Home Assistant. It can use the already available firmware\nimages, or download them using\n[Koenkk/zigbee-OTA](https://github.com/Koenkk/zigbee-OTA)'s list and\nresources. It also notifies the device that it should issue a request to be\nupdated. That launches the update process.\n\n`OTA` is the acronym for \"Over the Air\" and we implicitly add \"update\" or\n\"upgrade\".\n\nYou must have configured the\n[otau_directory](https://github.com/zigpy/zigpy/wiki/OTA-Device-Firmware-Updates).\nThis is where ZHA/zigpy looks for firmware images, and where downloaded\nfirmware images will be placed.\n\n`ota_notify` will indicate to the device that an update is available, which\nwill trigger the device to request this update from the coordinator (in\nthis case zigpy).\n\nPrior to notifying the device, `ota_notify` will request all image\nproviders to update the list of available images. By default, this is only\ndone on startup, so when you add a new image to your local directory or\nwhen a new update is available from a third party, you'd have to restart\nHA. But with `ota_notify` no restart is required.\n\nFor details on how to setup your images sources, check the\n[zigpy wiki section](https://github.com/zigpy/zigpy/wiki/OTA-Device-Firmware-Updates#enabling-ota-updates).\nAlso read about the possibilities to enable logging, and that some devices\nrequire to be re-associated.\n\nTo trigger the OTA update, use `ota_notify` instead. The debug log is\nuseful to check the update progress or indication that no update is\navailable.\\\nWhen the update starts, be patient: it can take a while.\n\n```yaml\naction: zha_toolkit.ota_notify\ndata:\n  # Reference of the device that should be notified about an update.\n  # Using one of the entity/sensor names is so much easier !\n  ieee: sensor.lixee_zlinky_tic_00000000_electrical_measurement\n  # Optional, when true download images from info at https://github.com/Koenkk/zigbee-OTA\n  download: true\n  # Optional, directory to write OTA files to (default: same as ZHA configuration)\n  path: /config/zb_ota\n```\n\n### `zha_devices`: Device Information to Event or CSV or Script variable\n\nGet Device information as event data or in a CSV file.\n\nYou can select the data fields in the CSV and the event data through the\ncommand_data parameter. If you do not provide a list, a default list is\nused for the CSV file, and all available data is provided in the devices\nfield of the event data.\n\nYou also get this data in the 'devices' field of the generated events which\nallows you to get information about endpoints and services as well.\n\n```yaml\naction: zha_toolkit.zha_devices\ndata:\n  # Optional: Device to report on, by default all devices are in the report\n  ieee: sensor.my_zha_sensor\n  # Optional list of fields to write to the CSV, all non-list fields by default.\n  command_data: [name, ieee, rssi, lqi]\n  # Optional, field the list is sorted by (example: sort by signal strength)\n  csvlabel: rssi\n  csvout: ../www/devices.csv\n  # Optional: JSON file to write devices data to - located in /config/json/...\n  json_out: zha_devices.json\n  # Optional: Add timestamp to Filename of JSON file. Defaults to False.\n  json_timestamp: true\n  event_done: zha_devices\n```\n\nThe above should write the CSV to the www directory, so it's available as\n'INSTANCEURL/local/devices.csv' and you could add a button to your UI for\ndownloading:\n\n```yaml\ntype: button\nname: Devices CSV File\ntap_action:\n  action: url\n  url_path: /local/devices.csv\n```\n\nSee [script_use_zha_devices.yaml](examples/script_use_zha_devices.yaml) to\nsee how you can loop over the device list provided in the event data.\n\nSee\n[script_use_zha_devices_response.yaml](examples/script_use_zha_devices_response.yaml)\nshows how a new method available since Home Assistant 2023.7 that allows us\nto avoid the complexity of event_data by using the response from the\nzha-toolkit service.\n\n### `register_services`: Reregister ZHA-Toolkit services\n\nThe services may have evolved after an update of the code and calling\n`register_services` will reload the `services.yaml` file defining the\noptions available in the UI interface, as well as internal structures that\ndefine the validation rules for the parameters.\n\nMost of the time this operation will be done automatically (when upgrading\nthrough HACS), but during development no version or file changes may be\ndetected, and a manual update may be due for testing or accessing updated\ninterfaces.\n\n```yaml\naction: zha_toolkit.register_services\n```\n\n### `ha_set_state` - Update HA state\n\nSet/update any Home Assistant state.\n\n```yaml\naction: zha_toolkit.ha_set_state\ndata:\n  fail_exception: true\n  state_id: sensor.mysensor\n  attr_val: 10\n  # optional Parameters\n  state_attr: some_attribute\n  allow_create: true\n  # When defined, the read attribute is converted using this template string\n  # before writing it to the state.\n  # Note that no curly braces should be used here!\n  state_value_template: value + 2\n  csvout: set_state.csv\n  csvlabel: Example reason\n```\n\n`state_value_template` is a template(-like) expression that is interpreted\nwhere `attr_val` is available as `value` and `attr_value`. This a template\nexpression without the curly parentheses (`{{ }}`). If the curly\nparentheses are used, the expression would be expanded before the zha\nservice code is entered which is incompatible with this functionality.\n\nThis is not strictly a `zha` specific tool, but useful in some scripting\nsituations.\n\n### `misc_energy_scan`: Perform an energy scan\n\nScan Zigbee channels for congestion level. The value is a percentage from\nzero to 100. A lower value is less congested.\n\n```yaml\naction: zha_toolkit.misc_energy_scan\ndata:\n  # Optional: CSV file to write attribute to - located in /config/csv/...\n  csvout: energy_scan.csv\n```\n\nThe values can vary quite a bit between scans. You can create helpers to\nstore results which will allow you to see trends via the History tab. This\nautomation runs each hour:\n\n```\n  - id: zigbee_energy_scan\n    alias: Zigbee Energy Scan\n    mode: single\n    triggers:\n      - trigger: time_pattern\n      # Matches every hour at 17 minutes past the hour\n        minutes: 17\n    actions:\n      - action: zha_toolkit.execute\n        data:\n          command: misc_energy_scan\n        response_variable: scan\n      - repeat:\n          for_each: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]\n          sequence:\n            - action: input_number.set_value\n              target:\n                entity_id: \"input_number.zigbee_energy_channel_{{ repeat.item }}\"\n              data:\n                value: \"{{ scan['energy_scan'][repeat.item] | round }}\"\n```\n\nCreating 16 input_number helpers can be tedious. ZHA recommends only\nchannels 15, 20, and 25 be used. Alternatively you can create just three\nhelpers and reduce the for_each list to only those three channels.\n\n## User method\n\nYou can add your own Python commands in `local/user.py`. Your file is\nreloaded on each call and will survive updates because it's inside the\n`local` directory.\n\nExample of `user_test` that has the expected method signature, but just\nprints that it's executed:\n\n```python\nimport logging\n\nLOGGER = logging.getLogger(__name__)\n\n\nasync def user_test(app, listener, ieee, cmd, data, service, params, event_data):\n    LOGGER.debug(f\"User test called\")\n```\n\nThe service call to execute it looks like this:\n\n```yaml\naction: zha_toolkit.execute\ndata:\n  command: user_test\n```\n\nYou're free to reuse the parameters already available for the other\ncommands. If you add your own, you'll need to parse them yourself from\n`service.data`. You can check out `utils.py/extractParams` to look for\nideas, and you can examine the other methods to see how you can use ZHA.\n\nThis is a powerful tool to develop your own custom tool, and propose it for\ninclusion in the `zha-toolkit` when it's ready and of potential use to\nothers.\n\n## Manufacturers\n\n### Tuya\n\nShame on Tuya to be a\n[member of the Zigbee Alliance](https://zigbeealliance.org/member/tuya-global-inc/)\nand deviate from the Zigbee Specifications.\n\nThese commands help fix some of that.\n\n#### `tuya_magic` - Tuya Magic spell\n\nThis was labelled the\n[standard tuya \"magic spell\"](https://github.com/Koenkk/zigbee2mqtt/issues/9564#issuecomment-1051123722)\nas it makes most Tuya devices work normally.\n\ncurrently only the \"read\" part is implemented - if needed a\nsuper_magic_spell can be added to also execute the write procedure.\n\nIt has to be done using the \"execute\" command it's not implemented as a\nsearchable service.\n\n```yaml\naction: zha_toolkit.execute\ndata:\n  command: tuya_magic\n  ieee: light.tz3000_dbou1ap4_ts0505a_level_light_color_on_off\n```\n\n# Credits/Motivation\n\nThis project was forked from\n[Adminiguaga/zha_custom](https://github.com/Adminiuga/zha_custom) where the\n\"hard tricks\" for providing services and accessing ZHA functions were\nimplemented/demonstrated. The original codeowners were\n\"[dmulcahey](https://github.com/dmulcahey)\" and\n\"[Adminiuga](https://github.com/adminiuga)\".\n\nThe znp and ezsp backup core code is work originally created by @puddly\neither available in the official `zigpy/zigpy_znp` repository or the\n`pudly/bellows` fork.\n\nThe initial purpose of this fork was mainly to add custom attribute writes,\ncustom reporting and more binding possibilities.\n\nThe structure was then updated to be compliant with HACS integration so\nthat the component can be easily added to a Home Assistant setup.\n\n# License\n\nI set the License the same as Home Assistant that has the ZHA component.\nThe original `zha_custom` repository does not mention a license.\n\n# Contributing\n\n#See [Contributing.md](Contributing.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmdeweerd%2Fzha-toolkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmdeweerd%2Fzha-toolkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmdeweerd%2Fzha-toolkit/lists"}