Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ repos:
rev: v3.15.0
hooks:
- id: pyupgrade
args: [--py38-plus]
args: [--py311-plus]

- repo: https://github.com/PyCQA/autoflake
rev: v2.2.1
Expand Down
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ authors = [
]
readme = "README.md"
license = {text = "GPL-3.0"}
requires-python = ">=3.8"
requires-python = ">=3.11"
dependencies = [
"zigpy>=0.70.0",
"zigpy>=2.0.0",
]

[tool.setuptools.packages.find]
Expand All @@ -23,7 +23,6 @@ exclude = ["tests", "tests.*"]
[project.optional-dependencies]
testing = [
"pytest>=7.1.2",
"asynctest>=0.13.0",
"pytest-asyncio>=0.19.0",
]

Expand Down
3 changes: 1 addition & 2 deletions requirements_test.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Test dependencies.

asynctest
isort
black
flake8
Expand All @@ -15,6 +14,6 @@ pytest-sugar
pytest-timeout
pytest-asyncio>=0.17
pytest>=7.1.3
zigpy>=0.56.0
zigpy>=2.0.0
ruff>=0.0.291
Flake8-pyproject
2 changes: 1 addition & 1 deletion tests/test_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ async def _test_start_network(
def _at_command_mock(cmd, *args):
nonlocal ai_tries
if not api_mode:
raise asyncio.TimeoutError
raise TimeoutError
if cmd == "CE" and legacy_module:
raise InvalidCommand

Expand Down
5 changes: 2 additions & 3 deletions tests/test_uart.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from unittest import mock

import pytest
import serial_asyncio_fast
import zigpy.config
import zigpy.serial

from zigpy_xbee import uart

Expand All @@ -22,7 +22,6 @@ def gw():
"""Gateway fixture."""
gw = uart.Gateway(mock.MagicMock())
gw._transport = mock.MagicMock()
gw._transport.serial.BAUDRATES = serial_asyncio_fast.serial.Serial.BAUDRATES
return gw


Expand All @@ -48,7 +47,7 @@ async def mock_conn(loop, protocol_factory, **kwargs):
loop.call_soon(protocol.connection_made, None)
return None, protocol

monkeypatch.setattr(serial_asyncio_fast, "create_serial_connection", mock_conn)
monkeypatch.setattr(zigpy.serial, "create_serial_connection", mock_conn)

await uart.connect(DEVICE_CONFIG, api)

Expand Down
36 changes: 0 additions & 36 deletions tox.ini

This file was deleted.

16 changes: 8 additions & 8 deletions zigpy_xbee/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import binascii
import functools
import logging
from typing import Any, Dict, Optional
from typing import Any

from zigpy.exceptions import APIException, DeliveryError
import zigpy.types as t
Expand Down Expand Up @@ -274,15 +274,15 @@
class XBee:
"""Class implementing XBee communication protocol."""

def __init__(self, device_config: Dict[str, Any]) -> None:
def __init__(self, device_config: dict[str, Any]) -> None:
"""Initialize instance."""
self._config = device_config
self._uart: Optional[uart.Gateway] = None
self._uart: uart.Gateway | None = None
self._seq: int = 1
self._commands_by_id = {v[0]: k for k, v in COMMAND_RESPONSES.items()}
self._awaiting = {}
self._app = None
self._cmd_mode_future: Optional[asyncio.Future] = None
self._cmd_mode_future: asyncio.Future | None = None
self._reset: asyncio.Event = asyncio.Event()
self._running: asyncio.Event = asyncio.Event()

Expand Down Expand Up @@ -310,7 +310,7 @@
try:
# Ensure we have escaped commands
await self._at_command("AP", 2)
except asyncio.TimeoutError:
except TimeoutError:
if not await self.init_api_mode():
raise APIException("Failed to configure XBee for API mode")
except Exception:
Expand All @@ -320,7 +320,7 @@
def connection_lost(self, exc: Exception) -> None:
"""Lost serial connection."""
if self._app is not None:
self._app.connection_lost(exc)

Check warning on line 323 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.11

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 323 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 323 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 323 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

async def disconnect(self):
"""Close the connection."""
Expand Down Expand Up @@ -354,7 +354,7 @@
),
timeout=REMOTE_AT_COMMAND_TIMEOUT,
)
except asyncio.TimeoutError:
except TimeoutError:
LOGGER.warning("No response to %s command", name)
raise

Expand All @@ -366,7 +366,7 @@
self._command(cmd_type, name.encode("ascii"), data),
timeout=AT_COMMAND_TIMEOUT,
)
except asyncio.TimeoutError:
except TimeoutError:
LOGGER.warning("%s: No response to %s command", cmd_type, name)
raise

Expand Down Expand Up @@ -507,12 +507,12 @@
async def command_mode_at_cmd(self, command):
"""Send AT command in command mode."""
self._cmd_mode_future = asyncio.Future()
self._uart.command_mode_send(command.encode("ascii"))

Check warning on line 510 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.11

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 510 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 510 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 510 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

try:
res = await asyncio.wait_for(self._cmd_mode_future, timeout=2)
return res
except asyncio.TimeoutError:
except TimeoutError:
LOGGER.debug("Command mode no response to AT '%s' command", command)
return None

Expand All @@ -534,7 +534,7 @@
LOGGER.debug("No response to %s cmd", cmd)
return None
LOGGER.debug("Successfully sent %s cmd", cmd)
self._uart.reset_command_mode()

Check warning on line 537 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.11

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 537 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.12

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 537 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.14

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited

Check warning on line 537 in zigpy_xbee/api.py

View workflow job for this annotation

GitHub Actions / shared-ci / Run tests Python 3.13

coroutine 'AsyncMockMixin._execute_mock_call' was never awaited
return True

async def init_api_mode(self):
Expand Down
46 changes: 40 additions & 6 deletions zigpy_xbee/uart.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import asyncio
import logging
from typing import Any, Dict
from typing import Any

import zigpy.config
import zigpy.serial
Expand All @@ -21,6 +21,42 @@ class Gateway(zigpy.serial.SerialProtocol):
RESERVED = START + ESCAPE + XON + XOFF
THIS_ONE = True

# Standard baudrates, previously sourced from the underlying serial library.
# zigpy now uses `serialx`, which does not expose a `BAUDRATES` attribute, so
# the list is kept here to avoid depending on the serial backend.
BAUDRATES = (
50,
75,
110,
134,
150,
200,
300,
600,
1200,
1800,
2400,
4800,
9600,
19200,
38400,
57600,
115200,
230400,
460800,
500000,
576000,
921600,
1000000,
1152000,
1500000,
2000000,
2500000,
3000000,
3500000,
4000000,
)

def __init__(self, api):
"""Initialize instance."""
super().__init__()
Expand All @@ -44,12 +80,10 @@ def baudrate(self):
@baudrate.setter
def baudrate(self, baudrate):
"""Set baudrate."""
if baudrate in self._transport.serial.BAUDRATES:
if baudrate in self.BAUDRATES:
self._transport.serial.baudrate = baudrate
else:
raise ValueError(
f"baudrate must be one of {self._transport.serial.BAUDRATES}"
)
raise ValueError(f"baudrate must be one of {self.BAUDRATES}")

def connection_lost(self, exc) -> None:
"""Port was closed expectedly or unexpectedly."""
Expand Down Expand Up @@ -148,7 +182,7 @@ def _checksum(self, data):
return 0xFF - (sum(data) % 0x100)


async def connect(device_config: Dict[str, Any], api) -> Gateway:
async def connect(device_config: dict[str, Any], api) -> Gateway:
"""Connect to the device."""
transport, protocol = await zigpy.serial.create_serial_connection(
loop=asyncio.get_running_loop(),
Expand Down
Loading