lifx-async 4.3.3__py3-none-any.whl → 4.3.4__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.
- lifx/devices/base.py +30 -6
- lifx/network/connection.py +22 -11
- {lifx_async-4.3.3.dist-info → lifx_async-4.3.4.dist-info}/METADATA +1 -1
- {lifx_async-4.3.3.dist-info → lifx_async-4.3.4.dist-info}/RECORD +6 -6
- {lifx_async-4.3.3.dist-info → lifx_async-4.3.4.dist-info}/WHEEL +0 -0
- {lifx_async-4.3.3.dist-info → lifx_async-4.3.4.dist-info}/licenses/LICENSE +0 -0
lifx/devices/base.py
CHANGED
|
@@ -252,6 +252,8 @@ class Device:
|
|
|
252
252
|
self.serial = serial_obj.to_string()
|
|
253
253
|
self.ip = ip
|
|
254
254
|
self.port = port
|
|
255
|
+
self._timeout = timeout
|
|
256
|
+
self._max_retries = max_retries
|
|
255
257
|
|
|
256
258
|
# Create lightweight connection handle - connection pooling is internal
|
|
257
259
|
self.connection = DeviceConnection(
|
|
@@ -304,10 +306,16 @@ class Device:
|
|
|
304
306
|
```
|
|
305
307
|
"""
|
|
306
308
|
if serial is None:
|
|
307
|
-
temp_conn = DeviceConnection(
|
|
309
|
+
temp_conn = DeviceConnection(
|
|
310
|
+
serial="000000000000",
|
|
311
|
+
ip=ip,
|
|
312
|
+
port=port,
|
|
313
|
+
timeout=timeout,
|
|
314
|
+
max_retries=max_retries,
|
|
315
|
+
)
|
|
308
316
|
try:
|
|
309
317
|
response = await temp_conn.request(
|
|
310
|
-
packets.Device.GetService(), timeout=
|
|
318
|
+
packets.Device.GetService(), timeout=timeout
|
|
311
319
|
)
|
|
312
320
|
if response and isinstance(response, packets.Device.StateService):
|
|
313
321
|
if temp_conn.serial and temp_conn.serial != "000000000000":
|
|
@@ -890,9 +898,17 @@ class Device:
|
|
|
890
898
|
|
|
891
899
|
try:
|
|
892
900
|
# Check each device for the target label
|
|
893
|
-
async for disc in discover_devices(
|
|
901
|
+
async for disc in discover_devices(
|
|
902
|
+
timeout=discover_timeout,
|
|
903
|
+
device_timeout=self._timeout,
|
|
904
|
+
max_retries=self._max_retries,
|
|
905
|
+
):
|
|
894
906
|
temp_conn = DeviceConnection(
|
|
895
|
-
serial=disc.serial,
|
|
907
|
+
serial=disc.serial,
|
|
908
|
+
ip=disc.ip,
|
|
909
|
+
port=disc.port,
|
|
910
|
+
timeout=self._timeout,
|
|
911
|
+
max_retries=self._max_retries,
|
|
896
912
|
)
|
|
897
913
|
|
|
898
914
|
try:
|
|
@@ -1063,9 +1079,17 @@ class Device:
|
|
|
1063
1079
|
|
|
1064
1080
|
try:
|
|
1065
1081
|
# Check each device for the target label
|
|
1066
|
-
async for disc in discover_devices(
|
|
1082
|
+
async for disc in discover_devices(
|
|
1083
|
+
timeout=discover_timeout,
|
|
1084
|
+
device_timeout=self._timeout,
|
|
1085
|
+
max_retries=self._max_retries,
|
|
1086
|
+
):
|
|
1067
1087
|
temp_conn = DeviceConnection(
|
|
1068
|
-
serial=disc.serial,
|
|
1088
|
+
serial=disc.serial,
|
|
1089
|
+
ip=disc.ip,
|
|
1090
|
+
port=disc.port,
|
|
1091
|
+
timeout=self._timeout,
|
|
1092
|
+
max_retries=self._max_retries,
|
|
1069
1093
|
)
|
|
1070
1094
|
|
|
1071
1095
|
try:
|
lifx/network/connection.py
CHANGED
|
@@ -467,13 +467,10 @@ class DeviceConnection:
|
|
|
467
467
|
correlation_keys: list[tuple[int, int, str]] = []
|
|
468
468
|
|
|
469
469
|
# Calculate per-attempt timeouts with exponential backoff
|
|
470
|
-
#
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
else:
|
|
475
|
-
# Only one attempt total, use entire timeout
|
|
476
|
-
attempt_timeout = timeout
|
|
470
|
+
# Use proper exponential backoff distribution: timeout / (2^(n+1) - 1)
|
|
471
|
+
# This ensures total of all attempt timeouts equals the overall timeout budget
|
|
472
|
+
total_weight = (2 ** (max_retries + 1)) - 1
|
|
473
|
+
base_timeout = timeout / total_weight
|
|
477
474
|
|
|
478
475
|
# Idle timeout for multi-response protocols
|
|
479
476
|
# Stop streaming if no responses for this long after first response
|
|
@@ -482,14 +479,17 @@ class DeviceConnection:
|
|
|
482
479
|
last_error: Exception | None = None
|
|
483
480
|
has_yielded = False
|
|
484
481
|
overall_start = time.monotonic()
|
|
482
|
+
total_sleep_time = 0.0 # Track sleep time to exclude from timeout budget
|
|
485
483
|
|
|
486
484
|
try:
|
|
487
485
|
for attempt in range(max_retries + 1):
|
|
488
486
|
# Calculate current attempt timeout with exponential backoff
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
487
|
+
# Exclude sleep time from elapsed time to preserve timeout budget
|
|
488
|
+
elapsed_response_time = (
|
|
489
|
+
time.monotonic() - overall_start - total_sleep_time
|
|
492
490
|
)
|
|
491
|
+
ideal_timeout = base_timeout * (2**attempt)
|
|
492
|
+
current_timeout = min(ideal_timeout, timeout - elapsed_response_time)
|
|
493
493
|
|
|
494
494
|
# Check if we've exceeded overall timeout budget
|
|
495
495
|
if current_timeout <= 0:
|
|
@@ -616,6 +616,9 @@ class DeviceConnection:
|
|
|
616
616
|
# Sleep with jitter before retry
|
|
617
617
|
sleep_time = self._calculate_retry_sleep_with_jitter(attempt)
|
|
618
618
|
await asyncio.sleep(sleep_time)
|
|
619
|
+
total_sleep_time += (
|
|
620
|
+
sleep_time # Track sleep to exclude from timeout
|
|
621
|
+
)
|
|
619
622
|
continue
|
|
620
623
|
else:
|
|
621
624
|
# All retries exhausted
|
|
@@ -673,9 +676,14 @@ class DeviceConnection:
|
|
|
673
676
|
base_timeout = timeout / total_weight
|
|
674
677
|
|
|
675
678
|
last_error: Exception | None = None
|
|
679
|
+
total_sleep_time = 0.0 # Track sleep time to exclude from timeout budget
|
|
680
|
+
overall_start = time.monotonic()
|
|
676
681
|
|
|
677
682
|
for attempt in range(max_retries + 1):
|
|
678
|
-
|
|
683
|
+
# Calculate timeout with budget remaining after excluding sleep time
|
|
684
|
+
elapsed_response_time = time.monotonic() - overall_start - total_sleep_time
|
|
685
|
+
ideal_timeout = base_timeout * (2**attempt)
|
|
686
|
+
current_timeout = min(ideal_timeout, timeout - elapsed_response_time)
|
|
679
687
|
sequence = attempt
|
|
680
688
|
|
|
681
689
|
# Correlation key: (source, sequence, serial)
|
|
@@ -737,6 +745,9 @@ class DeviceConnection:
|
|
|
737
745
|
# Sleep with jitter before retry
|
|
738
746
|
sleep_time = self._calculate_retry_sleep_with_jitter(attempt)
|
|
739
747
|
await asyncio.sleep(sleep_time)
|
|
748
|
+
total_sleep_time += (
|
|
749
|
+
sleep_time # Track sleep to exclude from timeout
|
|
750
|
+
)
|
|
740
751
|
continue
|
|
741
752
|
else:
|
|
742
753
|
break
|
|
@@ -5,7 +5,7 @@ lifx/const.py,sha256=dW64lf_jwAD40GSd6hkFkrni5j-w2qkV3pl6YNdCxv4,3426
|
|
|
5
5
|
lifx/exceptions.py,sha256=pikAMppLn7gXyjiQVWM_tSvXKNh-g366nG_UWyqpHhc,815
|
|
6
6
|
lifx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
lifx/devices/__init__.py,sha256=V7hW8sM_RwFgbR4Hv1ByR1JLhYq7Ft1X9pylQjCXYB8,777
|
|
8
|
-
lifx/devices/base.py,sha256=
|
|
8
|
+
lifx/devices/base.py,sha256=uD3hQe2kjycRZneSptON6psOhoEgPRHVelCoLgdHbFw,41482
|
|
9
9
|
lifx/devices/hev.py,sha256=2zZNYm3TFrL755B4cRPNdYtcDLZEQwGl_22112WsSZc,9504
|
|
10
10
|
lifx/devices/infrared.py,sha256=TrCgJyEioIPlFumMmcSmuGYmRsSGlQ5Rllg6_9Wtg4Y,4248
|
|
11
11
|
lifx/devices/light.py,sha256=9rL24fa44Y7QrRBDSQuG6xpWsaPbQTTm4ExvrDnYWHo,27572
|
|
@@ -20,7 +20,7 @@ lifx/effects/models.py,sha256=MS5D-cxD0Ar8XhqbqKAc9q2sk38IP1vPkYwd8V7jCr8,2446
|
|
|
20
20
|
lifx/effects/pulse.py,sha256=t5eyjfFWG1xT-RXKghRqHYJ9CG_50tPu4jsDapJZ2mw,8721
|
|
21
21
|
lifx/effects/state_manager.py,sha256=iDfYowiCN5IJqcR1s-pM0mQEJpe-RDsMcOOSMmtPVDE,8983
|
|
22
22
|
lifx/network/__init__.py,sha256=uSyA8r8qISG7qXUHbX8uk9A2E8rvDADgCcf94QIZ9so,499
|
|
23
|
-
lifx/network/connection.py,sha256=
|
|
23
|
+
lifx/network/connection.py,sha256=K5zzwYWKBvSBMqcP6a5Fp9JkVIiOLXJSAi1XMT4g-Go,38191
|
|
24
24
|
lifx/network/discovery.py,sha256=FoFoZcw3dtJs1daESiZiNXytanKQsMTdF9PjOxEgHM0,23804
|
|
25
25
|
lifx/network/message.py,sha256=jCLC9v0tbBi54g5CaHLFM_nP1Izu8kJmo2tt23HHBbA,2600
|
|
26
26
|
lifx/network/transport.py,sha256=8QS0YV32rdP0EDiPEwuvZXbplRWL08pmjKybd87mkZ0,11070
|
|
@@ -40,7 +40,7 @@ lifx/theme/canvas.py,sha256=4h7lgN8iu_OdchObGDgbxTqQLCb-FRKC-M-YCWef_i4,8048
|
|
|
40
40
|
lifx/theme/generators.py,sha256=L0X6_iApLx6XDboGlYunaVsl6nvUCqMfn23VQmRkyCk,6125
|
|
41
41
|
lifx/theme/library.py,sha256=tKlKZNqJp8lRGDnilWyDm_Qr1vCRGGwuvWVS82anNpQ,21326
|
|
42
42
|
lifx/theme/theme.py,sha256=qMEx_8E41C0Cc6f083XHiAXEglTv4YlXW0UFsG1rQKg,5521
|
|
43
|
-
lifx_async-4.3.
|
|
44
|
-
lifx_async-4.3.
|
|
45
|
-
lifx_async-4.3.
|
|
46
|
-
lifx_async-4.3.
|
|
43
|
+
lifx_async-4.3.4.dist-info/METADATA,sha256=MkrET2BAkIwK9D5rlzSmJyM9pp2DyHzBbSjHLvF27AM,2609
|
|
44
|
+
lifx_async-4.3.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
45
|
+
lifx_async-4.3.4.dist-info/licenses/LICENSE,sha256=eBz48GRA3gSiWn3rYZAz2Ewp35snnhV9cSqkVBq7g3k,1832
|
|
46
|
+
lifx_async-4.3.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|