Skip to content

Commit

Permalink
Merge branch 'master' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Adminiuga committed May 5, 2019
2 parents 94abd57 + e41ce4a commit a2753a7
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 14 deletions.
13 changes: 12 additions & 1 deletion bellows/zigbee/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
from bellows.exception import ControllerError, EzspError

APS_ACK_TIMEOUT = 120
APS_REPLY_TIMEOUT = 10
APS_REPLY_TIMEOUT = 5
APS_REPLY_TIMEOUT_EXTENDED = 28
MAX_WATCHDOG_FAILURES = 4
RESET_ATTEMPT_BACKOFF_TIME = 5
WATCHDOG_WAKE_PERIOD = 10
Expand Down Expand Up @@ -125,6 +126,11 @@ async def startup(self, auto_form=False):
ieee = await e.getEui64()
self._ieee = ieee[0]

dev = self.add_device(self._ieee, self._nwk)
dev.node_desc = zigpy.zdo.types.NodeDescriptor(
0, 0, 0b00001110, 0, 0, 0, 0, 0, 0)
LOGGER.debug("EZSP nwk=0x%04x, IEEE=%s", self._nwk, str(self._ieee))

e.add_callback(self.ezsp_callback_handler)
self.controller_event.set()
self._watchdog_task = asyncio.ensure_future(self._watchdog())
Expand Down Expand Up @@ -331,6 +337,11 @@ async def request(self, nwk, profile, cluster, src_ep, dst_ep, sequence, data, e
aps_frame.groupId = t.uint16_t(0)
aps_frame.sequence = t.uint8_t(sequence)

dev = self.get_device(nwk=nwk)
if dev.node_desc.is_end_device:
LOGGER.debug("Extending timeout for %s/0x%04x", dev.ieee, nwk)
await self._ezsp.setExtendedTimeout(dev.ieee, True)
timeout = APS_REPLY_TIMEOUT_EXTENDED
with self._pending.new(sequence, expect_reply) as req:
async with self._in_flight_msg:
res = await self._ezsp.sendUnicast(self.direct, nwk, aps_frame,
Expand Down
46 changes: 33 additions & 13 deletions tests/test_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import bellows.types as t
import bellows.zigbee.application
from bellows.exception import ControllerError, EzspError
from zigpy.device import Device
from zigpy.exceptions import DeliveryError


Expand Down Expand Up @@ -43,7 +44,7 @@ async def mock_coro(*args, **kwargs):
return mock.Mock(wraps=mock_coro)


def _test_startup(app, nwk_type, auto_form=False, init=0):
def _test_startup(app, nwk_type, ieee, auto_form=False, init=0):
async def mockezsp(*args, **kwargs):
return [0, nwk_type]

Expand All @@ -58,7 +59,8 @@ async def mockinit(*args, **kwargs):
app._ezsp.getNetworkParameters = mockezsp
app._ezsp.setPolicy = mockezsp
app._ezsp.getNodeId = mockezsp
app._ezsp.getEui64 = mockezsp
app._ezsp.getEui64.side_effect = asyncio.coroutine(
mock.MagicMock(return_value=[ieee]))
app._ezsp.leaveNetwork = mockezsp
app.form_network = mock.MagicMock(side_effect=asyncio.coroutine(mock.MagicMock()))
app._ezsp.reset.side_effect = asyncio.coroutine(mock.MagicMock())
Expand All @@ -70,26 +72,26 @@ async def mockinit(*args, **kwargs):
loop.run_until_complete(app.startup(auto_form=auto_form))


def test_startup(app):
return _test_startup(app, t.EmberNodeType.COORDINATOR)
def test_startup(app, ieee):
return _test_startup(app, t.EmberNodeType.COORDINATOR, ieee)


def test_startup_no_status(app):
def test_startup_no_status(app, ieee):
with pytest.raises(Exception):
return _test_startup(app, None, init=1)
return _test_startup(app, None, ieee, init=1)


def test_startup_no_status_form(app):
return _test_startup(app, None, auto_form=True, init=1)
def test_startup_no_status_form(app, ieee):
return _test_startup(app, None, ieee, auto_form=True, init=1)


def test_startup_end(app):
def test_startup_end(app, ieee):
with pytest.raises(Exception):
return _test_startup(app, t.EmberNodeType.SLEEPY_END_DEVICE)
return _test_startup(app, t.EmberNodeType.SLEEPY_END_DEVICE, ieee)


def test_startup_end_form(app):
return _test_startup(app, t.EmberNodeType.SLEEPY_END_DEVICE, True)
def test_startup_end_form(app, ieee):
return _test_startup(app, t.EmberNodeType.SLEEPY_END_DEVICE, ieee, True)


def test_form_network(app):
Expand Down Expand Up @@ -318,7 +320,8 @@ def test_permit_with_key_failed_set_policy(app, ieee):


def _request(app, returnvals, do_reply=True, send_ack_received=True,
send_ack_success=True, ezsp_operational=True, **kwargs):
send_ack_success=True, ezsp_operational=True, is_an_end_dev=None,
**kwargs):
async def mocksend(method, nwk, aps_frame, seq, data):
if not ezsp_operational:
raise EzspError
Expand All @@ -334,6 +337,13 @@ async def mocksend(method, nwk, aps_frame, seq, data):
req.reply.set_result(mock.sentinel.result)
return [returnvals.pop(0)]

def mock_get_device(*args, **kwargs):
dev = Device(app, mock.sentinel.ieee, mock.sentinel.nwk)
dev.node_desc = mock.MagicMock()
dev.node_desc.is_end_device = is_an_end_dev
return dev

app.get_device = mock_get_device
app._ezsp.sendUnicast = mocksend
loop = asyncio.get_event_loop()
res = loop.run_until_complete(app.request(0x1234, 9, 8, 7, 6, 5, b'', **kwargs))
Expand Down Expand Up @@ -413,6 +423,16 @@ def test_request_ctrl_not_running(app):
_request(app, [0], do_reply=False, expect_reply=True, timeout=0.1)


def test_request_extended_timeout(app):
app._ezsp.setExtendedTimeout.side_effect = asyncio.coroutine(
mock.MagicMock())
assert _request(app, [0], is_an_end_dev=False) == mock.sentinel.result
assert app._ezsp.setExtendedTimeout.call_count == 0

assert _request(app, [0], is_an_end_dev=True) == mock.sentinel.result
assert app._ezsp.setExtendedTimeout.call_count == 1


@pytest.mark.asyncio
async def _test_broadcast(app, broadcast_success=True, send_timeout=False,
ezsp_running=True):
Expand Down

0 comments on commit a2753a7

Please sign in to comment.