Skip to content

Commit 2ddaeec

Browse files
authored
0.12.0 Release
2 parents a47b228 + 8420a38 commit 2ddaeec

File tree

7 files changed

+52
-31
lines changed

7 files changed

+52
-31
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ jobs:
330330
COVERALLS_PARALLEL: true
331331
run: |
332332
. venv/bin/activate
333-
coveralls
333+
coveralls --service=github
334334
335335
336336
coverage:
@@ -374,4 +374,4 @@ jobs:
374374
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
375375
run: |
376376
. venv/bin/activate
377-
coveralls --finish
377+
coveralls --service=github --finish

requirements_test.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Test dependencies
22

33
asynctest
4-
coveralls
4+
coveralls==3.0.1
55
pytest
66
pytest-cov
77
pytest-asyncio

tests/test_api.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
import asyncio
44
import binascii
55
import logging
6-
import sys
76

87
import pytest
9-
import serial
108
import zigpy.config
119

1210
from zigpy_deconz import api as deconz_api, types as t, uart
@@ -239,7 +237,7 @@ def test_simplified_beacon(api):
239237

240238

241239
async def test_aps_data_confirm(api, monkeypatch):
242-
monkeypatch.setattr(deconz_api, "COMMAND_TIMEOUT", 0.1)
240+
monkeypatch.setattr(deconz_api, "COMMAND_TIMEOUT", 0.01)
243241

244242
success = True
245243

@@ -254,9 +252,10 @@ def mock_cmd(*args, **kwargs):
254252

255253
res = await api._aps_data_confirm()
256254
assert res is not None
257-
assert api._data_confirm is True
255+
assert api._data_confirm is False
258256

259257
success = False
258+
api._data_confirm = True
260259
res = await api._aps_data_confirm()
261260
assert res is None
262261
assert api._data_confirm is False
@@ -291,9 +290,10 @@ def mock_cmd(*args, **kwargs):
291290

292291
res = await api._aps_data_indication()
293292
assert res is not None
294-
assert api._data_indication is True
293+
assert api._data_indication is False
295294

296295
success = False
296+
api._data_indication = True
297297
res = await api._aps_data_indication()
298298
assert res is None
299299
assert api._data_indication is False
@@ -524,16 +524,7 @@ async def test_probe_success(mock_connect, mock_device_state):
524524

525525
@patch.object(deconz_api.Deconz, "device_state", new_callable=AsyncMock)
526526
@patch("zigpy_deconz.uart.connect", return_value=MagicMock(spec_set=uart.Gateway))
527-
@pytest.mark.parametrize(
528-
"exception",
529-
(
530-
asyncio.TimeoutError,
531-
serial.SerialException,
532-
zigpy_deconz.exception.CommandError,
533-
)
534-
if sys.version_info[:3] != (3, 7, 9)
535-
else (asyncio.TimeoutError,),
536-
)
527+
@pytest.mark.parametrize("exception", (asyncio.TimeoutError,))
537528
async def test_probe_fail(mock_connect, mock_device_state, exception):
538529
"""Test device probing fails."""
539530

@@ -587,7 +578,7 @@ async def test_aps_data_req_deserialize_error(api, uart_gw, status, caplog):
587578

588579
device_state = (
589580
deconz_api.DeviceState.APSDE_DATA_INDICATION
590-
| deconz_api.DeviceState.APSDE_DATA_REQUEST_SLOTS_AVAILABLE
581+
| deconz_api.DeviceState.APSDE_DATA_CONFIRM
591582
| deconz_api.NetworkState.CONNECTED
592583
)
593584
api._handle_device_state_value(device_state)
@@ -606,3 +597,15 @@ async def test_aps_data_req_deserialize_error(api, uart_gw, status, caplog):
606597
await asyncio.sleep(0)
607598
await asyncio.sleep(0)
608599
assert api._data_indication is False
600+
601+
602+
async def test_set_item(api):
603+
"""Test item setter."""
604+
605+
with patch.object(api, "write_parameter", new=AsyncMock()) as write_mock:
606+
api["test"] = sentinel.test_param
607+
for i in range(10):
608+
await asyncio.sleep(0)
609+
assert write_mock.await_count == 1
610+
assert write_mock.call_args[0][0] == "test"
611+
assert write_mock.call_args[0][1] is sentinel.test_param

zigpy_deconz/__init__.py

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

33
# coding: utf-8
44
MAJOR_VERSION = 0
5-
MINOR_VERSION = 11
6-
PATCH_VERSION = "1"
7-
__short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION)
8-
__version__ = "{}.{}".format(__short_version__, PATCH_VERSION)
5+
MINOR_VERSION = 12
6+
PATCH_VERSION = "0"
7+
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
8+
__version__ = f"{__short_version__}.{PATCH_VERSION}"

zigpy_deconz/api.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ async def _command(self, cmd, *args):
307307
LOGGER.warning(
308308
"No response to '%s' command with seq id '0x%02x'", cmd, seq
309309
)
310-
self._awaiting.pop(seq)
310+
self._awaiting.pop(seq, None)
311311
raise
312312

313313
def _api_frame(self, cmd, *args):
@@ -338,16 +338,21 @@ def data_received(self, data):
338338
if solicited and seq in self._awaiting:
339339
fut = self._awaiting.pop(seq)
340340
if status != Status.SUCCESS:
341-
fut.set_exception(
342-
CommandError(status, "%s, status: %s" % (command, status))
343-
)
341+
try:
342+
fut.set_exception(
343+
CommandError(status, "%s, status: %s" % (command, status))
344+
)
345+
except asyncio.InvalidStateError:
346+
LOGGER.warning(
347+
"Duplicate or delayed response for 0x:%02x sequence", seq
348+
)
344349
return
345350

346351
try:
347352
data, _ = t.deserialize(data[5:], schema)
348353
except Exception:
349354
LOGGER.warning("Failed to deserialize frame: %s", binascii.hexlify(data))
350-
if fut is not None:
355+
if fut is not None and not fut.done():
351356
fut.set_exception(
352357
APIException(
353358
f"Failed to deserialize frame: {binascii.hexlify(data)}"
@@ -356,7 +361,13 @@ def data_received(self, data):
356361
return
357362

358363
if fut is not None:
359-
fut.set_result(data)
364+
try:
365+
fut.set_result(data)
366+
except asyncio.InvalidStateError:
367+
LOGGER.warning(
368+
"Duplicate or delayed response for 0x:%02x sequence", seq
369+
)
370+
360371
getattr(self, "_handle_%s" % (command.name,))(data)
361372

362373
add_neighbour = functools.partialmethod(_command, Command.add_neighbour, 12)
@@ -475,6 +486,8 @@ async def _aps_data_indication(self):
475486
)
476487
return r
477488
except (asyncio.TimeoutError, zigpy.exceptions.ZigbeeException):
489+
pass
490+
finally:
478491
self._data_indication = False
479492

480493
def _handle_aps_data_indication(self, data):
@@ -537,6 +550,8 @@ async def _aps_data_confirm(self):
537550
)
538551
return r
539552
except (asyncio.TimeoutError, zigpy.exceptions.ZigbeeException):
553+
pass
554+
finally:
540555
self._data_confirm = False
541556

542557
def _handle_add_neighbour(self, data) -> None:

zigpy_deconz/uart.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ def data_received(self, data):
8888
continue
8989

9090
LOGGER.debug("Frame received: 0x%s", binascii.hexlify(frame).decode())
91-
self._api.data_received(frame)
91+
try:
92+
self._api.data_received(frame)
93+
except Exception as exc:
94+
LOGGER.error("Unexpected error handling the frame: %s", exc)
9295

9396
def _unescape(self, data):
9497
ret = []

zigpy_deconz/zigbee/application.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ def __init__(self, version: int, device_path: str, *args):
381381
"""Initialize instance."""
382382

383383
super().__init__(*args)
384-
is_gpio_device = re.match(r"/dev/tty(S|AMA)\d+", device_path)
384+
is_gpio_device = re.match(r"/dev/tty(S|AMA|ACM)\d+", device_path)
385385
self._model = "RaspBee" if is_gpio_device else "ConBee"
386386
self._model += " II" if ((version & 0x0000FF00) == 0x00000700) else ""
387387

0 commit comments

Comments
 (0)