Skip to content

Commit 5625ea5

Browse files
authored
fix zigbee groups, updates form zigbee-herdsman (#60)
* pull updates from zigbee-herdsman fix zigbee groups fixes #58 * add test * update broadcast based on zigbee-herdsman * ignore resetInd, do not log waiting for...
1 parent 9413973 commit 5625ea5

17 files changed

+391
-236
lines changed

setup.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
"Texas Instruments CC2531 radios for zigpy",
1818
long_description=long_description,
1919
long_description_content_type="text/markdown",
20-
url="http://github.com/sanyatuning/zigpy-cc",
21-
author="Balázs Sándor",
20+
url="http://github.com/zigpy/zigpy-cc",
21+
author="Balazs Sandor",
2222
author_email="[email protected]",
2323
license="GPL-3.0",
2424
packages=find_packages(exclude=["*.tests"]),

test.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@
33
import os
44

55
import coloredlogs as coloredlogs
6-
from zigpy_cc import config
6+
import zigpy.config
77
from zigpy.device import Device
88

9+
from zigpy_cc import config
910
from zigpy_cc.zigbee import application
1011

1112
fmt = "%(name)s %(levelname)s %(message)s"
1213
coloredlogs.install(level="DEBUG", fmt=fmt)
1314

1415
APP_CONFIG = {
16+
zigpy.config.CONF_NWK: {
17+
zigpy.config.CONF_NWK_PAN_ID: 0x2A61,
18+
zigpy.config.CONF_NWK_EXTENDED_PAN_ID: "A0:B0:C0:D0:10:20:30:40",
19+
},
1520
config.CONF_DEVICE: {
1621
config.CONF_DEVICE_PATH: "auto",
1722
config.CONF_DEVICE_BAUDRATE: 115200,
@@ -80,7 +85,7 @@ async def main():
8085
await app.startup(auto_form=False)
8186
await app.form_network()
8287

83-
# await app.permit_ncp()
88+
await app.permit_ncp()
8489

8590

8691
loop.run_until_complete(main())

tests/test_api.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ async def mock_fut():
8181

8282
for subsystem, commands in Definition.items():
8383
for cmd in commands:
84-
ret = await api._command(subsystem, cmd["name"], mock.sentinel.cmd_data)
84+
ret = await api.request(subsystem, cmd["name"], mock.sentinel.cmd_data)
8585
assert ret is mock.sentinel.cmd_result
8686
# assert api._api_frame.call_count == 1
8787
# assert api._api_frame.call_args[0][0] == cmd
@@ -111,7 +111,7 @@ def mock_obj(subsystem, command, payload):
111111
for subsystem, commands in Definition.items():
112112
for cmd in commands:
113113
with pytest.raises(asyncio.TimeoutError):
114-
await api._command(subsystem, cmd["name"], mock.sentinel.cmd_data)
114+
await api.request(subsystem, cmd["name"], mock.sentinel.cmd_data)
115115
# assert api._api_frame.call_count == 1
116116
# assert api._api_frame.call_args[0][0] == cmd
117117
# assert api._api_frame.call_args[0][1] == mock.sentinel.cmd_data

tests/test_application.py

+49-35
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
from unittest import mock
44

55
import pytest
6-
from zigpy.types import EUI64
6+
from zigpy.types import EUI64, Group, BroadcastAddress
77
import zigpy.zdo.types as zdo_t
8+
from zigpy.zcl.clusters.general import Groups
89

910
from zigpy_cc import types as t
1011
from zigpy_cc.api import API
@@ -26,6 +27,7 @@ def app():
2627
app = application.ControllerApplication(APP_CONFIG)
2728
app._api = API(APP_CONFIG[config.CONF_DEVICE])
2829
app._api.set_application(app)
30+
app._semaphore = asyncio.Semaphore()
2931
return app
3032

3133

@@ -64,39 +66,6 @@ def addr_nwk_and_ieee(nwk, ieee):
6466
return addr
6567

6668

67-
"""
68-
DEBUG:zigpy_cc.api:--> AREQ ZDO leaveInd {'srcaddr': 406, 'extaddr': '0x07a3c302008d1500', 'request': 0, 'removechildren': 0, 'rejoin': 0}
69-
DEBUG:zigpy_cc.api:--> AREQ ZDO tcDeviceInd {'nwkaddr': 11938, 'extaddr': '0x07a3c302008d1500', 'parentaddr': 0}
70-
DEBUG:zigpy_cc.api:--> AREQ ZDO endDeviceAnnceInd {'srcaddr': 11938, 'nwkaddr': 11938, 'ieeeaddr': '0x07a3c302008d1500', 'capabilities': 128}
71-
DEBUG:zigpy_cc.api:--> AREQ AF incomingMsg {'groupid': 0, 'clusterid': 0, 'srcaddr': 11938, 'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 123, 'securityuse': 0, 'timestamp': 1000027, 'transseqnumber': 0, 'len': 25, 'data': bytearray(b'\x18\x00\n\x05\x00B\x12lumi.sensor_switch')}
72-
DEBUG:zigpy_cc.api:--> AREQ AF incomingMsg {'groupid': 0, 'clusterid': 0, 'srcaddr': 11938, 'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 123, 'securityuse': 0, 'timestamp': 1000039, 'transseqnumber': 0, 'len': 7, 'data': bytearray(b'\x18\x01\n\x01\x00 \n')}
73-
DEBUG:zigpy_cc.api:--> AREQ AF incomingMsg {'groupid': 0, 'clusterid': 0, 'srcaddr': 11938, 'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 126, 'securityuse': 0, 'timestamp': 1000050, 'transseqnumber': 0, 'len': 29, 'data': bytearray(b'\x1c4\x12\x02\n\x02\xffL\x06\x00\x10\x01!\xd8\x0b!\xa8\x01$\x00\x00\x00\x00\x00!\xbdJ Y')}
74-
DEBUG:zigpy_cc.api:--> AREQ ZDO srcRtgInd {'dstaddr': 6595, 'relaycount': 1, 'relaylist': [30485]}
75-
DEBUG:zigpy_cc.api:--> AREQ AF incomingMsg {'groupid': 0, 'clusterid': 10, 'srcaddr': 6595, 'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 60, 'securityuse': 0, 'timestamp': 1069473, 'transseqnumber': 0, 'len': 5, 'data': bytearray(b'\x10\x94\x00\x00\x00')}
76-
DEBUG:zigpy_cc.api:--> AREQ ZDO srcRtgInd {'dstaddr': 49164, 'relaycount': 2, 'relaylist': [6595, 30485]}
77-
DEBUG:zigpy_cc.api:--> AREQ AF incomingMsg {'groupid': 0, 'clusterid': 10, 'srcaddr': 49164, 'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 60, 'securityuse': 0, 'timestamp': 1117084, 'transseqnumber': 0, 'len': 5, 'data': bytearray(b'\x10\x13\x00\x00\x00')}
78-
DEBUG:zigpy_cc.api:--> AREQ ZDO srcRtgInd {'dstaddr': 51918, 'relaycount': 0, 'relaylist': []}
79-
DEBUG:zigpy_cc.api:--> AREQ ZDO srcRtgInd {'dstaddr': 51918, 'relaycount': 0, 'relaylist': []}
80-
DEBUG:zigpy_cc.api:--> AREQ ZDO endDeviceAnnceInd {'srcaddr': 53322, 'nwkaddr': 53322, 'ieeeaddr': '0x41e54b02008d1500', 'capabilities': 132}
81-
DEBUG:zigpy_cc.api:--> AREQ ZDO tcDeviceInd {'nwkaddr': 53322, 'extaddr': '0x41e54b02008d1500', 'parentaddr': 51918}
82-
DEBUG:zigpy_cc.api:--> AREQ ZDO srcRtgInd {'dstaddr': 53322, 'relaycount': 1, 'relaylist': [51918]}
83-
DEBUG:zigpy_cc.api:--> AREQ AF incomingMsg {'groupid': 0, 'clusterid': 10, 'srcaddr': 53322, 'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 39, 'securityuse': 0, 'timestamp': 1137608, 'transseqnumber': 0, 'len': 5, 'data': bytearray(b'\x10\x1d\x00\x00\x00')}
84-
DEBUG:zigpy_cc.api:--> AREQ ZDO srcRtgInd {'dstaddr': 44052, 'relaycount': 2, 'relaylist': [6595, 30485]}
85-
DEBUG:zigpy_cc.api:--> AREQ AF incomingMsg {'groupid': 0, 'clusterid': 18, 'srcaddr': 44052, 'srcendpoint': 2, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 60, 'securityuse': 0, 'timestamp': 1167545, 'transseqnumber': 0, 'len': 8, 'data': bytearray(b'\x18E\nU\x00!\x02\x00')}
86-
DEBUG:zigpy_cc.api:--> AREQ ZDO srcRtgInd {'dstaddr': 6595, 'relaycount': 1, 'relaylist': [30485]}
87-
DEBUG:zigpy_cc.api:--> AREQ AF incomingMsg {'groupid': 0, 'clusterid': 10, 'srcaddr': 6595, 'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 57, 'securityuse': 0, 'timestamp': 1256953, 'transseqnumber': 0, 'len': 5, 'data': bytearray(b'\x10\xd1\x00\x00\x00')}
88-
DEBUG:zigpy_cc.api:--> AREQ ZDO srcRtgInd {'dstaddr': 49164, 'relaycount': 2, 'relaylist': [6595, 30485]}
89-
DEBUG:zigpy_cc.api:--> AREQ AF incomingMsg {'groupid': 0, 'clusterid': 10, 'srcaddr': 49164, 'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 57, 'securityuse': 0, 'timestamp': 1310524, 'transseqnumber': 0, 'len': 5, 'data': bytearray(b'\x10\x14\x00\x00\x00')}
90-
DEBUG:zigpy_cc.api:--> AREQ ZDO srcRtgInd {'dstaddr': 53322, 'relaycount': 1, 'relaylist': [51918]}
91-
DEBUG:zigpy_cc.api:--> AREQ AF incomingMsg {'groupid': 0, 'clusterid': 10, 'srcaddr': 53322, 'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 39, 'securityuse': 0, 'timestamp': 1331211, 'transseqnumber': 0, 'len': 5, 'data': bytearray(b'\x10\x1e\x00\x00\x00')}
92-
DEBUG:zigpy_cc.api:--> AREQ ZDO srcRtgInd {'dstaddr': 6595, 'relaycount': 1, 'relaylist': [30485]}
93-
DEBUG:zigpy_cc.api:--> AREQ AF incomingMsg {'groupid': 0, 'clusterid': 10, 'srcaddr': 6595, 'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 60, 'securityuse': 0, 'timestamp': 1444466, 'transseqnumber': 0, 'len': 5, 'data': bytearray(b'\x10\x0e\x00\x00\x00')}
94-
DEBUG:zigpy_cc.api:--> AREQ ZDO srcRtgInd {'dstaddr': 49164, 'relaycount': 2, 'relaylist': [6595, 30485]}
95-
DEBUG:zigpy_cc.api:--> AREQ AF incomingMsg {'groupid': 0, 'clusterid': 10, 'srcaddr': 49164, 'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 57, 'securityuse': 0, 'timestamp': 1504140, 'transseqnumber': 0, 'len': 5, 'data': bytearray(b'\x10\x15\x00\x00\x00')}
96-
DEBUG:zigpy_cc.api:--> AREQ ZDO tcDeviceInd {'nwkaddr': 49164, 'extaddr': '0x7ceb2303008d1500', 'parentaddr': 6595}
97-
"""
98-
99-
10069
def test_join(app):
10170
payload = {"nwkaddr": 27441, "extaddr": "0x07a3c302008d1500", "parentaddr": 0}
10271
obj = ZpiObject(2, 5, "tcDeviceInd", 202, payload, [])
@@ -199,13 +168,58 @@ async def test_request(app: application.ControllerApplication):
199168
)
200169

201170
assert len(app._api._waiters) == 1
171+
assert (
172+
"SREQ ZDO nodeDescReq tsn: 1 {'dstaddr': 0xd04a, 'nwkaddrofinterest': 0x2ea2}"
173+
== str(app._api.request_raw.call_args[0][0])
174+
)
202175
assert res == (0, "message send success")
203176

204177

178+
@pytest.mark.asyncio
179+
async def test_mrequest(app: application.ControllerApplication):
180+
fut = asyncio.Future()
181+
fut.set_result(None)
182+
app._api.request_raw = mock.MagicMock(return_value=fut)
183+
184+
# multicast (0x0002, 260, 6, 1, 39, b"\x01'\x00", 0, 3)
185+
res = await app.mrequest(Group(2), 260, Groups.cluster_id, 1, 39, b"\x01'\x00")
186+
187+
assert 1 == len(app._api._waiters)
188+
assert (
189+
"SREQ AF dataRequestExt tsn: 39 {'dstaddrmode': <AddressMode.ADDR_GROUP: 1>, "
190+
"'dstaddr': 0x0002, 'destendpoint': 255, 'dstpanid': 0, "
191+
"'srcendpoint': 1, 'clusterid': 4, 'transid': 39, 'options': 0, 'radius': 30, 'len': 3, "
192+
"'data': b\"\\x01'\\x00\"}" == str(app._api.request_raw.call_args[0][0])
193+
)
194+
assert (0, "message send success") == res
195+
196+
197+
@pytest.mark.asyncio
198+
async def test_broadcast(app: application.ControllerApplication):
199+
fut = asyncio.Future()
200+
fut.set_result(None)
201+
app._api.request_raw = mock.MagicMock(return_value=fut)
202+
203+
# broadcast (0, 54, 0, 0, 0, 0, 45, b'-<\x00', <BroadcastAddress.ALL_ROUTERS_AND_COORDINATOR: 65532>)
204+
res = await app.broadcast(
205+
0, 54, 0, 0, 0, 0, 45, b"-<\x00", BroadcastAddress.ALL_ROUTERS_AND_COORDINATOR
206+
)
207+
208+
assert 0 == len(app._api._waiters)
209+
assert (
210+
"SREQ ZDO mgmtPermitJoinReq tsn: 45 {'addrmode': <AddressMode.ADDR_BROADCAST: 15>, "
211+
"'dstaddr': 0xfffc, 'duration': 60, 'tcsignificance': 0}"
212+
== str(app._api.request_raw.call_args[0][0])
213+
)
214+
assert (0, "broadcast send success") == res
215+
216+
205217
"""
206218
zigpy_cc.api DEBUG <-- SREQ ZDO nodeDescReq {'dstaddr': 53322, 'nwkaddrofinterest': 0}
207219
zigpy_cc.api DEBUG --> SRSP ZDO nodeDescReq {'status': 0}
208-
zigpy_cc.api DEBUG --> AREQ ZDO nodeDescRsp {'srcaddr': 53322, 'status': 128, 'nwkaddr': 0, 'logicaltype_cmplxdescavai_userdescavai': 0, 'apsflags_freqband': 0, 'maccapflags': 0, 'manufacturercode': 0, 'maxbuffersize': 0, 'maxintransfersize': 0, 'servermask': 0, 'maxouttransfersize': 0, 'descriptorcap': 0}
220+
zigpy_cc.api DEBUG --> AREQ ZDO nodeDescRsp {'srcaddr': 53322, 'status': 128, 'nwkaddr': 0,
221+
'logicaltype_cmplxdescavai_userdescavai': 0, 'apsflags_freqband': 0, 'maccapflags': 0, 'manufacturercode': 0,
222+
'maxbuffersize': 0, 'maxintransfersize': 0, 'servermask': 0, 'maxouttransfersize': 0, 'descriptorcap': 0}
209223
"""
210224

211225

tests/test_buffalo.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import zigpy_cc.types as t
2-
from zigpy.types import EUI64, NWK
1+
from zigpy.types import EUI64, Group, NWK
32

3+
import zigpy_cc.types as t
44
from zigpy_cc.buffalo import Buffalo, BuffaloOptions
55

66
ieeeAddr1 = {
@@ -26,15 +26,21 @@ def test_write_ieee2():
2626
assert ieeeAddr2["hex"] == data_out.buffer
2727

2828

29+
def test_write_ieee_group():
30+
data_out = Buffalo(b"")
31+
data_out.write_parameter(t.ParameterType.IEEEADDR, Group(2), {})
32+
assert b"\x02\x00\x00\x00\x00\x00\x00\x00" == data_out.buffer
33+
34+
2935
def test_read_ieee():
3036
data_in = Buffalo(ieeeAddr1["hex"])
31-
actual = data_in.read_parameter(t.ParameterType.IEEEADDR, {})
37+
actual = data_in.read_parameter("test", t.ParameterType.IEEEADDR, {})
3238
assert ieeeAddr1["string"] == actual
3339

3440

3541
def test_read_ieee2():
3642
data_in = Buffalo(ieeeAddr2["hex"])
37-
actual = data_in.read_parameter(t.ParameterType.IEEEADDR, {})
43+
actual = data_in.read_parameter("test", t.ParameterType.IEEEADDR, {})
3844
assert ieeeAddr2["string"] == actual
3945

4046

@@ -62,5 +68,5 @@ def test_list_nighbor_lqi():
6268
data_in = Buffalo(data_out.buffer)
6369
options = BuffaloOptions()
6470
options.length = len(value)
65-
act = data_in.read_parameter(t.ParameterType.LIST_NEIGHBOR_LQI, options)
71+
act = data_in.read_parameter("test", t.ParameterType.LIST_NEIGHBOR_LQI, options)
6672
assert value == act

tests/test_types.py

+9-8
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ def test_ieee_addr():
305305
def test_from_cluster_id():
306306
profile = 0
307307
obj = ZpiObject.from_cluster(
308-
NWK(53322), profile, ZDOCmd.Node_Desc_req, 0, 0, 3, b"\x03\x4a\xd0", 32
308+
NWK(53322), profile, ZDOCmd.Node_Desc_req, 0, 0, 3, b"\x03\x4a\xd0"
309309
)
310310

311311
assert (
@@ -327,11 +327,11 @@ def test_from_cluster_id():
327327
def test_from_cluster_id_ZCL():
328328
profile = 260
329329
obj = ZpiObject.from_cluster(
330-
NWK(53322), profile, 0, 1, 1, 1, b"\x00\x0b\x00\x04\x00\x05\x00", 123
330+
NWK(53322), profile, 0, 1, 1, 123, b"\x00\x0b\x00\x04\x00\x05\x00"
331331
)
332332

333333
assert (
334-
"SREQ AF dataRequest tsn: 1 {'dstaddr': 53322, 'destendpoint': 1, "
334+
"SREQ AF dataRequest tsn: 123 {'dstaddr': 53322, 'destendpoint': 1, "
335335
"'srcendpoint': 1, 'clusterid': 0, 'transid': 123, 'options': 0, 'radius': 30, "
336336
"'len': 7, 'data': b'\\x00\\x0b\\x00\\x04\\x00\\x05\\x00'}" == str(obj)
337337
)
@@ -368,23 +368,24 @@ def test_bind_req():
368368
b"\x01<x'\xfe\xffW\x0b\x00\x01\x08\x00\x03\x0c%\xed\x18\x00K\x12\x00\x01", True, False)
369369
zigpy_cc.api DEBUG waiting for 1 bindReq
370370
zigpy_cc.api DEBUG --> SREQ ZDO bindReq tsn: 1 {
371-
'dstaddr': 0xbd8b, 'srcaddr': 00:0b:57:ff:fe:27:78:3c, 'srcendpoint': 1, 'clusterid': 8, 'dstaddrmode': 3, 'dstaddress': 00:12:4b:00:18:ed:25:0c, 'dstendpoint': 1}
371+
'dstaddr': 0xbd8b, 'srcaddr': 00:0b:57:ff:fe:27:78:3c, 'srcendpoint': 1, 'clusterid': 8,
372+
'dstaddrmode': 3, 'dstaddress': 00:12:4b:00:18:ed:25:0c, 'dstendpoint': 1}
372373
zigpy_cc.uart DEBUG Send:
373374
b"\xfe\x17%!\x8b\xbd<x'\xfe\xffW\x0b\x00\x01\x08\x00\x03\x0c%\xed\x18\x00K\x12\x00\x01\x95"
374375
375376
"""
376377

377378
data = b"\x02<x'\xfe\xffW\x0b\x00\x01\x08\x00\x03\x0c%\xed\x18\x00K\x12\x00\x01"
378379

379-
obj = ZpiObject.from_cluster(NWK(0x6292), 0, 0x0021, 0, 0, 2, data, 123)
380+
obj = ZpiObject.from_cluster(NWK(0x6292), 0, 0x0021, 0, 0, 2, data)
380381

381382
assert (
382383
"SREQ ZDO bindReq tsn: 2 {"
383384
"'dstaddr': 0x6292, "
384385
"'srcaddr': 00:0b:57:ff:fe:27:78:3c, "
385386
"'srcendpoint': 1, "
386387
"'clusterid': 8, "
387-
"'dstaddrmode': 3, "
388+
"'dstaddrmode': <AddressMode.ADDR_64BIT: 3>, "
388389
"'dstaddress': 00:12:4b:00:18:ed:25:0c, "
389390
"'dstendpoint': 1}" == str(obj)
390391
)
@@ -431,7 +432,7 @@ def test_bind_req_serialize():
431432
"srcaddr": EUI64(reversed(b"\x00\x0b\x57\xff\xfe\x27\x78\x3c")),
432433
"srcendpoint": 1,
433434
"clusterid": 8,
434-
"dstaddrmode": 3,
435+
"dstaddrmode": t.AddressMode.ADDR_64BIT,
435436
"dstaddress": EUI64(reversed(b"\x00\x12\x4b\x00\x18\xed\x25\x0c")),
436437
"dstendpoint": 1,
437438
}
@@ -442,7 +443,7 @@ def test_bind_req_serialize():
442443
"'srcaddr': 00:0b:57:ff:fe:27:78:3c, "
443444
"'srcendpoint': 1, "
444445
"'clusterid': 8, "
445-
"'dstaddrmode': 3, "
446+
"'dstaddrmode': <AddressMode.ADDR_64BIT: 3>, "
446447
"'dstaddress': 00:12:4b:00:18:ed:25:0c, "
447448
"'dstendpoint': 1}" == str(obj)
448449
)

version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
for line in file:
1111
line = re.sub(r"(MAJOR_VERSION =).*", "\\1 " + parts[0], line)
1212
line = re.sub(r"(MINOR_VERSION =).*", "\\1 " + parts[1], line)
13-
line = re.sub(r"(PATCH_VERSION =).*", "\\1 \"" + parts[2] + "\"", line)
13+
line = re.sub(r"(PATCH_VERSION =).*", '\\1 "' + parts[2] + '"', line)
1414
print(line, end="")

0 commit comments

Comments
 (0)