Skip to content

Commit 60ce36a

Browse files
committed
Sync up with zigpy 0.60.0
1 parent 626bce6 commit 60ce36a

File tree

8 files changed

+32
-141
lines changed

8 files changed

+32
-141
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ readme = "README.md"
1414
license = {text = "GPL-3.0"}
1515
requires-python = ">=3.8"
1616
dependencies = [
17-
"zigpy>=0.56.0",
17+
"zigpy>=0.60.0",
1818
]
1919

2020
[tool.setuptools.packages.find]

tests/test_api.py

Lines changed: 6 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
"""Tests for API."""
22

33
import asyncio
4-
import logging
54

65
import pytest
76
import serial
7+
import zigpy.config
88
import zigpy.exceptions
99
import zigpy.types as t
1010

1111
from zigpy_xbee import api as xbee_api, types as xbee_t, uart
12-
import zigpy_xbee.config
1312
from zigpy_xbee.exceptions import ATCommandError, ATCommandException, InvalidCommand
1413
from zigpy_xbee.zigbee.application import ControllerApplication
1514

1615
import tests.async_mock as mock
1716

18-
DEVICE_CONFIG = zigpy_xbee.config.SCHEMA_DEVICE(
19-
{zigpy_xbee.config.CONF_DEVICE_PATH: "/dev/null"}
17+
DEVICE_CONFIG = zigpy.config.SCHEMA_DEVICE(
18+
{
19+
zigpy.config.CONF_DEVICE_PATH: "/dev/null",
20+
zigpy.config.CONF_DEVICE_BAUDRATE: 57600,
21+
}
2022
)
2123

2224

@@ -602,51 +604,6 @@ def test_handle_many_to_one_rri(api):
602604
api._handle_many_to_one_rri(ieee, nwk, 0)
603605

604606

605-
async def test_reconnect_multiple_disconnects(monkeypatch, caplog):
606-
"""Test reconnect with multiple disconnects."""
607-
api = xbee_api.XBee(DEVICE_CONFIG)
608-
connect_mock = mock.AsyncMock(return_value=True)
609-
monkeypatch.setattr(uart, "connect", connect_mock)
610-
611-
await api.connect()
612-
613-
caplog.set_level(logging.DEBUG)
614-
connect_mock.reset_mock()
615-
connect_mock.side_effect = [OSError, mock.sentinel.uart_reconnect]
616-
api.connection_lost("connection lost")
617-
await asyncio.sleep(0.3)
618-
api.connection_lost("connection lost 2")
619-
await asyncio.sleep(0.3)
620-
621-
assert "Cancelling reconnection attempt" in caplog.messages
622-
assert api._uart is mock.sentinel.uart_reconnect
623-
assert connect_mock.call_count == 2
624-
625-
626-
async def test_reconnect_multiple_attempts(monkeypatch, caplog):
627-
"""Test reconnect with multiple attempts."""
628-
api = xbee_api.XBee(DEVICE_CONFIG)
629-
connect_mock = mock.AsyncMock(return_value=True)
630-
monkeypatch.setattr(uart, "connect", connect_mock)
631-
632-
await api.connect()
633-
634-
caplog.set_level(logging.DEBUG)
635-
connect_mock.reset_mock()
636-
connect_mock.side_effect = [
637-
asyncio.TimeoutError,
638-
OSError,
639-
mock.sentinel.uart_reconnect,
640-
]
641-
642-
with mock.patch("asyncio.sleep"):
643-
api.connection_lost("connection lost")
644-
await api._conn_lost_task
645-
646-
assert api._uart is mock.sentinel.uart_reconnect
647-
assert connect_mock.call_count == 3
648-
649-
650607
@mock.patch.object(xbee_api.XBee, "_at_command", new_callable=mock.AsyncMock)
651608
@mock.patch.object(uart, "connect", return_value=mock.MagicMock())
652609
async def test_probe_success(mock_connect, mock_at_cmd):

tests/test_application.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import asyncio
44

55
import pytest
6+
import zigpy.config as config
67
import zigpy.exceptions
78
import zigpy.state
89
import zigpy.types as t
910
import zigpy.zdo
1011
import zigpy.zdo.types as zdo_t
1112

1213
from zigpy_xbee.api import XBee
13-
import zigpy_xbee.config as config
1414
from zigpy_xbee.exceptions import InvalidCommand
1515
import zigpy_xbee.types as xbee_t
1616
from zigpy_xbee.zigbee import application

tests/test_uart.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55

66
import pytest
77
import serial_asyncio
8+
import zigpy.config
89

910
from zigpy_xbee import uart
10-
import zigpy_xbee.config
1111

12-
DEVICE_CONFIG = zigpy_xbee.config.SCHEMA_DEVICE(
13-
{zigpy_xbee.config.CONF_DEVICE_PATH: "/dev/null"}
12+
DEVICE_CONFIG = zigpy.config.SCHEMA_DEVICE(
13+
{
14+
zigpy.config.CONF_DEVICE_PATH: "/dev/null",
15+
zigpy.config.CONF_DEVICE_BAUDRATE: 57600,
16+
}
1417
)
1518

1619

zigpy_xbee/api.py

Lines changed: 4 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
from typing import Any, Dict, Optional
88

99
import serial
10+
from zigpy.config import CONF_DEVICE_PATH, SCHEMA_DEVICE
1011
from zigpy.exceptions import APIException, DeliveryError
1112
import zigpy.types as t
1213

1314
import zigpy_xbee
14-
from zigpy_xbee.config import CONF_DEVICE_BAUDRATE, CONF_DEVICE_PATH, SCHEMA_DEVICE
1515
from zigpy_xbee.exceptions import (
1616
ATCommandError,
1717
ATCommandException,
@@ -287,7 +287,6 @@ def __init__(self, device_config: Dict[str, Any]) -> None:
287287
self._awaiting = {}
288288
self._app = None
289289
self._cmd_mode_future: Optional[asyncio.Future] = None
290-
self._conn_lost_task: Optional[asyncio.Task] = None
291290
self._reset: asyncio.Event = asyncio.Event()
292291
self._running: asyncio.Event = asyncio.Event()
293292

@@ -323,64 +322,15 @@ async def connect(self) -> None:
323322
assert self._uart is None
324323
self._uart = await uart.connect(self._config, self)
325324

326-
def reconnect(self):
327-
"""Reconnect using saved parameters."""
328-
LOGGER.debug(
329-
"Reconnecting '%s' serial port using %s",
330-
self._config[CONF_DEVICE_PATH],
331-
self._config[CONF_DEVICE_BAUDRATE],
332-
)
333-
return self.connect()
334-
335325
def connection_lost(self, exc: Exception) -> None:
336326
"""Lost serial connection."""
337-
LOGGER.warning(
338-
"Serial '%s' connection lost unexpectedly: %s",
339-
self._config[CONF_DEVICE_PATH],
340-
exc,
341-
)
342-
self._uart = None
343-
if self._conn_lost_task and not self._conn_lost_task.done():
344-
self._conn_lost_task.cancel()
345-
self._conn_lost_task = asyncio.create_task(self._connection_lost())
346-
347-
async def _connection_lost(self) -> None:
348-
"""Reconnect serial port."""
349-
try:
350-
await self._reconnect_till_done()
351-
except asyncio.CancelledError:
352-
LOGGER.debug("Cancelling reconnection attempt")
353-
raise
354-
355-
async def _reconnect_till_done(self) -> None:
356-
attempt = 1
357-
while True:
358-
try:
359-
await asyncio.wait_for(self.reconnect(), timeout=10)
360-
break
361-
except (asyncio.TimeoutError, OSError) as exc:
362-
wait = 2 ** min(attempt, 5)
363-
attempt += 1
364-
LOGGER.debug(
365-
"Couldn't re-open '%s' serial port, retrying in %ss: %s",
366-
self._config[CONF_DEVICE_PATH],
367-
wait,
368-
str(exc),
369-
)
370-
await asyncio.sleep(wait)
327+
if self._app is not None:
328+
self._app.connection_lost(exc)
371329

372-
LOGGER.debug(
373-
"Reconnected '%s' serial port after %s attempts",
374-
self._config[CONF_DEVICE_PATH],
375-
attempt,
376-
)
330+
self.close()
377331

378332
def close(self):
379333
"""Close the connection."""
380-
if self._conn_lost_task:
381-
self._conn_lost_task.cancel()
382-
self._conn_lost_task = None
383-
384334
if self._uart:
385335
self._uart.close()
386336
self._uart = None

zigpy_xbee/config.py

Lines changed: 0 additions & 19 deletions
This file was deleted.

zigpy_xbee/uart.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
import logging
55
from typing import Any, Dict
66

7+
import zigpy.config
78
import zigpy.serial
89

9-
from zigpy_xbee.config import CONF_DEVICE_BAUDRATE, CONF_DEVICE_PATH
10-
1110
LOGGER = logging.getLogger(__name__)
1211

1312

@@ -178,8 +177,8 @@ async def connect(device_config: Dict[str, Any], api, loop=None) -> Gateway:
178177
transport, protocol = await zigpy.serial.create_serial_connection(
179178
loop,
180179
lambda: protocol,
181-
url=device_config[CONF_DEVICE_PATH],
182-
baudrate=device_config[CONF_DEVICE_BAUDRATE],
180+
url=device_config[zigpy.config.CONF_DEVICE_PATH],
181+
baudrate=device_config[zigpy.config.CONF_DEVICE_BAUDRATE],
183182
xonxoff=False,
184183
)
185184

zigpy_xbee/zigbee/application.py

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

1111
import zigpy.application
1212
import zigpy.config
13+
from zigpy.config import CONF_DEVICE
1314
import zigpy.device
1415
import zigpy.exceptions
1516
import zigpy.quirks
@@ -22,7 +23,6 @@
2223

2324
import zigpy_xbee
2425
import zigpy_xbee.api
25-
from zigpy_xbee.config import CONF_DEVICE, CONFIG_SCHEMA, SCHEMA_DEVICE
2626
from zigpy_xbee.exceptions import InvalidCommand
2727
from zigpy_xbee.types import EUI64, UNKNOWN_IEEE, UNKNOWN_NWK, TXOptions, TXStatus
2828

@@ -42,17 +42,15 @@
4242
class ControllerApplication(zigpy.application.ControllerApplication):
4343
"""Implementation of Zigpy ControllerApplication for XBee devices."""
4444

45-
SCHEMA = CONFIG_SCHEMA
46-
SCHEMA_DEVICE = SCHEMA_DEVICE
47-
48-
probe = zigpy_xbee.api.XBee.probe
49-
5045
def __init__(self, config: dict[str, Any]):
5146
"""Initialize instance."""
5247
super().__init__(config=zigpy.config.ZIGPY_SCHEMA(config))
5348
self._api: zigpy_xbee.api.XBee | None = None
5449
self.topology.add_listener(self)
5550

51+
async def _watchdog_feed(self):
52+
await self._api._at_command("VR")
53+
5654
async def disconnect(self):
5755
"""Shutdown application."""
5856
if self._api:
@@ -136,6 +134,13 @@ async def load_network_info(self, *, load_devices=False):
136134
LOGGER.warning("CE command failed, assuming node is coordinator")
137135
node_info.logical_type = zdo_t.LogicalType.Coordinator
138136

137+
# TODO: Feature detect the XBee's exact model
138+
node_info.model = "XBee"
139+
node_info.manufacturer = "Digi"
140+
141+
version = await self._api._at_command("VR")
142+
node_info.version = f"{int(version):#06x}"
143+
139144
# Load network info
140145
pan_id = await self._api._at_command("OI")
141146
extended_pan_id = await self._api._at_command("ID")
@@ -345,10 +350,6 @@ async def permit_with_link_key(
345350
# 1 = Install Code With CRC (I? command of the joining device)
346351
await self._api.register_joining_device(node, reserved, key_type, link_key)
347352

348-
async def permit_with_key(self, node: EUI64, code: bytes, time_s=500):
349-
"""Permits a new device to join with the given IEEE and Install Code."""
350-
await self.permit_with_link_key(node, code, time_s, key_type=1)
351-
352353
def handle_modem_status(self, status):
353354
"""Handle changed Modem Status of the device."""
354355
LOGGER.info("Modem status update: %s (%s)", status.name, status.value)

0 commit comments

Comments
 (0)