Skip to content

Commit

Permalink
0.12.0 Release
Browse files Browse the repository at this point in the history
  • Loading branch information
Adminiuga committed Apr 15, 2020
2 parents a98eaac + 73d786f commit c3cfc2d
Show file tree
Hide file tree
Showing 11 changed files with 829 additions and 85 deletions.
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ These are XBee Zigbee based radios that have been tested with the [zigpy-xbee](h
- Digi XBee Series 2 (S2) modules. Note: These will need to be manually flashed with the Zigbee Coordinator API firmware via XCTU.
- Digi XBee Series 3 (xbee3-24) modules

# Releases of zigpy-xbee-homeassistant via PyPI
Tagged versions of zigpy-xbee-homeassistant are also released via PyPI
# Releases of zigpy-xbee via PyPI
Tagged versions of zigpy-xbee are also released via PyPI

- https://pypi.org/project/zigpy-xbee-homeassistant/
- https://pypi.org/project/zigpy-xbee-homeassistant/#history
- https://pypi.org/project/zigpy-xbee-homeassistant/#files
- https://pypi.org/project/zigpy-xbee/
- https://pypi.org/project/zigpy-xbee/#history
- https://pypi.org/project/zigpy-xbee/#files

# How to contribute

Expand Down
12 changes: 10 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
"""Setup module for zigpy-xbee"""

import os

from setuptools import find_packages, setup

import zigpy_xbee

this_directory = os.path.join(os.path.abspath(os.path.dirname(__file__)))
with open(os.path.join(this_directory, "README.md"), encoding="utf-8") as f:
long_description = f.read()

setup(
name="zigpy-xbee-homeassistant",
name="zigpy-xbee",
version=zigpy_xbee.__version__,
description="A library which communicates with XBee radios for zigpy",
long_description=long_description,
long_description_content_type="text/markdown",
url="http://github.com/zigpy/zigpy-xbee",
author="Russell Cloran",
author_email="rcloran@gmail.com",
license="GPL-3.0",
packages=find_packages(exclude=["*.tests"]),
install_requires=["pyserial-asyncio", "zigpy-homeassistant >= 0.17.0"],
install_requires=["pyserial-asyncio", "zigpy>= 0.20.a1"],
tests_require=["pytest"],
)
52 changes: 31 additions & 21 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,26 @@
import zigpy.exceptions

from zigpy_xbee import api as xbee_api, types as t, uart
import zigpy_xbee.config
from zigpy_xbee.zigbee.application import ControllerApplication

DEVICE_CONFIG = zigpy_xbee.config.SCHEMA_DEVICE(
{zigpy_xbee.config.CONF_DEVICE_PATH: "/dev/null"}
)


@pytest.fixture
def api():
api = xbee_api.XBee()
api = xbee_api.XBee(DEVICE_CONFIG)
api._uart = mock.MagicMock()
return api


@pytest.mark.asyncio
async def test_connect(monkeypatch):
api = xbee_api.XBee()
dev = mock.MagicMock()
monkeypatch.setattr(
uart, "connect", mock.MagicMock(side_effect=asyncio.coroutine(mock.MagicMock()))
)
await api.connect(dev, 115200)
api = xbee_api.XBee(DEVICE_CONFIG)
monkeypatch.setattr(uart, "connect", CoroutineMock())
await api.connect()


def test_close(api):
Expand Down Expand Up @@ -542,14 +544,13 @@ def test_handle_many_to_one_rri(api):

@pytest.mark.asyncio
async def test_reconnect_multiple_disconnects(monkeypatch, caplog):
api = xbee_api.XBee()
dev = mock.sentinel.uart
api = xbee_api.XBee(DEVICE_CONFIG)
connect_mock = CoroutineMock()
connect_mock.return_value = asyncio.Future()
connect_mock.return_value.set_result(True)
monkeypatch.setattr(uart, "connect", connect_mock)

await api.connect(dev, 115200)
await api.connect()

caplog.set_level(logging.DEBUG)
connected = asyncio.Future()
Expand All @@ -568,14 +569,13 @@ async def test_reconnect_multiple_disconnects(monkeypatch, caplog):

@pytest.mark.asyncio
async def test_reconnect_multiple_attempts(monkeypatch, caplog):
api = xbee_api.XBee()
dev = mock.sentinel.uart
api = xbee_api.XBee(DEVICE_CONFIG)
connect_mock = CoroutineMock()
connect_mock.return_value = asyncio.Future()
connect_mock.return_value.set_result(True)
monkeypatch.setattr(uart, "connect", connect_mock)

await api.connect(dev, 115200)
await api.connect()

caplog.set_level(logging.DEBUG)
connected = asyncio.Future()
Expand All @@ -597,11 +597,11 @@ async def test_reconnect_multiple_attempts(monkeypatch, caplog):
async def test_probe_success(mock_connect, mock_at_cmd):
"""Test device probing."""

res = await xbee_api.XBee.probe(mock.sentinel.uart, mock.sentinel.baud)
res = await xbee_api.XBee.probe(DEVICE_CONFIG)
assert res is True
assert mock_connect.call_count == 1
assert mock_connect.await_count == 1
assert mock_connect.call_args[0][0] is mock.sentinel.uart
assert mock_connect.call_args[0][0] == DEVICE_CONFIG
assert mock_at_cmd.call_count == 1
assert mock_connect.return_value.close.call_count == 1

Expand All @@ -613,11 +613,11 @@ async def test_probe_success(mock_connect, mock_at_cmd):
async def test_probe_success_api_mode(mock_connect, mock_at_cmd, mock_api_mode):
"""Test device probing."""

res = await xbee_api.XBee.probe(mock.sentinel.uart, mock.sentinel.baud)
res = await xbee_api.XBee.probe(DEVICE_CONFIG)
assert res is True
assert mock_connect.call_count == 1
assert mock_connect.await_count == 1
assert mock_connect.call_args[0][0] is mock.sentinel.uart
assert mock_connect.call_args[0][0] == DEVICE_CONFIG
assert mock_at_cmd.call_count == 1
assert mock_api_mode.call_count == 1
assert mock_connect.return_value.close.call_count == 1
Expand All @@ -638,11 +638,11 @@ async def test_probe_fail(mock_connect, mock_at_cmd, mock_api_mode, exception):
mock_api_mode.reset_mock()
mock_at_cmd.reset_mock()
mock_connect.reset_mock()
res = await xbee_api.XBee.probe(mock.sentinel.uart, mock.sentinel.baud)
res = await xbee_api.XBee.probe(DEVICE_CONFIG)
assert res is False
assert mock_connect.call_count == 1
assert mock_connect.await_count == 1
assert mock_connect.call_args[0][0] is mock.sentinel.uart
assert mock_connect.call_args[0][0] == DEVICE_CONFIG
assert mock_at_cmd.call_count == 1
assert mock_api_mode.call_count == 1
assert mock_connect.return_value.close.call_count == 1
Expand All @@ -658,11 +658,21 @@ async def test_probe_fail_api_mode(mock_connect, mock_at_cmd, mock_api_mode):
mock_api_mode.reset_mock()
mock_at_cmd.reset_mock()
mock_connect.reset_mock()
res = await xbee_api.XBee.probe(mock.sentinel.uart, mock.sentinel.baud)
res = await xbee_api.XBee.probe(DEVICE_CONFIG)
assert res is False
assert mock_connect.call_count == 1
assert mock_connect.await_count == 1
assert mock_connect.call_args[0][0] is mock.sentinel.uart
assert mock_connect.call_args[0][0] == DEVICE_CONFIG
assert mock_at_cmd.call_count == 1
assert mock_api_mode.call_count == 1
assert mock_connect.return_value.close.call_count == 1


@pytest.mark.asyncio
@mock.patch.object(xbee_api.XBee, "connect")
async def test_xbee_new(conn_mck):
"""Test new class method."""
api = await xbee_api.XBee.new(mock.sentinel.application, DEVICE_CONFIG)
assert isinstance(api, xbee_api.XBee)
assert conn_mck.call_count == 1
assert conn_mck.await_count == 1
47 changes: 24 additions & 23 deletions tests/test_application.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
import asyncio
from unittest import mock

from asynctest import CoroutineMock, mock
import pytest
from zigpy import types as t
from zigpy.zdo.types import ZDOCmd

from zigpy_xbee.api import ModemStatus, XBee
import zigpy_xbee.config as config
import zigpy_xbee.types as xbee_t
from zigpy_xbee.zigbee import application

APP_CONFIG = {
config.CONF_DEVICE: {
config.CONF_DEVICE_PATH: "/dev/null",
config.CONF_DEVICE_BAUDRATE: 115200,
},
config.CONF_DATABASE: None,
}


@pytest.fixture
def app(monkeypatch, database_file=None):
def app(monkeypatch):
monkeypatch.setattr(application, "TIMEOUT_TX_STATUS", 0.1)
monkeypatch.setattr(application, "TIMEOUT_REPLY", 0.1)
monkeypatch.setattr(application, "TIMEOUT_REPLY_EXTENDED", 0.1)
return application.ControllerApplication(XBee(), database_file=database_file)
app = application.ControllerApplication(APP_CONFIG)
api = XBee(APP_CONFIG[config.CONF_DEVICE])
monkeypatch.setattr(api, "_command", CoroutineMock())
app._api = api
return app


def test_modem_status(app):
Expand Down Expand Up @@ -188,11 +201,7 @@ async def test_broadcast(app):
b"\x02\x01\x00",
)

app._api._command = mock.MagicMock(
side_effect=asyncio.coroutine(
mock.MagicMock(return_value=xbee_t.TXStatus.SUCCESS)
)
)
app._api._command.return_value = xbee_t.TXStatus.SUCCESS

r = await app.broadcast(profile, cluster, src_ep, dst_ep, grpid, radius, tsn, data)
assert r[0] == xbee_t.TXStatus.SUCCESS
Expand All @@ -202,17 +211,11 @@ async def test_broadcast(app):
assert app._api._command.call_args[0][4] == dst_ep
assert app._api._command.call_args[0][9] == data

app._api._command = mock.MagicMock(
side_effect=asyncio.coroutine(
mock.MagicMock(return_value=xbee_t.TXStatus.ADDRESS_NOT_FOUND)
)
)
app._api._command.return_value = xbee_t.TXStatus.ADDRESS_NOT_FOUND
r = await app.broadcast(profile, cluster, src_ep, dst_ep, grpid, radius, tsn, data)
assert r[0] != xbee_t.TXStatus.SUCCESS

app._api._command = mock.MagicMock(
side_effect=asyncio.coroutine(mock.MagicMock(side_effect=asyncio.TimeoutError))
)
app._api._command.side_effect = asyncio.TimeoutError
r = await app.broadcast(profile, cluster, src_ep, dst_ep, grpid, radius, tsn, data)
assert r[0] != xbee_t.TXStatus.SUCCESS

Expand Down Expand Up @@ -304,19 +307,17 @@ async def _at_command_mock(cmd, *args):
"ZS": zs,
}.get(cmd, None)

app._api._at_command = mock.MagicMock(
spec=XBee._at_command, side_effect=_at_command_mock
)

async def init_api_mode_mock():
nonlocal api_mode
api_mode = api_config_succeeds
return api_config_succeeds

app._api.init_api_mode = mock.MagicMock(side_effect=init_api_mode_mock)
app.form_network = mock.MagicMock(side_effect=asyncio.coroutine(mock.MagicMock()))
app.form_network = CoroutineMock()

await app.startup(auto_form=auto_form)
with mock.patch.object(XBee, "new") as api:
api.return_value._at_command = CoroutineMock(side_effect=_at_command_mock)
api.return_value.init_api_mode = CoroutineMock(side_effect=init_api_mode_mock)
await app.startup(auto_form=auto_form)
return app


Expand Down
8 changes: 6 additions & 2 deletions tests/test_uart.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
import serial_asyncio

from zigpy_xbee import uart
import zigpy_xbee.config

DEVICE_CONFIG = zigpy_xbee.config.SCHEMA_DEVICE(
{zigpy_xbee.config.CONF_DEVICE_PATH: "/dev/null"}
)


@pytest.fixture
Expand All @@ -29,7 +34,6 @@ def test_baudrate_fail(gw):
@pytest.mark.asyncio
async def test_connect(monkeypatch):
api = mock.MagicMock()
portmock = mock.MagicMock()

async def mock_conn(loop, protocol_factory, **kwargs):
protocol = protocol_factory()
Expand All @@ -38,7 +42,7 @@ async def mock_conn(loop, protocol_factory, **kwargs):

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

await uart.connect(portmock, 57600, api)
await uart.connect(DEVICE_CONFIG, api)


def test_command_mode_rsp(gw):
Expand Down
2 changes: 1 addition & 1 deletion zigpy_xbee/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MAJOR_VERSION = 0
MINOR_VERSION = 11
MINOR_VERSION = 12
PATCH_VERSION = "0"
__short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION)
__version__ = "{}.{}".format(__short_version__, PATCH_VERSION)

0 comments on commit c3cfc2d

Please sign in to comment.