Skip to content

Commit 779e48e

Browse files
authored
Merge branch 'dev' into add-thermostat-_TZE200_viy9ihs7
2 parents 3d0c1f6 + 4f64c18 commit 779e48e

20 files changed

+250
-104
lines changed

.github/workflows/stale.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Stale
33
# yamllint disable-line rule:truthy
44
on:
55
schedule:
6-
- cron: "0 * * * *"
6+
- cron: "30 1 * * *"
77
workflow_dispatch:
88

99
jobs:
@@ -16,7 +16,7 @@ jobs:
1616
# - No PRs marked as no-stale
1717
# - No issues marked as no-stale or help-wanted
1818
- name: 180 days stale issues & PRs policy
19-
uses: actions/stale@v8
19+
uses: actions/stale@v9
2020
with:
2121
repo-token: ${{ secrets.GITHUB_TOKEN }}
2222
days-before-stale: 180
@@ -49,7 +49,7 @@ jobs:
4949
# - No Issues marked as no-stale or help-wanted
5050
# - No PRs (-1)
5151
- name: Needs more information stale issues policy
52-
uses: actions/stale@v8
52+
uses: actions/stale@v9
5353
with:
5454
repo-token: ${{ secrets.GITHUB_TOKEN }}
5555
only-labels: "needs more information"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ZHA Device Handlers For Home Assistant
22

3-
![CI](https://github.com/zigpy/zha-device-handlers/workflows/CI/badge.svg?branch=dev)
3+
[![CI](https://github.com/zigpy/zha-device-handlers/actions/workflows/ci.yml/badge.svg)](https://github.com/zigpy/zha-device-handlers/actions/workflows/ci.yml)
44
[![Coverage Status](https://codecov.io/gh/zigpy/zha-device-handlers/branch/dev/graph/badge.svg)](https://app.codecov.io/gh/zigpy/zha-device-handlers/tree/dev)
55

66
ZHA Device Handlers are custom quirks implementations for [Zigpy](https://github.com/zigpy/zigpy), the library that provides the [Zigbee](http://www.zigbee.org) support for the [ZHA](https://www.home-assistant.io/components/zha/) component in [Home Assistant](https://www.home-assistant.io).

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ readme = "README.md"
1414
license = {text = "Apache-2.0"}
1515
requires-python = ">=3.12"
1616
dependencies = [
17-
"zigpy>=0.74.0",
17+
"zigpy>=0.75.0",
1818
]
1919

2020
[tool.setuptools.packages.find]

requirements_test.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ pytest-sugar
1313
pytest-timeout
1414
pytest-asyncio
1515
pytest>=7.1.3
16-
zigpy>=0.74.0
16+
zigpy>=0.75.0
1717
ruff==0.0.261

tests/test_inovelli_blue.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from unittest import mock
44
from unittest.mock import MagicMock
55

6+
import zigpy.types as t
7+
68
import zhaquirks
79
from zhaquirks.inovelli.VZM31SN import InovelliVZM31SNv11
810

@@ -25,7 +27,15 @@ class Listener:
2527
cluster_listener
2628
)
2729

28-
device.handle_message(260, cluster_id, endpoint_id, endpoint_id, data)
30+
device.packet_received(
31+
t.ZigbeePacket(
32+
profile_id=260,
33+
cluster_id=cluster_id,
34+
src_ep=endpoint_id,
35+
dst_ep=endpoint_id,
36+
data=t.SerializableBytes(data),
37+
)
38+
)
2939

3040
assert cluster_listener.zha_send_event.call_count == 1
3141
assert cluster_listener.zha_send_event.call_args == mock.call(
@@ -35,8 +45,14 @@ class Listener:
3545
cluster_listener.zha_send_event.reset_mock()
3646

3747
led_effect_complete_data = b"\x15/\x12\x0c$\x10"
38-
device.handle_message(
39-
260, cluster_id, endpoint_id, endpoint_id, led_effect_complete_data
48+
device.packet_received(
49+
t.ZigbeePacket(
50+
profile_id=260,
51+
cluster_id=cluster_id,
52+
src_ep=endpoint_id,
53+
dst_ep=endpoint_id,
54+
data=t.SerializableBytes(led_effect_complete_data),
55+
)
4056
)
4157

4258
assert cluster_listener.zha_send_event.call_count == 1

tests/test_konke.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from unittest import mock
55

66
import pytest
7+
import zigpy.types as t
78

89
from tests.common import ZCL_IAS_MOTION_COMMAND, ClusterListener
910
import zhaquirks
@@ -83,7 +84,15 @@ async def test_konke_button(zigpy_device_from_quirk, quirk):
8384

8485
# single press
8586
message = b"\x08W\n\x00\x00\x10\x80"
86-
device.handle_message(260, cluster.cluster_id, 1, 1, message)
87+
device.packet_received(
88+
t.ZigbeePacket(
89+
profile_id=260,
90+
cluster_id=cluster.cluster_id,
91+
src_ep=1,
92+
dst_ep=1,
93+
data=t.SerializableBytes(message),
94+
)
95+
)
8796
assert listener.zha_send_event.call_count == 1
8897
assert listener.zha_send_event.call_args_list[0][0][0] == COMMAND_SINGLE
8998
assert listener.zha_send_event.call_args_list[0][0][1][PRESS_TYPE] == COMMAND_SINGLE
@@ -92,7 +101,15 @@ async def test_konke_button(zigpy_device_from_quirk, quirk):
92101
# double press
93102
listener.reset_mock()
94103
message = b"\x08X\n\x00\x00\x10\x81"
95-
device.handle_message(260, cluster.cluster_id, 1, 1, message)
104+
device.packet_received(
105+
t.ZigbeePacket(
106+
profile_id=260,
107+
cluster_id=cluster.cluster_id,
108+
src_ep=1,
109+
dst_ep=1,
110+
data=t.SerializableBytes(message),
111+
)
112+
)
96113
assert listener.zha_send_event.call_count == 1
97114
assert listener.zha_send_event.call_args_list[0][0][0] == COMMAND_DOUBLE
98115
assert listener.zha_send_event.call_args_list[0][0][1][PRESS_TYPE] == COMMAND_DOUBLE
@@ -101,7 +118,15 @@ async def test_konke_button(zigpy_device_from_quirk, quirk):
101118
# long press
102119
listener.reset_mock()
103120
message = b"\x08Y\n\x00\x00\x10\x82"
104-
device.handle_message(260, cluster.cluster_id, 1, 1, message)
121+
device.packet_received(
122+
t.ZigbeePacket(
123+
profile_id=260,
124+
cluster_id=cluster.cluster_id,
125+
src_ep=1,
126+
dst_ep=1,
127+
data=t.SerializableBytes(message),
128+
)
129+
)
105130
assert listener.zha_send_event.call_count == 1
106131
assert listener.zha_send_event.call_args_list[0][0][0] == COMMAND_HOLD
107132
assert listener.zha_send_event.call_args_list[0][0][1][PRESS_TYPE] == COMMAND_HOLD

tests/test_linxura.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from unittest import mock
44

55
import pytest
6+
import zigpy.types as t
67
from zigpy.zcl.clusters.security import IasZone
78

89
import zhaquirks
@@ -105,7 +106,15 @@ async def test_button_triggers(zigpy_device_from_quirk, message, button, press_t
105106
listener = mock.MagicMock()
106107
cluster.add_listener(listener)
107108

108-
device.handle_message(260, cluster.cluster_id, 1, 1, message)
109+
device.packet_received(
110+
t.ZigbeePacket(
111+
profile_id=260,
112+
cluster_id=cluster.cluster_id,
113+
src_ep=1,
114+
dst_ep=1,
115+
data=t.SerializableBytes(message),
116+
)
117+
)
109118
assert listener.zha_send_event.call_count == 1
110119
assert listener.zha_send_event.call_args == mock.call(
111120
f"{button}_{press_type}",

tests/test_philips.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ def test_PhilipsRemoteCluster_long_press(
628628
(4),
629629
),
630630
)
631-
def test_ButtonPressQueue_presses_without_pause(button_presses):
631+
async def test_ButtonPressQueue_presses_without_pause(button_presses):
632632
"""Test ButtonPressQueue presses without pause in between presses."""
633633

634634
q = ButtonPressQueue()

tests/test_quirks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
zhaquirks.setup()
6161

6262
ALL_QUIRK_CLASSES = []
63-
for manufacturer in zq._DEVICE_REGISTRY._registry.values():
63+
for manufacturer in zq.DEVICE_REGISTRY.registry_v1.values():
6464
for model_quirk_list in manufacturer.values():
6565
for quirk in model_quirk_list:
6666
if quirk in ALL_QUIRK_CLASSES:

tests/test_quirks_v2.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010

1111
zhaquirks.setup()
1212

13-
14-
ALL_QUIRK_V2_CLASSES: list[QuirksV2RegistryEntry] = itertools.chain.from_iterable(
15-
zigpy.quirks._DEVICE_REGISTRY._registry_v2.values()
13+
# zigpy registry v2 contains duplicates (due to being keyed by manufacturer and model),
14+
# so to avoid duplicates but maintain insertion order, we use a dict instead of a set
15+
ALL_QUIRK_V2_CLASSES: dict[QuirksV2RegistryEntry, None] = dict.fromkeys(
16+
itertools.chain.from_iterable(zigpy.quirks.DEVICE_REGISTRY.registry_v2.values())
1617
)
1718

1819

@@ -46,3 +47,26 @@ def test_translation_key_and_fallback_name_match() -> None:
4647
assert (
4748
len(set(fallback_names)) == 1
4849
), f"Translation key '{translation_key}' is shared by quirks with different fallback names: {quirk_locations}"
50+
51+
52+
def test_manufacturer_model_metadata_unique() -> None:
53+
"""Ensure that each manufacturer-model pair is unique across all v2 quirks."""
54+
# quirk_locations are a list and not a set below,
55+
# as they are not guaranteed to be unique when set up incorrectly
56+
57+
# (manufacturer, model) -> {quirk_location}
58+
man_model_quirk_map: dict[tuple[str, str], list[str]] = collections.defaultdict(
59+
list
60+
)
61+
62+
for quirk in ALL_QUIRK_V2_CLASSES:
63+
for metadata in quirk.manufacturer_model_metadata:
64+
man_model_quirk_map[(metadata.manufacturer, metadata.model)].append(
65+
f"{quirk.quirk_file}:{quirk.quirk_file_line}"
66+
)
67+
68+
# check that each manufacturer-model pair is unique
69+
for (manufacturer, model), quirk_locations in man_model_quirk_map.items():
70+
assert (
71+
len(quirk_locations) == 1
72+
), f"Manufacturer-model pair '{manufacturer}' '{model}' is shared by multiple quirks: {quirk_locations}"

0 commit comments

Comments
 (0)