lifx-async 4.5.1__py3-none-any.whl → 4.6.0__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/__init__.py +2 -0
- lifx/devices/__init__.py +2 -1
- lifx/devices/base.py +17 -3
- lifx/devices/ceiling.py +150 -2
- {lifx_async-4.5.1.dist-info → lifx_async-4.6.0.dist-info}/METADATA +1 -1
- {lifx_async-4.5.1.dist-info → lifx_async-4.6.0.dist-info}/RECORD +8 -8
- {lifx_async-4.5.1.dist-info → lifx_async-4.6.0.dist-info}/WHEEL +0 -0
- {lifx_async-4.5.1.dist-info → lifx_async-4.6.0.dist-info}/licenses/LICENSE +0 -0
lifx/__init__.py
CHANGED
|
@@ -17,6 +17,7 @@ from lifx.api import (
|
|
|
17
17
|
from lifx.color import HSBK, Colors
|
|
18
18
|
from lifx.devices import (
|
|
19
19
|
CeilingLight,
|
|
20
|
+
CeilingLightState,
|
|
20
21
|
Device,
|
|
21
22
|
DeviceInfo,
|
|
22
23
|
DeviceVersion,
|
|
@@ -73,6 +74,7 @@ __all__ = [
|
|
|
73
74
|
"MatrixLight",
|
|
74
75
|
"MatrixLightState",
|
|
75
76
|
"CeilingLight",
|
|
77
|
+
"CeilingLightState",
|
|
76
78
|
# Color
|
|
77
79
|
"HSBK",
|
|
78
80
|
"Colors",
|
lifx/devices/__init__.py
CHANGED
|
@@ -10,7 +10,7 @@ from lifx.devices.base import (
|
|
|
10
10
|
FirmwareInfo,
|
|
11
11
|
WifiInfo,
|
|
12
12
|
)
|
|
13
|
-
from lifx.devices.ceiling import CeilingLight
|
|
13
|
+
from lifx.devices.ceiling import CeilingLight, CeilingLightState
|
|
14
14
|
from lifx.devices.hev import HevLight, HevLightState
|
|
15
15
|
from lifx.devices.infrared import InfraredLight, InfraredLightState
|
|
16
16
|
from lifx.devices.light import Light, LightState
|
|
@@ -19,6 +19,7 @@ from lifx.devices.multizone import MultiZoneEffect, MultiZoneLight, MultiZoneLig
|
|
|
19
19
|
|
|
20
20
|
__all__ = [
|
|
21
21
|
"CeilingLight",
|
|
22
|
+
"CeilingLightState",
|
|
22
23
|
"CollectionInfo",
|
|
23
24
|
"Device",
|
|
24
25
|
"DeviceInfo",
|
lifx/devices/base.py
CHANGED
|
@@ -26,7 +26,14 @@ from lifx.protocol import packets
|
|
|
26
26
|
from lifx.protocol.models import Serial
|
|
27
27
|
|
|
28
28
|
if TYPE_CHECKING:
|
|
29
|
-
from lifx.devices import
|
|
29
|
+
from lifx.devices import (
|
|
30
|
+
CeilingLight,
|
|
31
|
+
HevLight,
|
|
32
|
+
InfraredLight,
|
|
33
|
+
Light,
|
|
34
|
+
MatrixLight,
|
|
35
|
+
MultiZoneLight,
|
|
36
|
+
)
|
|
30
37
|
|
|
31
38
|
_LOGGER = logging.getLogger(__name__)
|
|
32
39
|
|
|
@@ -509,7 +516,7 @@ class Device(Generic[StateT]):
|
|
|
509
516
|
port: int = LIFX_UDP_PORT,
|
|
510
517
|
timeout: float = DEFAULT_REQUEST_TIMEOUT,
|
|
511
518
|
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
512
|
-
) -> Light | HevLight | InfraredLight | MultiZoneLight | MatrixLight:
|
|
519
|
+
) -> Light | HevLight | InfraredLight | MultiZoneLight | MatrixLight | CeilingLight:
|
|
513
520
|
"""Create and return a fully initialized device instance.
|
|
514
521
|
|
|
515
522
|
This factory method creates the appropriate device type (Light, etc)
|
|
@@ -610,7 +617,14 @@ class Device(Generic[StateT]):
|
|
|
610
617
|
|
|
611
618
|
device_class: type[Device] = cls
|
|
612
619
|
|
|
613
|
-
|
|
620
|
+
# Check for ceiling products first (subset of matrix devices)
|
|
621
|
+
from lifx.products import is_ceiling_product
|
|
622
|
+
|
|
623
|
+
if is_ceiling_product(version.product):
|
|
624
|
+
from lifx.devices.ceiling import CeilingLight
|
|
625
|
+
|
|
626
|
+
device_class = CeilingLight
|
|
627
|
+
elif product_info.has_matrix:
|
|
614
628
|
from lifx.devices.matrix import MatrixLight
|
|
615
629
|
|
|
616
630
|
device_class = MatrixLight
|
lifx/devices/ceiling.py
CHANGED
|
@@ -20,11 +20,13 @@ from __future__ import annotations
|
|
|
20
20
|
|
|
21
21
|
import json
|
|
22
22
|
import logging
|
|
23
|
+
import time
|
|
24
|
+
from dataclasses import asdict, dataclass
|
|
23
25
|
from pathlib import Path
|
|
24
|
-
from typing import TYPE_CHECKING
|
|
26
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
25
27
|
|
|
26
28
|
from lifx.color import HSBK
|
|
27
|
-
from lifx.devices.matrix import MatrixLight
|
|
29
|
+
from lifx.devices.matrix import MatrixLight, MatrixLightState
|
|
28
30
|
from lifx.exceptions import LifxError
|
|
29
31
|
from lifx.products import get_ceiling_layout, is_ceiling_product
|
|
30
32
|
|
|
@@ -34,6 +36,81 @@ if TYPE_CHECKING:
|
|
|
34
36
|
_LOGGER = logging.getLogger(__name__)
|
|
35
37
|
|
|
36
38
|
|
|
39
|
+
@dataclass
|
|
40
|
+
class CeilingLightState(MatrixLightState):
|
|
41
|
+
"""Ceiling light device state with uplight/downlight component control.
|
|
42
|
+
|
|
43
|
+
Extends MatrixLightState with ceiling-specific component information.
|
|
44
|
+
|
|
45
|
+
Attributes:
|
|
46
|
+
uplight_color: Current HSBK color of the uplight component
|
|
47
|
+
downlight_colors: List of HSBK colors for each downlight zone
|
|
48
|
+
uplight_is_on: Whether uplight component is on (brightness > 0)
|
|
49
|
+
downlight_is_on: Whether downlight component is on (any zone brightness > 0)
|
|
50
|
+
uplight_zone: Zone index for the uplight component
|
|
51
|
+
downlight_zones: Slice representing downlight component zones
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
uplight_color: HSBK
|
|
55
|
+
downlight_colors: list[HSBK]
|
|
56
|
+
uplight_is_on: bool
|
|
57
|
+
downlight_is_on: bool
|
|
58
|
+
uplight_zone: int
|
|
59
|
+
downlight_zones: slice
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def as_dict(self) -> Any:
|
|
63
|
+
"""Return CeilingLightState as dict."""
|
|
64
|
+
return asdict(self)
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def from_matrix_state(
|
|
68
|
+
cls,
|
|
69
|
+
matrix_state: MatrixLightState,
|
|
70
|
+
uplight_color: HSBK,
|
|
71
|
+
downlight_colors: list[HSBK],
|
|
72
|
+
uplight_zone: int,
|
|
73
|
+
downlight_zones: slice,
|
|
74
|
+
) -> CeilingLightState:
|
|
75
|
+
"""Create CeilingLightState from MatrixLightState.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
matrix_state: Base MatrixLightState to extend
|
|
79
|
+
uplight_color: Current uplight zone color
|
|
80
|
+
downlight_colors: Current downlight zone colors
|
|
81
|
+
uplight_zone: Zone index for uplight component
|
|
82
|
+
downlight_zones: Slice representing downlight component zones
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
CeilingLightState with all matrix state plus ceiling components
|
|
86
|
+
"""
|
|
87
|
+
return cls(
|
|
88
|
+
model=matrix_state.model,
|
|
89
|
+
label=matrix_state.label,
|
|
90
|
+
serial=matrix_state.serial,
|
|
91
|
+
mac_address=matrix_state.mac_address,
|
|
92
|
+
power=matrix_state.power,
|
|
93
|
+
capabilities=matrix_state.capabilities,
|
|
94
|
+
host_firmware=matrix_state.host_firmware,
|
|
95
|
+
wifi_firmware=matrix_state.wifi_firmware,
|
|
96
|
+
location=matrix_state.location,
|
|
97
|
+
group=matrix_state.group,
|
|
98
|
+
color=matrix_state.color,
|
|
99
|
+
chain=matrix_state.chain,
|
|
100
|
+
tile_orientations=matrix_state.tile_orientations,
|
|
101
|
+
tile_colors=matrix_state.tile_colors,
|
|
102
|
+
tile_count=matrix_state.tile_count,
|
|
103
|
+
effect=matrix_state.effect,
|
|
104
|
+
uplight_color=uplight_color,
|
|
105
|
+
downlight_colors=downlight_colors,
|
|
106
|
+
uplight_is_on=uplight_color.brightness > 0,
|
|
107
|
+
downlight_is_on=any(c.brightness > 0 for c in downlight_colors),
|
|
108
|
+
uplight_zone=uplight_zone,
|
|
109
|
+
downlight_zones=downlight_zones,
|
|
110
|
+
last_updated=time.time(),
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
37
114
|
class CeilingLight(MatrixLight):
|
|
38
115
|
"""LIFX Ceiling Light with independent uplight and downlight control.
|
|
39
116
|
|
|
@@ -111,6 +188,63 @@ class CeilingLight(MatrixLight):
|
|
|
111
188
|
|
|
112
189
|
return self
|
|
113
190
|
|
|
191
|
+
async def _initialize_state(self) -> CeilingLightState:
|
|
192
|
+
"""Initialize ceiling light state transactionally.
|
|
193
|
+
|
|
194
|
+
Extends MatrixLight implementation to add ceiling-specific component state.
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
CeilingLightState instance with all device, light, matrix,
|
|
198
|
+
and ceiling component information.
|
|
199
|
+
|
|
200
|
+
Raises:
|
|
201
|
+
LifxTimeoutError: If device does not respond within timeout
|
|
202
|
+
LifxDeviceNotFoundError: If device cannot be reached
|
|
203
|
+
LifxProtocolError: If responses are invalid
|
|
204
|
+
"""
|
|
205
|
+
matrix_state = await super()._initialize_state()
|
|
206
|
+
|
|
207
|
+
# Get ceiling component colors
|
|
208
|
+
uplight_color = await self.get_uplight_color()
|
|
209
|
+
downlight_colors = await self.get_downlight_colors()
|
|
210
|
+
|
|
211
|
+
# Create ceiling state from matrix state
|
|
212
|
+
ceiling_state = CeilingLightState.from_matrix_state(
|
|
213
|
+
matrix_state=matrix_state,
|
|
214
|
+
uplight_color=uplight_color,
|
|
215
|
+
downlight_colors=downlight_colors,
|
|
216
|
+
uplight_zone=self.uplight_zone,
|
|
217
|
+
downlight_zones=self.downlight_zones,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# Store in _state - cast is used in state property to access ceiling fields
|
|
221
|
+
self._state = ceiling_state
|
|
222
|
+
|
|
223
|
+
return ceiling_state
|
|
224
|
+
|
|
225
|
+
async def refresh_state(self) -> None:
|
|
226
|
+
"""Refresh ceiling light state from hardware.
|
|
227
|
+
|
|
228
|
+
Fetches color, tiles, tile colors, effect, and ceiling component state.
|
|
229
|
+
|
|
230
|
+
Raises:
|
|
231
|
+
RuntimeError: If state has not been initialized
|
|
232
|
+
LifxTimeoutError: If device does not respond
|
|
233
|
+
LifxDeviceNotFoundError: If device cannot be reached
|
|
234
|
+
"""
|
|
235
|
+
await super().refresh_state()
|
|
236
|
+
|
|
237
|
+
# Get ceiling component colors
|
|
238
|
+
uplight_color = await self.get_uplight_color()
|
|
239
|
+
downlight_colors = await self.get_downlight_colors()
|
|
240
|
+
|
|
241
|
+
# Update ceiling-specific state fields
|
|
242
|
+
state = cast(CeilingLightState, self._state)
|
|
243
|
+
state.uplight_color = uplight_color
|
|
244
|
+
state.downlight_colors = downlight_colors
|
|
245
|
+
state.uplight_is_on = uplight_color.brightness > 0
|
|
246
|
+
state.downlight_is_on = any(c.brightness > 0 for c in downlight_colors)
|
|
247
|
+
|
|
114
248
|
@classmethod
|
|
115
249
|
async def from_ip(
|
|
116
250
|
cls,
|
|
@@ -148,6 +282,20 @@ class CeilingLight(MatrixLight):
|
|
|
148
282
|
ceiling.connection = device.connection
|
|
149
283
|
return ceiling
|
|
150
284
|
|
|
285
|
+
@property
|
|
286
|
+
def state(self) -> CeilingLightState:
|
|
287
|
+
"""Get Ceiling light state.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
CeilingLightState with current state information.
|
|
291
|
+
|
|
292
|
+
Raises:
|
|
293
|
+
RuntimeError: If accessed before state initialization.
|
|
294
|
+
"""
|
|
295
|
+
if self._state is None:
|
|
296
|
+
raise RuntimeError("State not found.")
|
|
297
|
+
return cast(CeilingLightState, self._state)
|
|
298
|
+
|
|
151
299
|
@property
|
|
152
300
|
def uplight_zone(self) -> int:
|
|
153
301
|
"""Zone index of the uplight component.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
lifx/__init__.py,sha256=
|
|
1
|
+
lifx/__init__.py,sha256=aiMLKLhmcXADJyeISNHIZ_Nuc6jEhPG8-I_R3peWpwo,2610
|
|
2
2
|
lifx/api.py,sha256=PFS2b28ow40kCQvT_MKvBLZD6fKCbvsoOQFtiODDrPE,33861
|
|
3
3
|
lifx/color.py,sha256=wcmeeiBmOAjunInERNd6rslKvBEpV4vfjwwiZ8v7H8A,17877
|
|
4
4
|
lifx/const.py,sha256=cf_O_3TqJjIBXF1tI35PkJ1JOhmy4tRt14PSa63pilA,3471
|
|
5
5
|
lifx/exceptions.py,sha256=pikAMppLn7gXyjiQVWM_tSvXKNh-g366nG_UWyqpHhc,815
|
|
6
6
|
lifx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
lifx/devices/__init__.py,sha256=
|
|
8
|
-
lifx/devices/base.py,sha256=
|
|
9
|
-
lifx/devices/ceiling.py,sha256=
|
|
7
|
+
lifx/devices/__init__.py,sha256=4b5QtO0EFWxIqN2lUYgM8uLjWyHI5hUcReiF9QCjCGw,1061
|
|
8
|
+
lifx/devices/base.py,sha256=0G2PCJRNeIPkMCIw68x0ijn6gUIwh2jFlex8SN4Hs1Y,63530
|
|
9
|
+
lifx/devices/ceiling.py,sha256=Y4lwLWyQr8KtrwX3FMo3R_WKBn7CBxk-pNUsjfPXLgk,32981
|
|
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.
|
|
46
|
-
lifx_async-4.
|
|
47
|
-
lifx_async-4.
|
|
48
|
-
lifx_async-4.
|
|
45
|
+
lifx_async-4.6.0.dist-info/METADATA,sha256=MONJFD1mggSLhTieobasroj1mECAgXBS2IndKq9Poq0,2609
|
|
46
|
+
lifx_async-4.6.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
47
|
+
lifx_async-4.6.0.dist-info/licenses/LICENSE,sha256=eBz48GRA3gSiWn3rYZAz2Ewp35snnhV9cSqkVBq7g3k,1832
|
|
48
|
+
lifx_async-4.6.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|