lifx-async 4.7.4__py3-none-any.whl → 4.7.5__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/ceiling.py +75 -17
- {lifx_async-4.7.4.dist-info → lifx_async-4.7.5.dist-info}/METADATA +1 -1
- {lifx_async-4.7.4.dist-info → lifx_async-4.7.5.dist-info}/RECORD +5 -5
- {lifx_async-4.7.4.dist-info → lifx_async-4.7.5.dist-info}/WHEEL +0 -0
- {lifx_async-4.7.4.dist-info → lifx_async-4.7.5.dist-info}/licenses/LICENSE +0 -0
lifx/devices/ceiling.py
CHANGED
|
@@ -347,6 +347,22 @@ class CeilingLight(MatrixLight):
|
|
|
347
347
|
|
|
348
348
|
return layout.downlight_zones
|
|
349
349
|
|
|
350
|
+
@property
|
|
351
|
+
def downlight_zone_count(self) -> int:
|
|
352
|
+
"""Number of downlight zones.
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
Zone count (63 for standard 8x8, 127 for Capsule 16x8)
|
|
356
|
+
|
|
357
|
+
Raises:
|
|
358
|
+
LifxError: If device version is not available or not a Ceiling product
|
|
359
|
+
"""
|
|
360
|
+
# downlight_zones is slice(0, N), so stop equals the count
|
|
361
|
+
stop = self.downlight_zones.stop
|
|
362
|
+
if stop is None:
|
|
363
|
+
raise LifxError("Invalid downlight zones configuration")
|
|
364
|
+
return stop
|
|
365
|
+
|
|
350
366
|
@property
|
|
351
367
|
def uplight_is_on(self) -> bool:
|
|
352
368
|
"""True if uplight component is currently on.
|
|
@@ -496,7 +512,7 @@ class CeilingLight(MatrixLight):
|
|
|
496
512
|
"Cannot set downlight color with brightness=0. "
|
|
497
513
|
"Use turn_downlight_off() instead."
|
|
498
514
|
)
|
|
499
|
-
downlight_colors = [colors] *
|
|
515
|
+
downlight_colors = [colors] * self.downlight_zone_count
|
|
500
516
|
else:
|
|
501
517
|
if all(c.brightness == 0 for c in colors):
|
|
502
518
|
raise ValueError(
|
|
@@ -504,10 +520,10 @@ class CeilingLight(MatrixLight):
|
|
|
504
520
|
"Use turn_downlight_off() instead."
|
|
505
521
|
)
|
|
506
522
|
|
|
507
|
-
|
|
508
|
-
if len(colors) != expected_count:
|
|
523
|
+
if len(colors) != self.downlight_zone_count:
|
|
509
524
|
raise ValueError(
|
|
510
|
-
f"Expected {
|
|
525
|
+
f"Expected {self.downlight_zone_count} colors for downlight, "
|
|
526
|
+
f"got {len(colors)}"
|
|
511
527
|
)
|
|
512
528
|
downlight_colors = colors
|
|
513
529
|
|
|
@@ -684,10 +700,6 @@ class CeilingLight(MatrixLight):
|
|
|
684
700
|
ValueError: If list length doesn't match downlight zone count
|
|
685
701
|
LifxTimeoutError: Device did not respond
|
|
686
702
|
"""
|
|
687
|
-
# Number of downlight zones equals the uplight zone index
|
|
688
|
-
# (downlight is zones 0 to uplight_zone-1)
|
|
689
|
-
downlight_zone_count = self.uplight_zone
|
|
690
|
-
|
|
691
703
|
# Validate provided colors early
|
|
692
704
|
if colors is not None:
|
|
693
705
|
if isinstance(colors, HSBK):
|
|
@@ -696,9 +708,9 @@ class CeilingLight(MatrixLight):
|
|
|
696
708
|
else:
|
|
697
709
|
if all(c.brightness == 0 for c in colors):
|
|
698
710
|
raise ValueError("Cannot turn on downlight with brightness=0")
|
|
699
|
-
if len(colors) != downlight_zone_count:
|
|
711
|
+
if len(colors) != self.downlight_zone_count:
|
|
700
712
|
raise ValueError(
|
|
701
|
-
f"Expected {downlight_zone_count} colors for downlight, "
|
|
713
|
+
f"Expected {self.downlight_zone_count} colors for downlight, "
|
|
702
714
|
f"got {len(colors)}"
|
|
703
715
|
)
|
|
704
716
|
|
|
@@ -711,7 +723,7 @@ class CeilingLight(MatrixLight):
|
|
|
711
723
|
# Determine target colors (pass pre-fetched colors to avoid extra fetch)
|
|
712
724
|
if colors is not None:
|
|
713
725
|
if isinstance(colors, HSBK):
|
|
714
|
-
target_colors = [colors] * downlight_zone_count
|
|
726
|
+
target_colors = [colors] * self.downlight_zone_count
|
|
715
727
|
else:
|
|
716
728
|
target_colors = list(colors)
|
|
717
729
|
else:
|
|
@@ -750,7 +762,7 @@ class CeilingLight(MatrixLight):
|
|
|
750
762
|
# Light is already on - determine target colors first, then set
|
|
751
763
|
if colors is not None:
|
|
752
764
|
if isinstance(colors, HSBK):
|
|
753
|
-
target_colors = [colors] * downlight_zone_count
|
|
765
|
+
target_colors = [colors] * self.downlight_zone_count
|
|
754
766
|
else:
|
|
755
767
|
target_colors = list(colors)
|
|
756
768
|
else:
|
|
@@ -824,6 +836,54 @@ class CeilingLight(MatrixLight):
|
|
|
824
836
|
if turning_off and self._state_file:
|
|
825
837
|
self._save_state_to_file()
|
|
826
838
|
|
|
839
|
+
async def set_color(self, color: HSBK, duration: float = 0.0) -> None:
|
|
840
|
+
"""Set light color, updating component state tracking.
|
|
841
|
+
|
|
842
|
+
Overrides Light.set_color() to track the color change in the ceiling
|
|
843
|
+
light's component state. When set_color() is called, all zones (uplight
|
|
844
|
+
and downlight) are set to the same color. This override ensures that
|
|
845
|
+
the cached component colors stay in sync so that subsequent component
|
|
846
|
+
control methods (like turn_uplight_on or turn_downlight_on) use the
|
|
847
|
+
correct color values.
|
|
848
|
+
|
|
849
|
+
Args:
|
|
850
|
+
color: HSBK color to set for the entire light
|
|
851
|
+
duration: Transition duration in seconds (default 0.0)
|
|
852
|
+
|
|
853
|
+
Raises:
|
|
854
|
+
LifxDeviceNotFoundError: If device is not connected
|
|
855
|
+
LifxTimeoutError: If device does not respond
|
|
856
|
+
LifxUnsupportedCommandError: If device doesn't support this command
|
|
857
|
+
|
|
858
|
+
Example:
|
|
859
|
+
```python
|
|
860
|
+
from lifx.color import HSBK
|
|
861
|
+
|
|
862
|
+
# Set entire ceiling light to warm white
|
|
863
|
+
await ceiling.set_color(
|
|
864
|
+
HSBK(hue=0, saturation=0, brightness=1.0, kelvin=2700)
|
|
865
|
+
)
|
|
866
|
+
|
|
867
|
+
# Later component control will use this color
|
|
868
|
+
await ceiling.turn_uplight_off() # Uplight off
|
|
869
|
+
await ceiling.turn_uplight_on() # Restores to warm white
|
|
870
|
+
```
|
|
871
|
+
"""
|
|
872
|
+
# Call parent to perform actual color change
|
|
873
|
+
await super().set_color(color, duration)
|
|
874
|
+
|
|
875
|
+
# Update cached component colors - all zones now have the same color
|
|
876
|
+
self._last_uplight_color = color
|
|
877
|
+
self._last_downlight_colors = [color] * self.downlight_zone_count
|
|
878
|
+
|
|
879
|
+
# Also update stored state for restoration
|
|
880
|
+
self._stored_uplight_state = color
|
|
881
|
+
self._stored_downlight_state = [color] * self.downlight_zone_count
|
|
882
|
+
|
|
883
|
+
# Persist if enabled
|
|
884
|
+
if self._state_file:
|
|
885
|
+
self._save_state_to_file()
|
|
886
|
+
|
|
827
887
|
async def turn_downlight_off(
|
|
828
888
|
self, colors: HSBK | list[HSBK] | None = None, duration: float = 0.0
|
|
829
889
|
) -> None:
|
|
@@ -845,8 +905,6 @@ class CeilingLight(MatrixLight):
|
|
|
845
905
|
Note:
|
|
846
906
|
Sets all downlight zone brightness to 0 on device while preserving H, S, K.
|
|
847
907
|
"""
|
|
848
|
-
expected_count = len(range(*self.downlight_zones.indices(256)))
|
|
849
|
-
|
|
850
908
|
# Validate provided colors early (before fetching)
|
|
851
909
|
stored_colors: list[HSBK] | None = None
|
|
852
910
|
if colors is not None:
|
|
@@ -856,16 +914,16 @@ class CeilingLight(MatrixLight):
|
|
|
856
914
|
"Provided color cannot have brightness=0. "
|
|
857
915
|
"Omit the parameter to use current colors."
|
|
858
916
|
)
|
|
859
|
-
stored_colors = [colors] *
|
|
917
|
+
stored_colors = [colors] * self.downlight_zone_count
|
|
860
918
|
else:
|
|
861
919
|
if all(c.brightness == 0 for c in colors):
|
|
862
920
|
raise ValueError(
|
|
863
921
|
"Provided colors cannot have brightness=0. "
|
|
864
922
|
"Omit the parameter to use current colors."
|
|
865
923
|
)
|
|
866
|
-
if len(colors) !=
|
|
924
|
+
if len(colors) != self.downlight_zone_count:
|
|
867
925
|
raise ValueError(
|
|
868
|
-
f"Expected {
|
|
926
|
+
f"Expected {self.downlight_zone_count} colors for downlight, "
|
|
869
927
|
f"got {len(colors)}"
|
|
870
928
|
)
|
|
871
929
|
stored_colors = list(colors)
|
|
@@ -6,7 +6,7 @@ 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=4b5QtO0EFWxIqN2lUYgM8uLjWyHI5hUcReiF9QCjCGw,1061
|
|
8
8
|
lifx/devices/base.py,sha256=0G2PCJRNeIPkMCIw68x0ijn6gUIwh2jFlex8SN4Hs1Y,63530
|
|
9
|
-
lifx/devices/ceiling.py,sha256=
|
|
9
|
+
lifx/devices/ceiling.py,sha256=bLAurvqTNmhKMFUUJmLqn1vDFawapYju2i4G0pHOH_4,45790
|
|
10
10
|
lifx/devices/hev.py,sha256=T5hvt2q_vdgPBvThx_-M7n5pZu9pL0y9Fs3Zz_KL0NM,15588
|
|
11
11
|
lifx/devices/infrared.py,sha256=ePk9qxX_s-hv5gQMvio1Vv8FYiCd68HF0ySbWgSrvuU,8130
|
|
12
12
|
lifx/devices/light.py,sha256=gk92lhViUWINGaxDWbs4qn8Stnn2fGCfRkC5Kk0Q-hI,34087
|
|
@@ -42,7 +42,7 @@ lifx/theme/canvas.py,sha256=4h7lgN8iu_OdchObGDgbxTqQLCb-FRKC-M-YCWef_i4,8048
|
|
|
42
42
|
lifx/theme/generators.py,sha256=nq3Yvntq_h-eFHbmmow3LcAdA_hEbRRaP5mv9Bydrjk,6435
|
|
43
43
|
lifx/theme/library.py,sha256=tKlKZNqJp8lRGDnilWyDm_Qr1vCRGGwuvWVS82anNpQ,21326
|
|
44
44
|
lifx/theme/theme.py,sha256=qMEx_8E41C0Cc6f083XHiAXEglTv4YlXW0UFsG1rQKg,5521
|
|
45
|
-
lifx_async-4.7.
|
|
46
|
-
lifx_async-4.7.
|
|
47
|
-
lifx_async-4.7.
|
|
48
|
-
lifx_async-4.7.
|
|
45
|
+
lifx_async-4.7.5.dist-info/METADATA,sha256=1SN5XqtWLHrF_JtLHyWGNSCCeoajcu32g0MWFC48VIM,2609
|
|
46
|
+
lifx_async-4.7.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
47
|
+
lifx_async-4.7.5.dist-info/licenses/LICENSE,sha256=eBz48GRA3gSiWn3rYZAz2Ewp35snnhV9cSqkVBq7g3k,1832
|
|
48
|
+
lifx_async-4.7.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|