python-dali 0.14__py3-none-any.whl → 0.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dali/driver/serial.py CHANGED
@@ -660,18 +660,30 @@ class DriverLubaRs232(DriverSerialBase):
660
660
  )
661
661
  if confirm.error_code is not None:
662
662
  raise TransmissionError(confirm.error_code)
663
+ if (
664
+ hasattr(confirm.message, "frame")
665
+ and confirm.message.frame != tx.frame
666
+ ):
667
+ # A confirmation for a different frame can only be a
668
+ # stale one for an earlier send whose confirmation
669
+ # arrived after it had already timed out: sends are
670
+ # serialised under '_tx_lock', so nothing later is in
671
+ # flight yet. Drop it and keep waiting for this frame's
672
+ # own confirmation, otherwise every subsequent send
673
+ # inherits the one-off mismatch and the stream never
674
+ # resynchronises.
675
+ _LOG.warning(
676
+ "Discarding stale LUBA confirmation for '%s' "
677
+ "while awaiting '%s'",
678
+ confirm.message,
679
+ tx,
680
+ )
681
+ continue
663
682
  if hasattr(confirm.message, "frame"):
664
- if confirm.message.frame == tx.frame:
665
- _LOG.trace(
666
- f"LUBA device reports message '{tx}' sent, "
667
- f"with ID {confirm.tx_id}"
668
- )
669
- else:
670
- _LOG.error(
671
- "Expected LUBA device to confirm transmission "
672
- f"of message '{tx}', but got a confirmation "
673
- f"for '{confirm.message}'"
674
- )
683
+ _LOG.trace(
684
+ f"LUBA device reports message '{tx}' sent, "
685
+ f"with ID {confirm.tx_id}"
686
+ )
675
687
  else:
676
688
  _LOG.debug(
677
689
  f"Unable to decode message id {confirm.tx_id}, but "
@@ -6,11 +6,12 @@ from unittest.mock import AsyncMock, MagicMock
6
6
 
7
7
  import pytest
8
8
 
9
- from dali.address import DeviceShort, InstanceNumber
9
+ from dali.address import DeviceShort, GearShort, InstanceNumber
10
10
  from dali.command import NumericResponse
11
11
  from dali.device.general import QueryInstanceType
12
12
  from dali.device.helpers import check_bad_rsp
13
13
  from dali.driver.serial import _DALI_FRAMING_ERROR, DriverLubaRs232
14
+ from dali.gear.general import QueryActualLevel
14
15
 
15
16
 
16
17
  @pytest.mark.asyncio
@@ -149,6 +150,35 @@ async def test_connect_reopens_the_port_after_a_lost_transport(monkeypatch):
149
150
  assert driver._protocol is replacement
150
151
 
151
152
 
153
+ @pytest.mark.asyncio
154
+ async def test_send_dali_command_resyncs_after_stale_confirmation(caplog):
155
+ """A stale confirmation must not desync every following transmission.
156
+
157
+ A weak bus can let a send's confirmation arrive after it timed out; the
158
+ next send then finds that stale confirmation queued ahead of its own. It
159
+ must be discarded and the matching one awaited, so the stream recovers
160
+ instead of every later frame inheriting the one-off mismatch.
161
+ """
162
+ protocol = DriverLubaRs232.LubaProtocol()
163
+ protocol.transport = MagicMock()
164
+ protocol.rx_idle.set()
165
+
166
+ command = QueryActualLevel(GearShort(0))
167
+ stale = QueryActualLevel(GearShort(1))
168
+ protocol._queue_tx_conf.put_nowait(
169
+ protocol.LubaMsgTxConf(tx_id=1, message=stale)
170
+ )
171
+ protocol._queue_tx_conf.put_nowait(
172
+ protocol.LubaMsgTxConf(tx_id=2, message=command)
173
+ )
174
+
175
+ with caplog.at_level(logging.WARNING, logger="dali.driver"):
176
+ await protocol.send_dali_command(command)
177
+
178
+ assert protocol._queue_tx_conf.empty()
179
+ assert any("stale LUBA confirmation" in r.getMessage() for r in caplog.records)
180
+
181
+
152
182
  @pytest.mark.asyncio
153
183
  async def test_reset_luba_response_drains_all(caplog):
154
184
  """Stale LUBA command replies must be cleared before a handshake retry."""
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-dali
3
- Version: 0.14
3
+ Version: 0.15
4
4
  Summary: Interface to DALI lighting systems
5
5
  Home-page: https://github.com/sde1000/python-dali
6
6
  Author: Stephen Early
7
7
  Author-email: steve@assorted.org.uk
8
- License: "LGPL-3.0-or-later"
8
+ License: LGPL-3.0-or-later
9
9
  Classifier: Development Status :: 3 - Alpha
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: Programming Language :: Python :: 3
@@ -18,7 +18,7 @@ dali/driver/base.py,sha256=Jd_0PrkVg84CdkVLmGBr5IyK5Sm7N68tqNDdPFRB7-0,3891
18
18
  dali/driver/daliserver.py,sha256=YbaTv8glbsPWtXy-m-zakxsPwZBu5FsuXxtVPfE1n78,3120
19
19
  dali/driver/hasseb.py,sha256=dQDrkxdpXlXlxmoShsoYOpvXpGzSLqZ8eqG-HMKIGOI,9376
20
20
  dali/driver/hid.py,sha256=CyBkCZeyDFumzvfTUeTB3xIjALZkg6dugd3G4DYIeig,33591
21
- dali/driver/serial.py,sha256=8bERuROWq_Sj5YH3--3Z-IOORXltmlTmqHf8hEGN_vk,81696
21
+ dali/driver/serial.py,sha256=XPMytdl7bijJBFDx2d3q94AFcZUdH6m0z0dOvkLvdI0,82350
22
22
  dali/driver/trace_logging.py,sha256=qfkEdgVQsu-dXYKsmPXb6j7VRC6O1JJovuU8ca-KEMs,2366
23
23
  dali/driver/tridonic.py,sha256=H-j0u-7oP36uKxm-KdCO35AFuoyVzKu_jQs31jeDW6Y,10889
24
24
  dali/driver/unipi.py,sha256=arQ-o8zI-PtyvnyRa6f6kPKYswFtFvvdoKfCNRxTAiY,7399
@@ -54,11 +54,11 @@ dali/tests/test_frame.py,sha256=qd9LzN5ie9zFMTeqzTW5CIsLeuR4n0U4ZqybuG-s4Ck,6035
54
54
  dali/tests/test_general_sensor.py,sha256=jQqsjzUJa9rbX5pt1K9oavDiFXzMvqclx7qZ7FHrUos,1818
55
55
  dali/tests/test_memory.py,sha256=CGcoyhyd_pVC9C4yY0D7X83RIGs8RzYcDX32VuJvd3A,29526
56
56
  dali/tests/test_sequences.py,sha256=VaGy1WbUAXFRh-RU6v0OIOHKAhFwVh4KqU7O0N28zF8,4314
57
- dali/tests/test_serial_driver.py,sha256=oQ5qYCo93X7qxuhmySmqT5Ym97dkMZrzI-o2HmJsTpk,7531
58
- python_dali-0.14.dist-info/licenses/COPYING,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
59
- python_dali-0.14.dist-info/licenses/COPYING.LESSER,sha256=2n6rt7r999OuXp8iOqW9we7ORaxWncIbOwN1ILRGR2g,7651
60
- python_dali-0.14.dist-info/licenses/LICENSE,sha256=HVcO3iFdIg-1DaBsl4fgk3swO0aZDktmHBZPIhhn_5o,168
61
- python_dali-0.14.dist-info/METADATA,sha256=x7ztPGVIdmPi80odDqzJ_Xtr-fvZiHJNJ1ajVC6N42I,6200
62
- python_dali-0.14.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
63
- python_dali-0.14.dist-info/top_level.txt,sha256=VlSHNdAIGn5irB2PYMRKK0POsLocy-YusWmK3GwHViI,5
64
- python_dali-0.14.dist-info/RECORD,,
57
+ dali/tests/test_serial_driver.py,sha256=5tZYvE3D2BDD4nQc14te9oKh7z6uAj46uYdC5IaHq6w,8711
58
+ python_dali-0.15.dist-info/licenses/COPYING,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
59
+ python_dali-0.15.dist-info/licenses/COPYING.LESSER,sha256=2n6rt7r999OuXp8iOqW9we7ORaxWncIbOwN1ILRGR2g,7651
60
+ python_dali-0.15.dist-info/licenses/LICENSE,sha256=HVcO3iFdIg-1DaBsl4fgk3swO0aZDktmHBZPIhhn_5o,168
61
+ python_dali-0.15.dist-info/METADATA,sha256=NqKxhlAm09OC_InJQejTr2eQVdnboPV1nbmkFmzAZsY,6198
62
+ python_dali-0.15.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
63
+ python_dali-0.15.dist-info/top_level.txt,sha256=VlSHNdAIGn5irB2PYMRKK0POsLocy-YusWmK3GwHViI,5
64
+ python_dali-0.15.dist-info/RECORD,,