zha-device-handlers: the quirk layer between ZHA and odd Zigbee devices
ZHA quirks bridge the functionality gap created when manufacturers deviate from the ZCL specification, handling deviations and exceptions by parsing custom messages to and from Zigbee devices.
At a glance
- What is it?
- zha-device-handlers is the zha-quirks library that lets Home Assistant's ZHA component talk to Zigbee devices whose manufacturers did not follow the ZCL specification. The quirks parse custom messages to and from devices, and the project now points new contributors at its v2 guidance rather than the v1 documentation.
- Who is it for?
- Adopt zha-device-handlers if you run Home Assistant with ZHA and have a device whose features are broken because its manufacturer ignored the ZCL specification, since a quirk is the supported way to recover the missing behaviour.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why a quirk layer has to exist at all
Zigbee devices are supposed to behave the same way, which is what makes the ecosystem work. The Zigbee Cluster Library specification defines how clusters and attributes are structured, and the host application, in this case Zigpy, relies on that to talk to any device without per model code. Manufacturers cut corners. A device sends an attribute in an unexpected place, adds a private cluster, or reports state in a form the standard does not describe, and the generic handling breaks or exposes only part of the features. ZHA device handlers close that gap. They are custom quirks implementations for Zigpy that parse the custom messages to and from a device and expose the functionality the standard path misses, so a device whose manufacturer deviated from the specification still works properly inside Home Assistant.
Endpoints and clusters are where the gaps appear
The primer in the README explains the model, because a quirk is really a patch against this structure. A device is described by descriptors, and the device itself contains endpoints, and each endpoint contains clusters. There are two kinds. in_clusters are the Server clusters in ZCL terms, the ones that control the device, so a smart plug or light bulb has an on_off server cluster, and these are the clusters that send attribute reports and that you can read an attribute from. out_clusters are Client clusters, the ones that control some other device, as an on_off remote has an on_off client cluster that generates cluster commands and sends them to a server elsewhere. A quirk is usually about one of two things: a cluster that is not where the standard says it is, or a message payload whose contents do not match the documented schema. The upstream specifications referenced include the Zigbee Cluster Library, the Zigbee Protocol Specification, the device behaviour specifications, Green Power and Smart Energy profiles.
The README documents v1 quirks while v2 is the direction
There is a documentation split worth knowing before you contribute. A note at the top of the README says the document primarily covers v1 quirks and will be updated, and that for v2 quirks documentation, which is recommended for new quirks, the project points to copilot-instructions.md in the .github directory. So the README is not the full contract for new work, and a contributor following only it may build a v1 style quirk when the project would prefer the v2 shape. The repository also carries AGENTS.md and CLAUDE.md at the top level, alongside a pre-commit configuration, an editor configuration and a script directory. The tooling is strict by the look of the configuration: pylint with a 120 character line limit and two disabled checks, mypy pinned to 2.1.0 with a long list of strict flags, and ruff pinned to 0.15.17, with the mypy version noted to be kept in sync with the pre-commit configuration.
Tuya gets a builder instead of hand written clusters
Tuya is large enough in the market to deserve its own path. The README points contributors who are supporting Tuya devices to the TuyaQuirkBuilder, documented in tuya.md, and separately links the Tuya Zigbee Connection Standard and the Zigbee2MQTT guide to understanding the custom manuSpecificTuya cluster that Tuya devices use. The builder is the interesting part, because Tuya devices share a private cluster convention, so the work is describing the vendor schema once rather than writing a bespoke quirk per model. That is the general shape of what a good quirk looks like here. A handler that decodes one manufacturer protocol can cover a whole family of devices, while a handler written for one model is a maintenance liability every time the firmware changes.
The same idea in two other ecosystems
The README compares ZHA device handlers to Hub-connected Device Handlers for the SmartThings Classics platform and to Zigbee-Herdsman Converters, formerly Zigbee-Shepherd Converters, as used by Zigbee2mqtt. The comparison is about the concept: in each case a virtual representation of a physical device exposes functionality that the existing integration does not provide out of the box. The difference in approach is where the code sits. A Zigbee2mqtt converter is a JavaScript module in the Zigbee2mqtt project that is loaded by the bridge at runtime, while a ZHA device handler is a Python class in this repository that is installed into Home Assistant as the zha-quirks package, so it is versioned with Home Assistant rather than with a separate bridge. That difference decides which ecosystem you end up in, and for a Home Assistant user it is not a close call.
The package is zha-quirks and needs Python 3.12
The distribution name differs from the repository name, which trips people up when they look for it on PyPI. The project metadata says:
name = "zha-quirks"
requires-python = ">=3.12"
dependencies = ["zigpy>=2.3.0", "zha>=2.3.0"]So the library is published as zha-quirks, it requires Python 3.12 or newer, and it pins nothing below zigpy 2.3.0 and zha 2.3.0, which are the components that provide the Zigbee support and the Home Assistant integration it extends. The version number is dynamic rather than written in the file, because the build uses setuptools-git-versioning, so the version comes from the git tag. The README does not give an install command, since the package is consumed as part of the Home Assistant ZHA component rather than installed by hand, and the tests live in tests/ alongside the zhaquirks/ package that holds the quirks themselves.
Release cadence and the Apache-2.0 licence
The project moves steadily. The recent releases are 2.2.1 on 2026-08-26, 2.2.2 on 2026-09-08 and 2.3.0 on 2026-09-29, and the last push to the dev branch, which is the default branch, was on 2026-10-14. The version scheme follows the zigpy and zha packages it depends on, so an upgrade of the underlying library usually means an upgrade here too, and the minimum versions of zigpy>=2.3.0 and zha>=2.3.0 in the metadata are the floor you should check against your own installation. The licence field on the repository says Apache-2.0, matching the licence text in pyproject.toml, and the LICENSE.md file sits at the top level. For a Home Assistant user the practical upgrade step is updating Home Assistant itself, since the quirks ship with it rather than as a separate install.
Editorial conclusion
Adopt zha-device-handlers if you run Home Assistant with ZHA and have a device whose features are broken because its manufacturer ignored the ZCL specification, since a quirk is the supported way to recover the missing behaviour. Do not expect it to fix a device whose problem lives in firmware and never appears in a message, and do not copy the v1 patterns from the README for new work, because the project recommends the v2 guidance in .github/copilot-instructions.md for new quirks. Verify first that your Home Assistant installation already carries zigpy and zha at version 2.3.0 or newer, since that is the declared floor, and check whether the Tuya builder in tuya.md already covers your device before writing a quirk from scratch.
Frequently asked questions
What are ZHA device handlers and who uses them?
They are custom quirks implementations for Zigpy that let ZHA in Home Assistant work with Zigbee devices whose manufacturers deviated from the ZCL specification. They parse custom messages to and from devices and expose functionality the generic integration does not provide.
How do I install zha-device-handlers?
The project is published as zha-quirks and requires Python 3.12 or later, depending on zigpy>=2.3.0 and zha>=2.3.0. The README does not document an install command, since the library is consumed as part of the Home Assistant ZHA component rather than installed separately.
What is the difference between in_clusters and out_clusters?
in_clusters are the Server clusters that control the device, such as the on_off server cluster of a plug or bulb, and they send attribute reports. out_clusters are Client clusters that control other devices, such as an on_off client cluster on a remote that sends commands to a server elsewhere.
How do I support a Tuya device with a ZHA quirk?
The project points contributors to the TuyaQuirkBuilder, documented in tuya.md, and links the Tuya Zigbee Connection Standard and the Zigbee2MQTT guide to the custom manuSpecificTuya cluster. Using the builder means describing the vendor schema once instead of writing a bespoke quirk per model.
Should I write a v1 or a v2 quirk?
New quirks should be v2. The README states that it primarily documents v1 quirks and points to copilot-instructions.md in the .github directory for v2 quirks documentation, which it calls the recommended path for new work.
Official sources
Was this useful?