Skip to content

Commit 42a5248

Browse files
committed
Use coordinator endpoint 1 for Z-Stack >= 20210708
1 parent 06e32a1 commit 42a5248

File tree

2 files changed

+38
-8
lines changed

2 files changed

+38
-8
lines changed

tests/application/test_requests.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import pytest
44
import zigpy.zdo
55
import zigpy.endpoint
6+
import zigpy.profiles
67
from zigpy.zdo.types import ZDOCmd, SizePrefixedSimpleDescriptor
78
from zigpy.exceptions import DeliveryError
89

@@ -63,6 +64,28 @@ async def test_zdo_request_interception(device, make_application):
6364
await app.shutdown()
6465

6566

67+
@pytest.mark.parametrize("device", FORMED_DEVICES)
68+
async def test_chosen_dst_endpoint(device, make_application, mocker):
69+
app, znp_server = make_application(device)
70+
await app.startup(auto_form=False)
71+
72+
cluster = mocker.Mock()
73+
cluster.endpoint.endpoint_id = 2
74+
cluster.endpoint.profile_id = zigpy.profiles.zll.PROFILE_ID
75+
cluster.cluster_id = 0x1234
76+
77+
# ZLL endpoint will be used normally
78+
assert app.get_dst_address(cluster).endpoint == 2
79+
80+
build = mocker.patch.object(type(app), "_zstack_build_id", mocker.PropertyMock())
81+
build.return_value = 20210708
82+
83+
# More recent builds work with everything on endpoint 1
84+
assert app.get_dst_address(cluster).endpoint == 1
85+
86+
await app.shutdown()
87+
88+
6689
@pytest.mark.parametrize("device", FORMED_DEVICES)
6790
async def test_zigpy_request(device, make_application):
6891
app, znp_server = make_application(device)

zigpy_znp/zigbee/application.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import itertools
99
import contextlib
1010

11+
import zigpy.zcl
1112
import zigpy.zdo
1213
import zigpy.util
1314
import zigpy.state
@@ -19,7 +20,6 @@
1920
import zigpy.profiles
2021
import zigpy.zdo.types as zdo_t
2122
import zigpy.application
22-
import zigpy.zcl.foundation
2323
from zigpy.zcl import clusters
2424
from zigpy.types import ExtendedPanId, deserialize as list_deserialize
2525
from zigpy.zdo.types import CLUSTERS as ZDO_CLUSTERS, ZDOCmd, ZDOHeader, MultiAddress
@@ -37,6 +37,8 @@
3737
from zigpy_znp.zigbee.zdo_converters import ZDO_CONVERTERS
3838

3939
ZDO_ENDPOINT = 0
40+
ZHA_ENDPOINT = 1
41+
ZLL_ENDPOINT = 2
4042

4143
# All of these are in seconds
4244
PROBE_TIMEOUT = 5
@@ -406,7 +408,7 @@ async def form_network(self):
406408
await self._write_stack_settings(reset_if_changed=False)
407409
await self._znp.reset()
408410

409-
def get_dst_address(self, cluster):
411+
def get_dst_address(self, cluster: zigpy.zcl.Cluster) -> MultiAddress:
410412
"""
411413
Helper to get a dst address for bind/unbind operations.
412414
@@ -418,7 +420,7 @@ def get_dst_address(self, cluster):
418420
dst_addr.addrmode = 0x03
419421
dst_addr.ieee = self.ieee
420422
dst_addr.endpoint = self._find_endpoint(
421-
dst_ep=cluster.endpoint,
423+
dst_ep=cluster.endpoint.endpoint_id,
422424
profile=cluster.endpoint.profile_id,
423425
cluster=cluster.cluster_id,
424426
)
@@ -1133,7 +1135,7 @@ async def _register_endpoints(self) -> None:
11331135

11341136
await self._znp.request(
11351137
c.AF.Register.Req(
1136-
Endpoint=1,
1138+
Endpoint=ZHA_ENDPOINT,
11371139
ProfileId=zigpy.profiles.zha.PROFILE_ID,
11381140
DeviceId=zigpy.profiles.zha.DeviceType.IAS_CONTROL,
11391141
DeviceVersion=0b0000,
@@ -1152,7 +1154,7 @@ async def _register_endpoints(self) -> None:
11521154

11531155
await self._znp.request(
11541156
c.AF.Register.Req(
1155-
Endpoint=2,
1157+
Endpoint=ZLL_ENDPOINT,
11561158
ProfileId=zigpy.profiles.zll.PROFILE_ID,
11571159
DeviceId=zigpy.profiles.zll.DeviceType.CONTROLLER,
11581160
DeviceVersion=0b0000,
@@ -1190,14 +1192,19 @@ async def write_network_info(
11901192
def _find_endpoint(self, dst_ep: int, profile: int, cluster: int) -> int:
11911193
"""
11921194
Zigpy defaults to sending messages with src_ep == dst_ep. This does not work
1193-
with Z-Stack, which requires endpoints to be registered explicitly on startup.
1195+
with all versions of Z-Stack, which requires endpoints to be registered
1196+
explicitly on startup.
11941197
"""
11951198

11961199
if dst_ep == ZDO_ENDPOINT:
11971200
return ZDO_ENDPOINT
11981201

1202+
# Newer Z-Stack releases ignore profiles and will work properly with endpoint 1
1203+
if self._zstack_build_id >= 20210708:
1204+
return ZHA_ENDPOINT
1205+
11991206
# Always fall back to endpoint 1
1200-
candidates = [1]
1207+
candidates = [ZHA_ENDPOINT]
12011208

12021209
for ep_id, endpoint in self.zigpy_device.endpoints.items():
12031210
if ep_id == ZDO_ENDPOINT:
@@ -1321,7 +1328,7 @@ async def _send_request_raw(
13211328
)
13221329

13231330
# Zigpy just sets src == dst, which doesn't work for devices with many endpoints
1324-
# We pick ours based on the registered endpoints.
1331+
# We pick ours based on the registered endpoints when using an older firmware
13251332
src_ep = self._find_endpoint(dst_ep=dst_ep, profile=profile, cluster=cluster)
13261333

13271334
if relays is None:

0 commit comments

Comments
 (0)