Skip to content

Commit c53be77

Browse files
authored
Implement many_to_one_rri handler. (#34)
* Swallow exceptions for non existent handlers. * Handler for 'many_to_one_rri' frames. * NWK class with default hex representation.
1 parent 03fe973 commit c53be77

File tree

4 files changed

+55
-7
lines changed

4 files changed

+55
-7
lines changed

tests/test_api.py

+25
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,25 @@ def test_frame_received(api, monkeypatch):
155155
my_handler.reset_mock()
156156

157157

158+
def test_frame_received_no_handler(api, monkeypatch):
159+
monkeypatch.setattr(t, 'deserialize', mock.MagicMock(
160+
return_value=(b'deserialized data', b'')))
161+
my_handler = mock.MagicMock()
162+
cmd = 'no_handler'
163+
cmd_id = 0x00
164+
xbee_api.COMMANDS[cmd] = (cmd_id, (), None)
165+
api._commands_by_id[cmd_id] = cmd
166+
167+
cmd_opts = xbee_api.COMMANDS[cmd]
168+
cmd_id = cmd_opts[0]
169+
payload = b'\x01\x02\x03\x04'
170+
data = cmd_id.to_bytes(1, 'big') + payload
171+
api.frame_received(data)
172+
assert t.deserialize.call_count == 1
173+
assert t.deserialize.call_args[0][0] == payload
174+
assert my_handler.call_count == 0
175+
176+
158177
def _handle_at_response(api, tsn, status, at_response=b''):
159178
data = (tsn, 'AI'.encode('ascii'), status, at_response)
160179
response = asyncio.Future()
@@ -346,3 +365,9 @@ def test_set_application(api):
346365

347366
def test_handle_route_record_indicator(api):
348367
api._handle_route_record_indicator(mock.sentinel.ri)
368+
369+
370+
def test_handle_many_to_one_rri(api):
371+
ieee = t.EUI64([t.uint8_t(a) for a in range(0, 8)])
372+
nwk = 0x1234
373+
api._handle_many_to_one_rri([ieee, nwk, 0])

tests/test_types.py

+7
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,10 @@ class undEnum(t.uint8_t, t.UndefinedEnum):
7171

7272
with pytest.raises(ValueError):
7373
undEnum(0xEE)
74+
75+
76+
def test_nwk():
77+
nwk = t.NWK(0x1234)
78+
79+
assert str(nwk) == '0x1234'
80+
assert repr(nwk) == '0x1234'

zigpy_xbee/api.py

+15-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import binascii
23
import enum
34
import logging
45

@@ -32,21 +33,21 @@ class ModemStatus(t.uint8_t, t.UndefinedEnum):
3233
'queued_at': (0x09, (t.uint8_t, t.ATCommand, t.Bytes), 0x88),
3334
'remote_at': (0x17, (), None),
3435
'tx': (0x10, (), None),
35-
'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),
36-
'create_source_route': (0x21, (), None),
36+
'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),
37+
'create_source_route': (0x21, (t.uint8_t, t.EUI64, t.NWK, t.uint8_t, LVList(t.NWK)), None),
3738
'register_joining_device': (0x24, (), None),
3839

3940
'at_response': (0x88, (t.uint8_t, t.ATCommand, t.uint8_t, t.Bytes), None),
4041
'modem_status': (0x8A, (ModemStatus, ), None),
41-
'tx_status': (0x8B, (t.uint8_t, t.uint16_t, t.uint8_t, t.uint8_t, t.uint8_t), None),
42+
'tx_status': (0x8B, (t.uint8_t, t.NWK, t.uint8_t, t.uint8_t, t.uint8_t), None),
4243
'route_information': (0x8D, (), None),
4344
'rx': (0x90, (), None),
44-
'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),
45+
'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),
4546
'rx_io_data_long_addr': (0x92, (), None),
4647
'remote_at_response': (0x97, (), None),
4748
'extended_status': (0x98, (), None),
48-
'route_record_indicator': (0xA1, (t.EUI64, t.uint16_t, t.uint8_t, LVList(t.uint16_t)), None),
49-
'many_to_one_rri': (0xA3, (), None),
49+
'route_record_indicator': (0xA1, (t.EUI64, t.NWK, t.uint8_t, LVList(t.NWK)), None),
50+
'many_to_one_rri': (0xA3, (t.EUI64, t.NWK, t.uint8_t), None),
5051
'node_id_indicator': (0x95, (), None),
5152

5253
}
@@ -261,7 +262,11 @@ def frame_received(self, data):
261262
command = self._commands_by_id[data[0]]
262263
LOGGER.debug("Frame received: %s", command)
263264
data, rest = t.deserialize(data[1:], COMMANDS[command][1])
264-
getattr(self, '_handle_%s' % (command, ))(data)
265+
try:
266+
getattr(self, '_handle_%s' % (command, ))(data)
267+
except AttributeError:
268+
LOGGER.error("No '%s' handler. Data: %s", command,
269+
binascii.hexlify(data))
265270

266271
def _handle_at_response(self, data):
267272
fut, = self._awaiting.pop(data[0])
@@ -283,6 +288,9 @@ def _handle_at_response(self, data):
283288
response, remains = response_type.deserialize(data[3])
284289
fut.set_result(response)
285290

291+
def _handle_many_to_one_rri(self, data):
292+
LOGGER.debug("_handle_many_to_one_rri: %s", data)
293+
286294
def _handle_modem_status(self, data):
287295
LOGGER.debug("Handle modem status frame: %s", data)
288296
status = data[0]

zigpy_xbee/types.py

+8
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,11 @@ def __call__(cls, value=None, *args, **kwargs):
147147

148148
class UndefinedEnum(enum.Enum, metaclass=UndefinedEnumMeta):
149149
pass
150+
151+
152+
class NWK(uint16_t):
153+
def __repr__(self):
154+
return '0x{:04x}'.format(self)
155+
156+
def __str__(self):
157+
return '0x{:04x}'.format(self)

0 commit comments

Comments
 (0)