Skip to content

Commit 06c0698

Browse files
authored
0.9.0 Release
2 parents eedf37a + 3911bd6 commit 06c0698

File tree

10 files changed

+874
-117
lines changed

10 files changed

+874
-117
lines changed

LICENSE

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

setup.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
"""Setup module for zigpy-deconz"""
22

3+
import os
4+
35
from setuptools import find_packages, setup
46

57
import zigpy_deconz
68

9+
this_directory = os.path.join(os.path.abspath(os.path.dirname(__file__)))
10+
with open(os.path.join(this_directory, "README.md"), encoding="utf-8") as f:
11+
long_description = f.read()
12+
713
setup(
814
name="zigpy-deconz",
915
version=zigpy_deconz.__version__,
1016
description="A library which communicates with Deconz radios for zigpy",
17+
long_description=long_description,
18+
long_description_content_type="text/markdown",
1119
url="http://github.com/zigpy/zigpy-deconz",
1220
author="Daniel Schmidt",
1321
author_email="[email protected]",
1422
license="GPL-3.0",
1523
packages=find_packages(exclude=["*.tests"]),
16-
install_requires=["pyserial-asyncio", "zigpy-homeassistant>=0.17.0"],
24+
install_requires=["pyserial-asyncio", "zigpy>=0.20.a1"],
1725
tests_require=["pytest", "pytest-asyncio", "asynctest"],
1826
)

tests/test_api.py

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,37 @@
44
from asynctest import CoroutineMock, mock
55
import pytest
66
import serial
7+
import zigpy.config
78

89
from zigpy_deconz import api as deconz_api, types as t, uart
910
import zigpy_deconz.exception
11+
import zigpy_deconz.zigbee.application
12+
13+
DEVICE_CONFIG = {zigpy.config.CONF_DEVICE_PATH: "/dev/null"}
1014

1115

1216
@pytest.fixture
1317
def api():
14-
api = deconz_api.Deconz()
18+
controller = mock.MagicMock(
19+
spec_set=zigpy_deconz.zigbee.application.ControllerApplication
20+
)
21+
api = deconz_api.Deconz(controller, {zigpy.config.CONF_DEVICE_PATH: "/dev/null"})
1522
api._uart = mock.MagicMock()
1623
return api
1724

1825

19-
def test_set_application(api):
20-
api.set_application(mock.sentinel.app)
21-
assert api._app == mock.sentinel.app
22-
23-
2426
@pytest.mark.asyncio
25-
async def test_connect(monkeypatch):
26-
api = deconz_api.Deconz()
27-
dev = mock.MagicMock()
28-
monkeypatch.setattr(
29-
uart, "connect", mock.MagicMock(side_effect=asyncio.coroutine(mock.MagicMock()))
27+
async def test_connect():
28+
controller = mock.MagicMock(
29+
spec_set=zigpy_deconz.zigbee.application.ControllerApplication
3030
)
31-
await api.connect(dev, 115200)
31+
api = deconz_api.Deconz(controller, {zigpy.config.CONF_DEVICE_PATH: "/dev/null"})
32+
33+
with mock.patch.object(uart, "connect", new=CoroutineMock()) as conn_mck:
34+
await api.connect()
35+
assert conn_mck.call_count == 1
36+
assert conn_mck.await_count == 1
37+
assert api._uart == conn_mck.return_value
3238

3339

3440
def test_close(api):
@@ -437,14 +443,13 @@ def test_device_state_network_state(data, network_state):
437443

438444
@pytest.mark.asyncio
439445
async def test_reconnect_multiple_disconnects(monkeypatch, caplog):
440-
api = deconz_api.Deconz()
441-
dev = mock.sentinel.uart
446+
api = deconz_api.Deconz(None, DEVICE_CONFIG)
442447
connect_mock = CoroutineMock()
443448
connect_mock.return_value = asyncio.Future()
444449
connect_mock.return_value.set_result(True)
445450
monkeypatch.setattr(uart, "connect", connect_mock)
446451

447-
await api.connect(dev, 115200)
452+
await api.connect()
448453

449454
caplog.set_level(logging.DEBUG)
450455
connected = asyncio.Future()
@@ -463,14 +468,13 @@ async def test_reconnect_multiple_disconnects(monkeypatch, caplog):
463468

464469
@pytest.mark.asyncio
465470
async def test_reconnect_multiple_attempts(monkeypatch, caplog):
466-
api = deconz_api.Deconz()
467-
dev = mock.sentinel.uart
471+
api = deconz_api.Deconz(None, DEVICE_CONFIG)
468472
connect_mock = CoroutineMock()
469473
connect_mock.return_value = asyncio.Future()
470474
connect_mock.return_value.set_result(True)
471475
monkeypatch.setattr(uart, "connect", connect_mock)
472476

473-
await api.connect(dev, 115200)
477+
await api.connect()
474478

475479
caplog.set_level(logging.DEBUG)
476480
connected = asyncio.Future()
@@ -492,22 +496,22 @@ async def test_reconnect_multiple_attempts(monkeypatch, caplog):
492496
async def test_probe_success(mock_connect, mock_device_state):
493497
"""Test device probing."""
494498

495-
res = await deconz_api.Deconz.probe(mock.sentinel.uart, mock.sentinel.baud)
499+
res = await deconz_api.Deconz.probe(DEVICE_CONFIG)
496500
assert res is True
497501
assert mock_connect.call_count == 1
498502
assert mock_connect.await_count == 1
499-
assert mock_connect.call_args[0][0] is mock.sentinel.uart
503+
assert mock_connect.call_args[0][0] is DEVICE_CONFIG
500504
assert mock_device_state.call_count == 1
501505
assert mock_connect.return_value.close.call_count == 1
502506

503507
mock_connect.reset_mock()
504508
mock_device_state.reset_mock()
505509
mock_connect.reset_mock()
506-
res = await deconz_api.Deconz.probe(mock.sentinel.uart, mock.sentinel.baud)
510+
res = await deconz_api.Deconz.probe(DEVICE_CONFIG)
507511
assert res is True
508512
assert mock_connect.call_count == 1
509513
assert mock_connect.await_count == 1
510-
assert mock_connect.call_args[0][0] is mock.sentinel.uart
514+
assert mock_connect.call_args[0][0] is DEVICE_CONFIG
511515
assert mock_device_state.call_count == 1
512516
assert mock_connect.return_value.close.call_count == 1
513517

@@ -525,10 +529,37 @@ async def test_probe_fail(mock_connect, mock_device_state, exception):
525529
mock_device_state.side_effect = exception
526530
mock_device_state.reset_mock()
527531
mock_connect.reset_mock()
528-
res = await deconz_api.Deconz.probe(mock.sentinel.uart, mock.sentinel.baud)
532+
res = await deconz_api.Deconz.probe(DEVICE_CONFIG)
529533
assert res is False
530534
assert mock_connect.call_count == 1
531535
assert mock_connect.await_count == 1
532-
assert mock_connect.call_args[0][0] is mock.sentinel.uart
536+
assert mock_connect.call_args[0][0] is DEVICE_CONFIG
533537
assert mock_device_state.call_count == 1
534538
assert mock_connect.return_value.close.call_count == 1
539+
540+
541+
@pytest.mark.parametrize(
542+
"value, name",
543+
(
544+
(0x00, "SUCCESS"),
545+
(0xA0, "APS_ASDU_TOO_LONG"),
546+
(0x01, "MAC_PAN_AT_CAPACITY"),
547+
(0xC9, "NWK_UNSUPPORTED_ATTRIBUTE"),
548+
(0xFE, "undefined_0xfe"),
549+
),
550+
)
551+
def test_tx_status(value, name):
552+
"""Test tx status undefined values."""
553+
i = deconz_api.TXStatus(value)
554+
assert i == value
555+
assert i.value == value
556+
assert i.name == name
557+
558+
extra = b"\xaa\55"
559+
data = t.uint8_t(value).serialize()
560+
status, rest = deconz_api.TXStatus.deserialize(data + extra)
561+
assert rest == extra
562+
assert isinstance(status, deconz_api.TXStatus)
563+
assert status == value
564+
assert status.value == value
565+
assert status.name == name

tests/test_application.py

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import asyncio
22
import logging
3-
from unittest import mock
43

5-
import asynctest
4+
from asynctest import CoroutineMock, mock
65
import pytest
6+
import zigpy.config
77
import zigpy.device
88
from zigpy.types import EUI64
99
import zigpy.zdo.types as zdo_t
@@ -15,10 +15,16 @@
1515

1616

1717
@pytest.fixture
18-
def app(monkeypatch, database_file=None):
19-
app = application.ControllerApplication(
20-
deconz_api.Deconz(), database_file=database_file
18+
def app(database_file=None):
19+
config = application.ControllerApplication.SCHEMA(
20+
{
21+
zigpy.config.CONF_DEVICE: {zigpy.config.CONF_DEVICE_PATH: "/dev/null"},
22+
zigpy.config.CONF_DATABASE: database_file,
23+
}
2124
)
25+
26+
app = application.ControllerApplication(config)
27+
app._api = deconz_api.Deconz(app, config[zigpy.config.CONF_DEVICE])
2228
return app
2329

2430

@@ -168,21 +174,24 @@ def test_rx_unknown_device(app, addr_ieee, addr_nwk, caplog):
168174

169175
@pytest.mark.asyncio
170176
async def test_form_network(app):
171-
app._api.change_network_state = mock.MagicMock(
172-
side_effect=asyncio.coroutine(mock.MagicMock())
173-
)
174-
app._api.device_state = mock.MagicMock(
175-
side_effect=asyncio.coroutine(mock.MagicMock())
177+
app._api.change_network_state = CoroutineMock()
178+
app._api.device_state = CoroutineMock(
179+
return_value=deconz_api.NetworkState.CONNECTED
176180
)
177181

178-
app._api._device_state = deconz_api.DeviceState(2)
182+
app._api._device_state = deconz_api.DeviceState(deconz_api.NetworkState.CONNECTED)
179183
await app.form_network()
180-
assert app._api.device_state.call_count == 0
184+
assert app._api.change_network_state.call_count == 0
185+
assert app._api.change_network_state.await_count == 0
186+
assert app._api.device_state.await_count == 0
181187

182-
app._api._device_state = deconz_api.DeviceState(0)
188+
app._api._device_state = deconz_api.DeviceState(deconz_api.NetworkState.OFFLINE)
183189
application.CHANGE_NETWORK_WAIT = 0.001
184190
with pytest.raises(Exception):
185191
await app.form_network()
192+
assert app._api.change_network_state.call_count == 1
193+
assert app._api.change_network_state.await_count == 1
194+
assert app._api.device_state.await_count == 10
186195
assert app._api.device_state.call_count == 10
187196

188197

@@ -195,26 +204,24 @@ async def _version():
195204
app._api._proto_ver = protocol_ver
196205
return [version]
197206

198-
app._reset_watchdog = mock.MagicMock(
199-
side_effect=asyncio.coroutine(mock.MagicMock())
200-
)
201-
app.form_network = mock.MagicMock(side_effect=asyncio.coroutine(mock.MagicMock()))
202-
app._api._command = mock.MagicMock(side_effect=asyncio.coroutine(mock.MagicMock()))
203-
app._api.read_parameter = mock.MagicMock(
204-
side_effect=asyncio.coroutine(mock.MagicMock(return_value=[[0]]))
205-
)
206-
app._api.version = mock.MagicMock(side_effect=_version)
207-
app._api.write_parameter = mock.MagicMock(
208-
side_effect=asyncio.coroutine(mock.MagicMock())
209-
)
207+
app._reset_watchdog = CoroutineMock()
208+
app.form_network = CoroutineMock()
209+
210+
app._api._command = CoroutineMock()
211+
api = deconz_api.Deconz(app, app._config[zigpy.config.CONF_DEVICE])
212+
api.connect = CoroutineMock()
213+
api._command = CoroutineMock()
214+
api.read_parameter = CoroutineMock(return_value=[[0]])
215+
api.version = mock.MagicMock(side_effect=_version)
216+
api.write_parameter = CoroutineMock()
210217

211-
new_mock = mock.MagicMock(side_effect=asyncio.coroutine(mock.MagicMock()))
212-
monkeypatch.setattr(application.ConBeeDevice, "new", new_mock)
213-
await app.startup(auto_form=False)
214-
assert app.form_network.call_count == 0
215-
assert app._reset_watchdog.call_count == watchdog_cc
216-
await app.startup(auto_form=True)
217-
assert app.form_network.call_count == 1
218+
monkeypatch.setattr(application.ConBeeDevice, "new", CoroutineMock())
219+
with mock.patch.object(application, "Deconz", return_value=api):
220+
await app.startup(auto_form=False)
221+
assert app.form_network.call_count == 0
222+
assert app._reset_watchdog.call_count == watchdog_cc
223+
await app.startup(auto_form=True)
224+
assert app.form_network.call_count == 1
218225

219226

220227
@pytest.mark.asyncio
@@ -514,16 +521,15 @@ async def test_mrequest_send_aps_data_error(app):
514521

515522

516523
@pytest.mark.asyncio
517-
@mock.patch.object(application, "WATCHDOG_TTL", new=1)
518524
async def test_reset_watchdog(app):
519525
"""Test watchdog."""
520-
with asynctest.patch.object(app._api, "write_parameter") as mock_api:
526+
with mock.patch.object(app._api, "write_parameter") as mock_api:
521527
dog = asyncio.ensure_future(app._reset_watchdog())
522528
await asyncio.sleep(0.3)
523529
dog.cancel()
524530
assert mock_api.call_count == 1
525531

526-
with asynctest.patch.object(app._api, "write_parameter") as mock_api:
532+
with mock.patch.object(app._api, "write_parameter") as mock_api:
527533
mock_api.side_effect = zigpy_deconz.exception.CommandError
528534
dog = asyncio.ensure_future(app._reset_watchdog())
529535
await asyncio.sleep(0.3)

tests/test_uart.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import pytest
44
import serial_asyncio
5+
from zigpy.config import CONF_DEVICE_PATH
56

67
from zigpy_deconz import uart
78

@@ -16,7 +17,6 @@ def gw():
1617
@pytest.mark.asyncio
1718
async def test_connect(monkeypatch):
1819
api = mock.MagicMock()
19-
portmock = mock.MagicMock()
2020

2121
async def mock_conn(loop, protocol_factory, **kwargs):
2222
protocol = protocol_factory()
@@ -25,7 +25,7 @@ async def mock_conn(loop, protocol_factory, **kwargs):
2525

2626
monkeypatch.setattr(serial_asyncio, "create_serial_connection", mock_conn)
2727

28-
await uart.connect(portmock, 57600, api)
28+
await uart.connect({CONF_DEVICE_PATH: "/dev/null"}, api)
2929

3030

3131
def test_send(gw):

zigpy_deconz/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# coding: utf-8
22
MAJOR_VERSION = 0
3-
MINOR_VERSION = 8
3+
MINOR_VERSION = 9
44
PATCH_VERSION = "0"
55
__short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION)
66
__version__ = "{}.{}".format(__short_version__, PATCH_VERSION)

0 commit comments

Comments
 (0)