88import itertools
99import contextlib
1010
11+ import zigpy .zcl
1112import zigpy .zdo
1213import zigpy .util
1314import zigpy .state
1920import zigpy .profiles
2021import zigpy .zdo .types as zdo_t
2122import zigpy .application
22- import zigpy .zcl .foundation
2323from zigpy .zcl import clusters
2424from zigpy .types import ExtendedPanId , deserialize as list_deserialize
2525from zigpy .zdo .types import CLUSTERS as ZDO_CLUSTERS , ZDOCmd , ZDOHeader , MultiAddress
3737from zigpy_znp .zigbee .zdo_converters import ZDO_CONVERTERS
3838
3939ZDO_ENDPOINT = 0
40+ ZHA_ENDPOINT = 1
41+ ZLL_ENDPOINT = 2
4042
4143# All of these are in seconds
4244PROBE_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