lifx-async 4.4.0__py3-none-any.whl → 4.4.1__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/matrix.py CHANGED
@@ -14,7 +14,6 @@ Terminology:
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- import asyncio
18
17
  import logging
19
18
  import time
20
19
  from dataclasses import asdict, dataclass
@@ -544,6 +543,57 @@ class MatrixLight(Light):
544
543
 
545
544
  return result
546
545
 
546
+ async def get_all_tile_colors(self) -> list[list[HSBK]]:
547
+ """Get colors for all tiles in the chain.
548
+
549
+ Fetches colors from each tile in the device chain and returns them
550
+ as a list of color lists (one per tile). This is the matrix equivalent
551
+ of MultiZoneLight's get_all_color_zones().
552
+
553
+ Always fetches from device. Tiles are queried sequentially to avoid
554
+ overwhelming the device with concurrent requests.
555
+
556
+ Returns:
557
+ List of color lists, one per tile. Each inner list contains
558
+ the colors for that tile (typically 64 for 8x8 tiles).
559
+
560
+ Raises:
561
+ LifxDeviceNotFoundError: If device is not connected
562
+ LifxTimeoutError: If device does not respond
563
+ LifxUnsupportedCommandError: If device doesn't support this command
564
+
565
+ Example:
566
+ ```python
567
+ # Get colors for all tiles
568
+ all_colors = await matrix.get_all_tile_colors()
569
+ print(f"Device has {len(all_colors)} tiles")
570
+ for i, tile_colors in enumerate(all_colors):
571
+ print(f"Tile {i}: {len(tile_colors)} colors")
572
+
573
+ # Flatten to single list if needed
574
+ flat_colors = [c for tile in all_colors for c in tile]
575
+ ```
576
+ """
577
+ # Get device chain (use cached if available)
578
+ if self._device_chain is None:
579
+ device_chain = await self.get_device_chain()
580
+ else:
581
+ device_chain = self._device_chain
582
+
583
+ # Fetch colors from each tile sequentially
584
+ all_colors: list[list[HSBK]] = []
585
+ for tile in device_chain:
586
+ tile_colors = await self.get64(tile_index=tile.tile_index)
587
+ all_colors.append(tile_colors)
588
+
589
+ # Update state if it exists (flatten for state storage)
590
+ if self._state is not None and hasattr(self._state, "tile_colors"):
591
+ flat_colors = [c for tile_colors in all_colors for c in tile_colors]
592
+ self._state.tile_colors = flat_colors
593
+ self._state.last_updated = time.time()
594
+
595
+ return all_colors
596
+
547
597
  async def set64(
548
598
  self,
549
599
  tile_index: int,
@@ -993,8 +1043,13 @@ class MatrixLight(Light):
993
1043
  canvas = Canvas()
994
1044
  for tile in tiles:
995
1045
  canvas.add_points_for_tile((int(tile.user_x), int(tile.user_y)), theme)
996
- canvas.shuffle_points()
997
- canvas.blur_by_distance()
1046
+
1047
+ # Shuffle and blur ONCE after all points are added
1048
+ # (Previously these were inside the loop, causing earlier tiles' points
1049
+ # to be shuffled/blurred multiple times, displacing them from their
1050
+ # intended positions and losing theme color variety)
1051
+ canvas.shuffle_points()
1052
+ canvas.blur_by_distance()
998
1053
 
999
1054
  # Create tile canvas and fill in gaps for smooth interpolation
1000
1055
  tile_canvas = Canvas()
@@ -1068,7 +1123,7 @@ class MatrixLight(Light):
1068
1123
  async def refresh_state(self) -> None:
1069
1124
  """Refresh matrix light state from hardware.
1070
1125
 
1071
- Fetches color, tiles, tile colors, and effect.
1126
+ Fetches color, tiles, tile colors for all tiles, and effect.
1072
1127
 
1073
1128
  Raises:
1074
1129
  RuntimeError: If state has not been initialized
@@ -1077,15 +1132,12 @@ class MatrixLight(Light):
1077
1132
  """
1078
1133
  await super().refresh_state()
1079
1134
 
1080
- # Fetch all matrix light state
1081
- async with asyncio.TaskGroup() as tg:
1082
- colors_task = tg.create_task(self.get64())
1083
- effect_task = tg.create_task(self.get_effect())
1084
-
1085
- tile_colors = colors_task.result()
1086
- effect = effect_task.result()
1135
+ # Fetch all matrix light state sequentially to avoid overwhelming device
1136
+ all_tile_colors = await self.get_all_tile_colors()
1137
+ effect = await self.get_effect()
1087
1138
 
1088
- self._state.tile_colors = tile_colors
1139
+ # Flatten tile colors for state storage
1140
+ self._state.tile_colors = [c for tile in all_tile_colors for c in tile]
1089
1141
  self._state.effect = effect.effect_type
1090
1142
 
1091
1143
  async def _initialize_state(self) -> MatrixLightState:
@@ -1103,24 +1155,24 @@ class MatrixLight(Light):
1103
1155
  """
1104
1156
  light_state = await super()._initialize_state()
1105
1157
 
1106
- async with asyncio.TaskGroup() as tg:
1107
- chain_task = tg.create_task(self.get_device_chain())
1108
- tile_colors_task = tg.create_task(self.get64())
1109
- effect_task = tg.create_task(self.get_effect())
1110
-
1111
- chain = chain_task.result()
1158
+ # Fetch matrix-specific state sequentially to avoid overwhelming device
1159
+ chain = await self.get_device_chain()
1112
1160
  tile_orientations = {
1113
1161
  index: tile.nearest_orientation for index, tile in enumerate(chain)
1114
1162
  }
1115
- tile_colors = tile_colors_task.result()
1116
- effect = effect_task.result()
1163
+ # get_all_tile_colors uses cached chain from above
1164
+ all_tile_colors = await self.get_all_tile_colors()
1165
+ effect = await self.get_effect()
1166
+
1167
+ # Flatten tile colors for state storage
1168
+ flat_tile_colors = [c for tile in all_tile_colors for c in tile]
1117
1169
 
1118
1170
  # Create state instance with matrix fields
1119
1171
  self._state = MatrixLightState.from_light_state(
1120
1172
  light_state,
1121
1173
  chain=chain,
1122
1174
  tile_orientations=tile_orientations,
1123
- tile_colors=tile_colors,
1175
+ tile_colors=flat_tile_colors,
1124
1176
  effect=effect.effect_type,
1125
1177
  )
1126
1178
 
lifx/theme/generators.py CHANGED
@@ -165,10 +165,16 @@ class MatrixGenerator:
165
165
  shuffled_theme = theme.shuffled()
166
166
  shuffled_theme.ensure_color()
167
167
 
168
+ # Add points for all tiles first
168
169
  for (left_x, top_y), (width, height) in self.coords_and_sizes:
169
170
  canvas.add_points_for_tile((left_x, top_y), shuffled_theme)
170
- canvas.shuffle_points()
171
- canvas.blur_by_distance()
171
+
172
+ # Shuffle and blur ONCE after all points are added
173
+ # (Previously these were inside the loop, causing earlier tiles' points
174
+ # to be shuffled/blurred multiple times, displacing them from their
175
+ # intended positions and losing theme color variety)
176
+ canvas.shuffle_points()
177
+ canvas.blur_by_distance()
172
178
 
173
179
  # Create tile canvas and fill gaps
174
180
  tile_canvas = Canvas()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lifx-async
3
- Version: 4.4.0
3
+ Version: 4.4.1
4
4
  Summary: A modern, type-safe, async Python library for controlling LIFX lights
5
5
  Author-email: Avi Miller <me@dje.li>
6
6
  Maintainer-email: Avi Miller <me@dje.li>
@@ -9,7 +9,7 @@ lifx/devices/base.py,sha256=x2RlGeCv60QLKklP6kA9wbCc3rmcHHhmvkSJHqTow5s,63151
9
9
  lifx/devices/hev.py,sha256=T5hvt2q_vdgPBvThx_-M7n5pZu9pL0y9Fs3Zz_KL0NM,15588
10
10
  lifx/devices/infrared.py,sha256=ePk9qxX_s-hv5gQMvio1Vv8FYiCd68HF0ySbWgSrvuU,8130
11
11
  lifx/devices/light.py,sha256=gk92lhViUWINGaxDWbs4qn8Stnn2fGCfRkC5Kk0Q-hI,34087
12
- lifx/devices/matrix.py,sha256=pjG8BkOf8vPKRvGggJip9m_exXF9nEFVP3j6ZLDoZbk,38667
12
+ lifx/devices/matrix.py,sha256=8Z0FbBGUzRhvqs3h9fL9ZQ691C9mAoA6kuOrhe89Qwk,41061
13
13
  lifx/devices/multizone.py,sha256=8OJ6zP5xgSCmlMQDj2mLUZ352EMkbYMbDZ1X-Cux7AU,32786
14
14
  lifx/effects/__init__.py,sha256=4DF31yp7RJic5JoltMlz5dCtF5KQobU6NOUtLUKkVKE,1509
15
15
  lifx/effects/base.py,sha256=YO0Hbg2VYHKPtfYnWxmrtzYoPGOi9BUXhn8HVFKv5IM,10283
@@ -37,10 +37,10 @@ lifx/protocol/protocol_types.py,sha256=m15A82zVrwAXomTqo-GfNmAIynVRDSV94UqHDkWgi
37
37
  lifx/protocol/serializer.py,sha256=Cl87-Y8_LnvqFANjorJK2CMoRtBGksB_Eq07xHMTqH0,10387
38
38
  lifx/theme/__init__.py,sha256=dg4Y25dYq22EemFyxQ1fyb3D_bP2hhxGCd9BE1g_hvk,1320
39
39
  lifx/theme/canvas.py,sha256=4h7lgN8iu_OdchObGDgbxTqQLCb-FRKC-M-YCWef_i4,8048
40
- lifx/theme/generators.py,sha256=L0X6_iApLx6XDboGlYunaVsl6nvUCqMfn23VQmRkyCk,6125
40
+ lifx/theme/generators.py,sha256=nq3Yvntq_h-eFHbmmow3LcAdA_hEbRRaP5mv9Bydrjk,6435
41
41
  lifx/theme/library.py,sha256=tKlKZNqJp8lRGDnilWyDm_Qr1vCRGGwuvWVS82anNpQ,21326
42
42
  lifx/theme/theme.py,sha256=qMEx_8E41C0Cc6f083XHiAXEglTv4YlXW0UFsG1rQKg,5521
43
- lifx_async-4.4.0.dist-info/METADATA,sha256=Ptnm4qrRJQQTnftUZWq_Fpj0PGT-rTlEFtYk3RlyERs,2609
44
- lifx_async-4.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
45
- lifx_async-4.4.0.dist-info/licenses/LICENSE,sha256=eBz48GRA3gSiWn3rYZAz2Ewp35snnhV9cSqkVBq7g3k,1832
46
- lifx_async-4.4.0.dist-info/RECORD,,
43
+ lifx_async-4.4.1.dist-info/METADATA,sha256=GPXITqP1r-6RIp91S1SuabkN4ie0cJxMvM498v3AKwg,2609
44
+ lifx_async-4.4.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
45
+ lifx_async-4.4.1.dist-info/licenses/LICENSE,sha256=eBz48GRA3gSiWn3rYZAz2Ewp35snnhV9cSqkVBq7g3k,1832
46
+ lifx_async-4.4.1.dist-info/RECORD,,