Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
70f9526
Remove zigpy dependency for Home Assistant units and constants
puddly May 9, 2026
3ca1c01
WIP: Compare units against Home Assistant
puddly May 9, 2026
219255f
Drop strict quirks requirement
puddly May 9, 2026
9ade966
Regenerate diagnostics after unit change
puddly May 27, 2026
8c995a7
Move most entity discovery out of discovery
puddly May 9, 2026
f96f25b
Allow for whole-device registration
puddly May 27, 2026
8c826f3
WIP: register quirks device subclasses with zigpy
puddly May 11, 2026
b9b1a37
WIP
puddly Jun 9, 2026
5f4ea4b
WIP
puddly Jun 9, 2026
bc57fc6
Migrate quirk logic to zha-device-handlers?
puddly Jun 18, 2026
a2771a7
Get device tests passing
puddly Jun 18, 2026
79c66e3
Rename `CustomDeviceV2` to `CustomZigpyDevice`
puddly Jun 18, 2026
af74f23
Forward `uninitialized_packet_handler`
puddly Jun 18, 2026
4feb202
Get ZHA tests passing
puddly Jun 18, 2026
810340e
Provide hooks for quirks to implement entity filtering/metadata changes
puddly Jun 19, 2026
817de69
Register legacy v1 quirks using the same system
puddly Jun 19, 2026
5e57140
Fix quirk regeneration
puddly Jun 19, 2026
a2772d2
Use a different format for quirk labels
puddly Jun 19, 2026
7c5a6c4
Fix `zigpy.quirks` -> `zhaquirks`
puddly Jun 19, 2026
d39c1a8
Migrate quirk IDs into ZHA
puddly Jun 19, 2026
ede82a1
Allow iteration over the device registry
puddly Jun 19, 2026
7e1b997
Typing
puddly Jun 19, 2026
53db551
Clean up registry usage in tests
puddly Jun 22, 2026
06914ba
Properly rebuild devices on reconfigure
puddly Jun 22, 2026
dcde908
Regenerate diagnostics
puddly Jun 22, 2026
0d42663
Merge branch 'dev' into puddly/decouple-zigpy
puddly Jun 22, 2026
c2459c4
Ensure quirk registry entries are fully hashable
puddly Jun 23, 2026
e180fa8
Log when quirks fail to transform a device
puddly Jun 23, 2026
17a3d63
Bump zigpy and quirks
puddly Jun 23, 2026
1421911
Move `targets_cluster` out of quirks and into ZHA
puddly Jun 23, 2026
342c640
Drop zhaquirks as a runtime dependency
puddly Jun 23, 2026
6b5de03
Add a test for entity reinterviewing events
puddly Jun 23, 2026
f17cb12
Fix reinterviewing logic per review
puddly Jun 23, 2026
a5ab718
Add an explicit test case for `DeviceFullInitEvent` on quirk swap out
puddly Jun 24, 2026
38ec9ae
Drop local zigpy override
puddly Jun 24, 2026
af78810
Temporarily fix `uv.lock` for CI
puddly Jun 24, 2026
9b262af
Fix pre-commit
puddly Jun 24, 2026
e284888
Regenerate mypy ignores
puddly Jun 24, 2026
9d3f641
Fix typing on 3.12
puddly Jun 24, 2026
4b53b53
Clean up circular export surfaced by xdist
puddly Jun 24, 2026
a310225
Regenerate diagnostics for broken Ubisys device
puddly Jun 24, 2026
36e9d31
Drop bad ubisys diagnostics
puddly Jun 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
184 changes: 91 additions & 93 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ readme = "README.md"
license = {text = "Apache-2.0"}
requires-python = ">=3.12"
dependencies = [
"zigpy==1.6.0",
"attrs",
"frozendict",
"bellows==0.49.2",
"zigpy-znp==1.1.0",
"zigpy-deconz==0.25.5",
"zigpy-xbee==0.21.1",
"zigpy-zigate==0.14.0",
"zha-quirks==1.2.0",
"zigpy==2.0.0",
]

[tool.setuptools.packages.find]
Expand All @@ -30,7 +31,8 @@ exclude = ["tests", "tests.*"]
testing = [
"pytest",
"coloredlogs",
"python-slugify"
"python-slugify",
"homeassistant",
]

[dependency-groups]
Expand All @@ -51,6 +53,7 @@ testing = [
"python-slugify",
"ruff==0.15.16",
"uv>=0.11.16",
"zha-quirks>=2.0.0",
]
ci = [
{include-group = "testing"},
Expand All @@ -61,6 +64,16 @@ ci = [
[tool.uv]
default-groups = ["testing"]

# `zha` and `zha-quirks` mutually pin `>=2.0.0`, but neither is tagged 2.0.0 yet. Drop
# those bounds for the dev lock so resolution succeeds. Will be fixed in 2.0.1.
[[tool.uv.dependency-metadata]]
name = "zha-quirks"
version = "2.0.0"
requires-dist = ["zigpy>=2.0.0", "zha"]

[tool.uv.sources]
zha-quirks = { git = "https://github.com/puddly/zha-device-handlers", rev = "7ac5b603cec5ae12fd24a7f40522aeb607aa4b1a" }

[tool.setuptools-git-versioning]
enabled = true

Expand Down Expand Up @@ -96,209 +109,193 @@ non_interactive = true
# first; clean up a module's errors and re-run the tool to shrink the list.
# Autogenerated mypy overrides: start
[[tool.mypy.overrides]]
module = "zha.application.discovery"
module = "zha.application.platforms.button"
disable_error_code = [
"no-any-return", # 3
"assignment", # 1
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.update"
disable_error_code = [
"arg-type", # 3
"arg-type", # 1
]

[[tool.mypy.overrides]]
module = "zha.async_"
module = "zha.application.platforms.virtual"
disable_error_code = [
"arg-type", # 2
"no-untyped-def", # 1
"no-any-return", # 1
]

[[tool.mypy.overrides]]
module = "zha.zigbee.cluster_config"
module = "zha.quirks"
disable_error_code = [
"arg-type", # 2
"no-untyped-call", # 1
"no-any-return", # 1
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.lock"
module = "zha.application.platforms.number"
disable_error_code = [
"arg-type", # 3
"no-untyped-def", # 1
"no-any-return", # 2
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.siren"
disable_error_code = [
"arg-type", # 2
"assignment", # 2
]

[[tool.mypy.overrides]]
module = "zha.event"
module = "zha.application.discovery"
disable_error_code = [
"no-untyped-def", # 4
"no-any-return", # 3
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.device_tracker"
module = "zha.application.platforms.binary_sensor"
disable_error_code = [
"no-any-return", # 1
"no-untyped-call", # 1
"no-untyped-def", # 1
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.lock"
disable_error_code = [
"arg-type", # 2
"no-untyped-def", # 3
"no-untyped-def", # 1
]

[[tool.mypy.overrides]]
module = "zha.zigbee.group"
module = "zha.async_"
disable_error_code = [
"no-untyped-def", # 3
"return-value", # 2
"arg-type", # 2
"no-untyped-def", # 1
]

[[tool.mypy.overrides]]
module = "zha.zigbee.cluster_config"
disable_error_code = [
"arg-type", # 2
"no-untyped-call", # 1
]

[[tool.mypy.overrides]]
module = "zha.application.platforms"
disable_error_code = [
"arg-type", # 1
"assignment", # 1
"attr-defined", # 2
"no-any-return", # 2
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.button"
module = "zha.application.platforms.device_tracker"
disable_error_code = [
"arg-type", # 5
"assignment", # 2
"override", # 2
"arg-type", # 1
"no-untyped-def", # 3
]

[[tool.mypy.overrides]]
module = "zha.application.gateway"
module = "zha.application.platforms.switch"
disable_error_code = [
"arg-type", # 3
"assignment", # 2
"no-untyped-call", # 4
"return-value", # 1
"arg-type", # 1
"no-any-return", # 1
"no-untyped-call", # 2
]

[[tool.mypy.overrides]]
module = "zha.event"
disable_error_code = [
"no-untyped-def", # 4
]

[[tool.mypy.overrides]]
module = "zha.zigbee.group"
disable_error_code = [
"no-untyped-def", # 3
"return-value", # 2
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.fan"
disable_error_code = [
"arg-type", # 5
"arg-type", # 2
"index", # 1
"no-any-return", # 3
"no-untyped-def", # 1
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.alarm_control_panel"
module = "zha.application.gateway"
disable_error_code = [
"arg-type", # 1
"no-untyped-call", # 1
"no-untyped-def", # 11
"arg-type", # 3
"assignment", # 2
"no-untyped-call", # 4
"return-value", # 1
]

[[tool.mypy.overrides]]
module = "zha.application.helpers"
module = "zha.application.platforms.alarm_control_panel"
disable_error_code = [
"arg-type", # 2
"no-untyped-call", # 4
"no-untyped-def", # 10
"no-untyped-call", # 1
"no-untyped-def", # 11
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.cover"
disable_error_code = [
"arg-type", # 3
"no-any-return", # 3
"no-untyped-call", # 6
"no-untyped-def", # 5
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.binary_sensor"
module = "zha.application.helpers"
disable_error_code = [
"arg-type", # 22
"no-any-return", # 1
"no-untyped-call", # 1
"no-untyped-def", # 1
"override", # 1
"arg-type", # 2
"no-untyped-call", # 4
"no-untyped-def", # 10
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.light"
disable_error_code = [
"arg-type", # 9
"arg-type", # 5
"no-any-return", # 4
"no-untyped-call", # 11
"no-untyped-def", # 8
"type-var", # 2
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.select"
disable_error_code = [
"arg-type", # 33
"override", # 1
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.virtual"
disable_error_code = [
"arg-type", # 40
"no-any-return", # 1
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.climate"
disable_error_code = [
"arg-type", # 9
"call-overload", # 4
"no-any-return", # 23
"no-untyped-def", # 8
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.switch"
module = "zha.application.platforms.sensor"
disable_error_code = [
"arg-type", # 41
"no-any-return", # 1
"no-untyped-call", # 2
"override", # 1
"arg-type", # 10
"assignment", # 3
"attr-defined", # 5
"no-any-return", # 9
"no-untyped-call", # 4
"no-untyped-def", # 3
"operator", # 4
]

[[tool.mypy.overrides]]
module = "zha.zigbee.device"
disable_error_code = [
"arg-type", # 12
"assignment", # 2
"no-any-return", # 4
"no-untyped-call", # 4
"no-untyped-call", # 3
"no-untyped-def", # 10
"return-value", # 1
"union-attr", # 18
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.number"
disable_error_code = [
"arg-type", # 56
"no-any-return", # 2
"override", # 1
]

[[tool.mypy.overrides]]
module = "zha.application.platforms.sensor"
disable_error_code = [
"arg-type", # 88
"assignment", # 1
"attr-defined", # 5
"no-any-return", # 9
"no-untyped-call", # 4
"no-untyped-def", # 3
"operator", # 4
"override", # 3
]
# Autogenerated mypy overrides: end

[[tool.mypy.overrides]]
Expand Down Expand Up @@ -461,6 +458,7 @@ split-on-trailing-comma = false

# Allow for main entry & scripts to write to stdout
"script/*" = ["T20"]
"tools/*" = ["T20"]

[tool.ruff.lint.mccabe]
max-complexity = 25
Expand Down
8 changes: 5 additions & 3 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

from zigpy.application import ControllerApplication
from zigpy.const import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_PROFILE, SIG_EP_TYPE
from zigpy.quirks import get_device as quirks_get_device
import zigpy.types as t
import zigpy.zcl
import zigpy.zcl.foundation as zcl_f
Expand All @@ -22,6 +21,7 @@
from zha.application import Platform
from zha.application.gateway import Gateway
from zha.application.platforms import BaseEntity, GroupEntity, PlatformEntity
from zha.quirks import DEVICE_REGISTRY, DeviceRegistry
from zha.zigbee.device import Device
from zha.zigbee.group import Group

Expand Down Expand Up @@ -363,6 +363,7 @@ def zigpy_device_from_device_data(
device_data: dict,
patch_cluster: bool = True,
quirk: Callable | None = None,
registry: DeviceRegistry = DEVICE_REGISTRY,
) -> zigpy.device.Device:
"""Make a fake device using the specified cluster classes."""

Expand Down Expand Up @@ -423,7 +424,7 @@ def zigpy_device_from_device_data(
if quirk:
device = quirk(app, device.ieee, device.nwk, device)
else:
device = quirks_get_device(device)
device = registry.resolve(device)

for epid, ep in device_data["endpoints"].items():
try:
Expand Down Expand Up @@ -557,6 +558,7 @@ def create_mock_zigpy_device(
patch_cluster: bool = True,
quirk: Callable | None = None,
attributes: dict[int, dict[str, dict[str, Any]]] = None,
registry: DeviceRegistry = DEVICE_REGISTRY,
) -> zigpy.device.Device:
"""Make a fake device using the specified cluster classes."""
zigpy_app_controller = zha_gateway.application_controller
Expand Down Expand Up @@ -601,7 +603,7 @@ def create_mock_zigpy_device(
if quirk:
device = quirk(zigpy_app_controller, device.ieee, device.nwk, device)
else:
device = quirks_get_device(device)
device = registry.resolve(device)

if patch_cluster:
for endpoint in (ep for epid, ep in device.endpoints.items() if epid):
Expand Down
Loading
Loading