Skip to content

Commit 2413670

Browse files
committed
Use specific exceptions for AT command responses
1 parent 367fed5 commit 2413670

File tree

5 files changed

+57
-20
lines changed

5 files changed

+57
-20
lines changed

tests/test_api.py

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

1111
from zigpy_xbee import api as xbee_api, types as xbee_t, uart
1212
import zigpy_xbee.config
13+
from zigpy_xbee.exceptions import ATCommandError, ATCommandException, InvalidCommand
1314
from zigpy_xbee.zigbee.application import ControllerApplication
1415

1516
import tests.async_mock as mock
@@ -327,7 +328,16 @@ def test_handle_at_response_error(api):
327328
status, response = 1, 0x23
328329
fut = _handle_at_response(api, tsn, status, [response])
329330
assert fut.done() is True
330-
assert fut.exception() is not None
331+
assert isinstance(fut.exception(), ATCommandError)
332+
333+
334+
def test_handle_at_response_invalid_command(api):
335+
"""Test invalid AT command response."""
336+
tsn = 123
337+
status, response = 2, 0x23
338+
fut = _handle_at_response(api, tsn, status, [response])
339+
assert fut.done() is True
340+
assert isinstance(fut.exception(), InvalidCommand)
331341

332342

333343
def test_handle_at_response_undef_error(api):
@@ -336,7 +346,7 @@ def test_handle_at_response_undef_error(api):
336346
status, response = 0xEE, 0x23
337347
fut = _handle_at_response(api, tsn, status, [response])
338348
assert fut.done() is True
339-
assert fut.exception() is not None
349+
assert isinstance(fut.exception(), ATCommandException)
340350

341351

342352
def test_handle_remote_at_rsp(api):

tests/test_application.py

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

1212
from zigpy_xbee.api import XBee
1313
import zigpy_xbee.config as config
14+
from zigpy_xbee.exceptions import InvalidCommand
1415
import zigpy_xbee.types as xbee_t
1516
from zigpy_xbee.zigbee import application
1617

@@ -305,7 +306,7 @@ async def test_write_network_info(app, node_info, network_info, legacy_module):
305306

306307
def _mock_queued_at(name, *args):
307308
if legacy_module and name == "CE":
308-
raise RuntimeError("Legacy module")
309+
raise InvalidCommand("Legacy module")
309310
return "OK"
310311

311312
app._api._queued_at = mock.AsyncMock(
@@ -346,7 +347,7 @@ def _at_command_mock(cmd, *args):
346347
if not api_mode:
347348
raise asyncio.TimeoutError
348349
if cmd == "CE" and legacy_module:
349-
raise RuntimeError
350+
raise InvalidCommand
350351

351352
ai_tries -= 1 if cmd == "AI" else 0
352353
return {

zigpy_xbee/api.py

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

33
import asyncio
44
import binascii
5-
import enum
65
import functools
76
import logging
87
from typing import Any, Dict, Optional
@@ -13,6 +12,13 @@
1312

1413
import zigpy_xbee
1514
from zigpy_xbee.config import CONF_DEVICE_BAUDRATE, CONF_DEVICE_PATH, SCHEMA_DEVICE
15+
from zigpy_xbee.exceptions import (
16+
ATCommandError,
17+
ATCommandException,
18+
InvalidCommand,
19+
InvalidParameter,
20+
TransmissionFailure,
21+
)
1622

1723
from . import types as xbee_t, uart
1824

@@ -261,14 +267,12 @@
261267
}
262268

263269

264-
class ATCommandResult(enum.IntEnum):
265-
"""AT Command Result."""
266-
267-
OK = 0
268-
ERROR = 1
269-
INVALID_COMMAND = 2
270-
INVALID_PARAMETER = 3
271-
TX_FAILURE = 4
270+
AT_COMMAND_RESULT = {
271+
1: ATCommandError,
272+
2: InvalidCommand,
273+
3: InvalidParameter,
274+
4: TransmissionFailure,
275+
}
272276

273277

274278
class XBee:
@@ -444,13 +448,13 @@ def frame_received(self, data):
444448
def _handle_at_response(self, frame_id, cmd, status, value):
445449
"""Local AT command response."""
446450
(fut,) = self._awaiting.pop(frame_id)
447-
try:
448-
status = ATCommandResult(status)
449-
except ValueError:
450-
status = ATCommandResult.ERROR
451451

452452
if status:
453-
fut.set_exception(RuntimeError(f"AT Command response: {status.name}"))
453+
try:
454+
exception = AT_COMMAND_RESULT[status]
455+
except KeyError:
456+
exception = ATCommandException
457+
fut.set_exception(exception(f"AT Command response: {status}"))
454458
return
455459

456460
response_type = AT_COMMANDS[cmd.decode("ascii")]

zigpy_xbee/exceptions.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""Additional exceptions for XBee."""
2+
3+
4+
class ATCommandException(Exception):
5+
"""Base exception class for AT Command exceptions."""
6+
7+
8+
class ATCommandError(ATCommandException):
9+
"""Exception for AT Command Status 1 (ERROR)."""
10+
11+
12+
class InvalidCommand(ATCommandException):
13+
"""Exception for AT Command Status 2 (Invalid command)."""
14+
15+
16+
class InvalidParameter(ATCommandException):
17+
"""Exception for AT Command Status 3 (Invalid parameter)."""
18+
19+
20+
class TransmissionFailure(ATCommandException):
21+
"""Exception for Remote AT Command Status 4 (Transmission failure)."""

zigpy_xbee/zigbee/application.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import zigpy_xbee
2424
import zigpy_xbee.api
2525
from zigpy_xbee.config import CONF_DEVICE, CONFIG_SCHEMA, SCHEMA_DEVICE
26+
from zigpy_xbee.exceptions import InvalidCommand
2627
from zigpy_xbee.types import EUI64, UNKNOWN_IEEE, UNKNOWN_NWK, TXOptions, TXStatus
2728

2829
# how long coordinator would hold message for an end device in 10ms units
@@ -131,7 +132,7 @@ async def load_network_info(self, *, load_devices=False):
131132
node_info.logical_type = zdo_t.LogicalType.Coordinator
132133
else:
133134
node_info.logical_type = zdo_t.LogicalType.EndDevice
134-
except RuntimeError:
135+
except InvalidCommand:
135136
LOGGER.warning("CE command failed, assuming node is coordinator")
136137
node_info.logical_type = zdo_t.LogicalType.Coordinator
137138

@@ -171,7 +172,7 @@ async def write_network_info(self, *, network_info, node_info):
171172

172173
try:
173174
await self._api._queued_at("CE", 1)
174-
except RuntimeError:
175+
except InvalidCommand:
175176
pass
176177

177178
await self._api._at_command("WR")

0 commit comments

Comments
 (0)