8
8
import itertools
9
9
import contextlib
10
10
11
+ import zigpy .zcl
11
12
import zigpy .zdo
12
13
import zigpy .util
13
14
import zigpy .state
19
20
import zigpy .profiles
20
21
import zigpy .zdo .types as zdo_t
21
22
import zigpy .application
22
- import zigpy .zcl .foundation
23
23
from zigpy .zcl import clusters
24
24
from zigpy .types import ExtendedPanId , deserialize as list_deserialize
25
25
from zigpy .zdo .types import CLUSTERS as ZDO_CLUSTERS , ZDOCmd , ZDOHeader , MultiAddress
37
37
from zigpy_znp .zigbee .zdo_converters import ZDO_CONVERTERS
38
38
39
39
ZDO_ENDPOINT = 0
40
+ ZHA_ENDPOINT = 1
41
+ ZLL_ENDPOINT = 2
40
42
41
43
# All of these are in seconds
42
44
PROBE_TIMEOUT = 5
@@ -406,7 +408,7 @@ async def form_network(self):
406
408
await self ._write_stack_settings (reset_if_changed = False )
407
409
await self ._znp .reset ()
408
410
409
- def get_dst_address (self , cluster ) :
411
+ def get_dst_address (self , cluster : zigpy . zcl . Cluster ) -> MultiAddress :
410
412
"""
411
413
Helper to get a dst address for bind/unbind operations.
412
414
@@ -418,7 +420,7 @@ def get_dst_address(self, cluster):
418
420
dst_addr .addrmode = 0x03
419
421
dst_addr .ieee = self .ieee
420
422
dst_addr .endpoint = self ._find_endpoint (
421
- dst_ep = cluster .endpoint ,
423
+ dst_ep = cluster .endpoint . endpoint_id ,
422
424
profile = cluster .endpoint .profile_id ,
423
425
cluster = cluster .cluster_id ,
424
426
)
@@ -1133,7 +1135,7 @@ async def _register_endpoints(self) -> None:
1133
1135
1134
1136
await self ._znp .request (
1135
1137
c .AF .Register .Req (
1136
- Endpoint = 1 ,
1138
+ Endpoint = ZHA_ENDPOINT ,
1137
1139
ProfileId = zigpy .profiles .zha .PROFILE_ID ,
1138
1140
DeviceId = zigpy .profiles .zha .DeviceType .IAS_CONTROL ,
1139
1141
DeviceVersion = 0b0000 ,
@@ -1152,7 +1154,7 @@ async def _register_endpoints(self) -> None:
1152
1154
1153
1155
await self ._znp .request (
1154
1156
c .AF .Register .Req (
1155
- Endpoint = 2 ,
1157
+ Endpoint = ZLL_ENDPOINT ,
1156
1158
ProfileId = zigpy .profiles .zll .PROFILE_ID ,
1157
1159
DeviceId = zigpy .profiles .zll .DeviceType .CONTROLLER ,
1158
1160
DeviceVersion = 0b0000 ,
@@ -1190,14 +1192,19 @@ async def write_network_info(
1190
1192
def _find_endpoint (self , dst_ep : int , profile : int , cluster : int ) -> int :
1191
1193
"""
1192
1194
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.
1194
1197
"""
1195
1198
1196
1199
if dst_ep == ZDO_ENDPOINT :
1197
1200
return ZDO_ENDPOINT
1198
1201
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
+
1199
1206
# Always fall back to endpoint 1
1200
- candidates = [1 ]
1207
+ candidates = [ZHA_ENDPOINT ]
1201
1208
1202
1209
for ep_id , endpoint in self .zigpy_device .endpoints .items ():
1203
1210
if ep_id == ZDO_ENDPOINT :
@@ -1321,7 +1328,7 @@ async def _send_request_raw(
1321
1328
)
1322
1329
1323
1330
# 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
1325
1332
src_ep = self ._find_endpoint (dst_ep = dst_ep , profile = profile , cluster = cluster )
1326
1333
1327
1334
if relays is None :
0 commit comments