From 01b65cc81c66785b332ef2c0849c923a9c987b36 Mon Sep 17 00:00:00 2001 From: Alexei Chetroi Date: Thu, 28 Mar 2019 12:15:39 -0400 Subject: [PATCH 1/3] Swallow exceptions for non existent handlers. --- tests/test_api.py | 19 +++++++++++++++++++ zigpy_xbee/api.py | 7 ++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/test_api.py b/tests/test_api.py index 7e1bf04..9ba254e 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -155,6 +155,25 @@ def test_frame_received(api, monkeypatch): my_handler.reset_mock() +def test_frame_received_no_handler(api, monkeypatch): + monkeypatch.setattr(t, 'deserialize', mock.MagicMock( + return_value=(b'deserialized data', b''))) + my_handler = mock.MagicMock() + cmd = 'no_handler' + cmd_id = 0x00 + xbee_api.COMMANDS[cmd] = (cmd_id, (), None) + api._commands_by_id[cmd_id] = cmd + + cmd_opts = xbee_api.COMMANDS[cmd] + cmd_id = cmd_opts[0] + payload = b'\x01\x02\x03\x04' + data = cmd_id.to_bytes(1, 'big') + payload + api.frame_received(data) + assert t.deserialize.call_count == 1 + assert t.deserialize.call_args[0][0] == payload + assert my_handler.call_count == 0 + + def _handle_at_response(api, tsn, status, at_response=b''): data = (tsn, 'AI'.encode('ascii'), status, at_response) response = asyncio.Future() diff --git a/zigpy_xbee/api.py b/zigpy_xbee/api.py index 129e757..d1e6a88 100644 --- a/zigpy_xbee/api.py +++ b/zigpy_xbee/api.py @@ -1,4 +1,5 @@ import asyncio +import binascii import enum import logging @@ -261,7 +262,11 @@ def frame_received(self, data): command = self._commands_by_id[data[0]] LOGGER.debug("Frame received: %s", command) data, rest = t.deserialize(data[1:], COMMANDS[command][1]) - getattr(self, '_handle_%s' % (command, ))(data) + try: + getattr(self, '_handle_%s' % (command, ))(data) + except AttributeError: + LOGGER.error("No '%s' handler. Data: %s", command, + binascii.hexlify(data)) def _handle_at_response(self, data): fut, = self._awaiting.pop(data[0]) From 032a308a137804cbe2841a5ea95704c7c9085add Mon Sep 17 00:00:00 2001 From: Alexei Chetroi Date: Thu, 28 Mar 2019 13:15:52 -0400 Subject: [PATCH 2/3] Handler for 'many_to_one_rri' frames. --- tests/test_api.py | 6 ++++++ zigpy_xbee/api.py | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 9ba254e..3cc3df5 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -365,3 +365,9 @@ def test_set_application(api): def test_handle_route_record_indicator(api): api._handle_route_record_indicator(mock.sentinel.ri) + + +def test_handle_many_to_one_rri(api): + ieee = t.EUI64([t.uint8_t(a) for a in range(0, 8)]) + nwk = 0x1234 + api._handle_many_to_one_rri([ieee, nwk, 0]) diff --git a/zigpy_xbee/api.py b/zigpy_xbee/api.py index d1e6a88..6131ed3 100644 --- a/zigpy_xbee/api.py +++ b/zigpy_xbee/api.py @@ -34,7 +34,7 @@ class ModemStatus(t.uint8_t, t.UndefinedEnum): 'remote_at': (0x17, (), None), 'tx': (0x10, (), None), 'tx_explicit': (0x11, (t.uint8_t, t.EUI64, t.uint16_t, t.uint8_t, t.uint8_t, t.uint16_t, t.uint16_t, t.uint8_t, t.uint8_t, t.Bytes), None), - 'create_source_route': (0x21, (), None), + 'create_source_route': (0x21, (t.uint8_t, t.EUI64, t.uint16_t, t.uint8_t, LVList(t.uint16_t)), None), 'register_joining_device': (0x24, (), None), 'at_response': (0x88, (t.uint8_t, t.ATCommand, t.uint8_t, t.Bytes), None), @@ -47,7 +47,7 @@ class ModemStatus(t.uint8_t, t.UndefinedEnum): 'remote_at_response': (0x97, (), None), 'extended_status': (0x98, (), None), 'route_record_indicator': (0xA1, (t.EUI64, t.uint16_t, t.uint8_t, LVList(t.uint16_t)), None), - 'many_to_one_rri': (0xA3, (), None), + 'many_to_one_rri': (0xA3, (t.EUI64, t.uint16_t, t.uint8_t), None), 'node_id_indicator': (0x95, (), None), } @@ -288,6 +288,9 @@ def _handle_at_response(self, data): response, remains = response_type.deserialize(data[3]) fut.set_result(response) + def _handle_many_to_one_rri(self, data): + LOGGER.debug("_handle_many_to_one_rri: %s", data) + def _handle_modem_status(self, data): LOGGER.debug("Handle modem status frame: %s", data) status = data[0] From ebe00371b34d81b55a74175d2c6217228cbe436e Mon Sep 17 00:00:00 2001 From: Alexei Chetroi Date: Thu, 28 Mar 2019 13:37:50 -0400 Subject: [PATCH 3/3] NWK class with default hex representation. --- tests/test_types.py | 7 +++++++ zigpy_xbee/api.py | 12 ++++++------ zigpy_xbee/types.py | 8 ++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/tests/test_types.py b/tests/test_types.py index c3c6dac..48cdcd7 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -71,3 +71,10 @@ class undEnum(t.uint8_t, t.UndefinedEnum): with pytest.raises(ValueError): undEnum(0xEE) + + +def test_nwk(): + nwk = t.NWK(0x1234) + + assert str(nwk) == '0x1234' + assert repr(nwk) == '0x1234' diff --git a/zigpy_xbee/api.py b/zigpy_xbee/api.py index 6131ed3..dbce120 100644 --- a/zigpy_xbee/api.py +++ b/zigpy_xbee/api.py @@ -33,21 +33,21 @@ class ModemStatus(t.uint8_t, t.UndefinedEnum): 'queued_at': (0x09, (t.uint8_t, t.ATCommand, t.Bytes), 0x88), 'remote_at': (0x17, (), None), 'tx': (0x10, (), None), - 'tx_explicit': (0x11, (t.uint8_t, t.EUI64, t.uint16_t, t.uint8_t, t.uint8_t, t.uint16_t, t.uint16_t, t.uint8_t, t.uint8_t, t.Bytes), None), - 'create_source_route': (0x21, (t.uint8_t, t.EUI64, t.uint16_t, t.uint8_t, LVList(t.uint16_t)), None), + 'tx_explicit': (0x11, (t.uint8_t, t.EUI64, t.NWK, t.uint8_t, t.uint8_t, t.uint16_t, t.uint16_t, t.uint8_t, t.uint8_t, t.Bytes), None), + 'create_source_route': (0x21, (t.uint8_t, t.EUI64, t.NWK, t.uint8_t, LVList(t.NWK)), None), 'register_joining_device': (0x24, (), None), 'at_response': (0x88, (t.uint8_t, t.ATCommand, t.uint8_t, t.Bytes), None), 'modem_status': (0x8A, (ModemStatus, ), None), - 'tx_status': (0x8B, (t.uint8_t, t.uint16_t, t.uint8_t, t.uint8_t, t.uint8_t), None), + 'tx_status': (0x8B, (t.uint8_t, t.NWK, t.uint8_t, t.uint8_t, t.uint8_t), None), 'route_information': (0x8D, (), None), 'rx': (0x90, (), None), - 'explicit_rx_indicator': (0x91, (t.EUI64, t.uint16_t, t.uint8_t, t.uint8_t, t.uint16_t, t.uint16_t, t.uint8_t, t.Bytes), None), + 'explicit_rx_indicator': (0x91, (t.EUI64, t.NWK, t.uint8_t, t.uint8_t, t.uint16_t, t.uint16_t, t.uint8_t, t.Bytes), None), 'rx_io_data_long_addr': (0x92, (), None), 'remote_at_response': (0x97, (), None), 'extended_status': (0x98, (), None), - 'route_record_indicator': (0xA1, (t.EUI64, t.uint16_t, t.uint8_t, LVList(t.uint16_t)), None), - 'many_to_one_rri': (0xA3, (t.EUI64, t.uint16_t, t.uint8_t), None), + 'route_record_indicator': (0xA1, (t.EUI64, t.NWK, t.uint8_t, LVList(t.NWK)), None), + 'many_to_one_rri': (0xA3, (t.EUI64, t.NWK, t.uint8_t), None), 'node_id_indicator': (0x95, (), None), } diff --git a/zigpy_xbee/types.py b/zigpy_xbee/types.py index 7b7a868..be3ac13 100644 --- a/zigpy_xbee/types.py +++ b/zigpy_xbee/types.py @@ -147,3 +147,11 @@ def __call__(cls, value=None, *args, **kwargs): class UndefinedEnum(enum.Enum, metaclass=UndefinedEnumMeta): pass + + +class NWK(uint16_t): + def __repr__(self): + return '0x{:04x}'.format(self) + + def __str__(self): + return '0x{:04x}'.format(self)