lifx-async 4.3.0__tar.gz → 4.3.2__tar.gz
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_async-4.3.0 → lifx_async-4.3.2}/.github/workflows/pr-automation.yml +2 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/PKG-INFO +1 -1
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/changelog.md +16 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/pyproject.toml +1 -1
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/devices/matrix.py +8 -8
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/effects/base.py +10 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/effects/colorloop.py +9 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/effects/pulse.py +9 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_devices/test_matrix.py +22 -22
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_effects/test_base.py +5 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_effects/test_colorloop.py +1 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_effects/test_integration.py +5 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_effects/test_models.py +5 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_effects/test_pulse.py +1 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/uv.lock +1 -1
- {lifx_async-4.3.0 → lifx_async-4.3.2}/.claude/settings.json +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/.github/dependabot.yml +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/.github/labeler.yml +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/.github/workflows/ci.yml +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/.github/workflows/docs.yml +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/.gitignore +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/.pre-commit-config.yaml +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/CLAUDE.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/LICENSE +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/README.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/api/colors.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/api/devices.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/api/effects.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/api/exceptions.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/api/high-level.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/api/index.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/api/network.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/api/protocol.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/api/themes.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/architecture/effects-architecture.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/architecture/overview.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/faq.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/getting-started/effects.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/getting-started/installation.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/getting-started/quickstart.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/getting-started/themes.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/index.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/migration/effect-api-changes.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/stylesheets/extra.css +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/user-guide/advanced-usage.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/user-guide/effects-custom.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/user-guide/effects-troubleshooting.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/user-guide/protocol-deep-dive.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/user-guide/themes.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/docs/user-guide/troubleshooting.md +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/examples/01_simple_discovery.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/examples/02_simple_control.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/examples/03_waveforms.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/examples/04_logging.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/examples/06_pulse_effect.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/examples/07_colorloop_effect.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/examples/08_custom_effect.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/examples/09_background_effect.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/examples/10_find_specific_devices.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/examples/11_matrix_basic.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/examples/12_matrix_effects.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/examples/13_matrix_large.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/mkdocs.yml +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/renovate.json +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/api.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/color.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/const.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/devices/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/devices/base.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/devices/hev.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/devices/infrared.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/devices/light.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/devices/multizone.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/effects/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/effects/conductor.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/effects/const.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/effects/models.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/effects/state_manager.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/exceptions.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/network/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/network/connection.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/network/discovery.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/network/message.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/network/transport.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/products/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/products/generator.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/products/registry.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/protocol/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/protocol/base.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/protocol/generator.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/protocol/header.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/protocol/models.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/protocol/packets.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/protocol/protocol_types.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/protocol/serializer.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/py.typed +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/theme/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/theme/canvas.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/theme/generators.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/theme/library.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/src/lifx/theme/theme.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/conftest.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_api/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_api/test_api_apply_theme.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_api/test_api_batch_errors.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_api/test_api_batch_operations.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_api/test_api_discovery.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_api/test_api_organization.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_color.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_devices/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_devices/conftest.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_devices/test_base.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_devices/test_hev.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_devices/test_infrared.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_devices/test_light.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_devices/test_mac_address.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_devices/test_multizone.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_effects/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_effects/test_capability_filtering.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_effects/test_state_manager.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_network/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_network/test_concurrent_requests.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_network/test_connection.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_network/test_discovery_devices.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_network/test_discovery_errors.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_network/test_message.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_network/test_message_advanced.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_network/test_transport.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_products/test_product_generator.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_products/test_registry.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_protocol/test_generated.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_protocol/test_header.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_protocol/test_protocol_generator.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_protocol/test_serializer.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_theme/__init__.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_theme/conftest.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_theme/test_apply_theme.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_theme/test_canvas.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_theme/test_generators.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_theme/test_library.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_theme/test_theme.py +0 -0
- {lifx_async-4.3.0 → lifx_async-4.3.2}/tests/test_utils.py +0 -0
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- version list -->
|
|
4
4
|
|
|
5
|
+
## v4.3.2 (2025-11-22)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- **effects**: Add name property to LIFXEffect and subclasses
|
|
10
|
+
([`deb8a54`](https://github.com/Djelibeybi/lifx-async/commit/deb8a54f674d2d4cd9b8dce519dc6ca8678e048a))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## v4.3.1 (2025-11-22)
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- Actually rename the matrix methods
|
|
18
|
+
([`061aaa7`](https://github.com/Djelibeybi/lifx-async/commit/061aaa7c1931b2fc606363d5acc14ec7fa1b039b))
|
|
19
|
+
|
|
20
|
+
|
|
5
21
|
## v4.3.0 (2025-11-22)
|
|
6
22
|
|
|
7
23
|
### Features
|
|
@@ -683,17 +683,17 @@ class MatrixLight(Light):
|
|
|
683
683
|
colors=colors,
|
|
684
684
|
)
|
|
685
685
|
|
|
686
|
-
async def
|
|
687
|
-
"""Get current running
|
|
686
|
+
async def get_effect(self) -> MatrixEffect:
|
|
687
|
+
"""Get current running matrix effect.
|
|
688
688
|
|
|
689
689
|
Returns:
|
|
690
690
|
MatrixEffect describing the current effect state
|
|
691
691
|
|
|
692
692
|
Example:
|
|
693
|
-
>>> effect = await matrix.
|
|
693
|
+
>>> effect = await matrix.get_effect()
|
|
694
694
|
>>> print(f"Effect type: {effect.effect_type}")
|
|
695
695
|
"""
|
|
696
|
-
_LOGGER.debug("Getting
|
|
696
|
+
_LOGGER.debug("Getting matrix effect for %s", self.label or self.serial)
|
|
697
697
|
|
|
698
698
|
response: packets.Tile.StateEffect = await self.connection.request(
|
|
699
699
|
packets.Tile.GetEffect()
|
|
@@ -720,7 +720,7 @@ class MatrixLight(Light):
|
|
|
720
720
|
self._tile_effect = effect
|
|
721
721
|
return effect
|
|
722
722
|
|
|
723
|
-
async def
|
|
723
|
+
async def set_effect(
|
|
724
724
|
self,
|
|
725
725
|
effect_type: FirmwareEffect,
|
|
726
726
|
speed: int = 3000,
|
|
@@ -730,7 +730,7 @@ class MatrixLight(Light):
|
|
|
730
730
|
cloud_saturation_min: int = 0,
|
|
731
731
|
cloud_saturation_max: int = 0,
|
|
732
732
|
) -> None:
|
|
733
|
-
"""Set
|
|
733
|
+
"""Set matrix effect with configuration.
|
|
734
734
|
|
|
735
735
|
Args:
|
|
736
736
|
effect_type: Type of effect (OFF, MORPH, FLAME, SKY)
|
|
@@ -749,14 +749,14 @@ class MatrixLight(Light):
|
|
|
749
749
|
... HSBK(120, 1.0, 1.0, 3500), # Green
|
|
750
750
|
... HSBK(240, 1.0, 1.0, 3500), # Blue
|
|
751
751
|
... ]
|
|
752
|
-
>>> await matrix.
|
|
752
|
+
>>> await matrix.set_effect(
|
|
753
753
|
... effect_type=FirmwareEffect.MORPH,
|
|
754
754
|
... speed=5000,
|
|
755
755
|
... palette=rainbow,
|
|
756
756
|
... )
|
|
757
757
|
"""
|
|
758
758
|
_LOGGER.debug(
|
|
759
|
-
"Setting
|
|
759
|
+
"Setting matrix effect %s (speed=%d) for %s",
|
|
760
760
|
effect_type,
|
|
761
761
|
speed,
|
|
762
762
|
self.label or self.serial,
|
|
@@ -59,6 +59,16 @@ class LIFXEffect(ABC):
|
|
|
59
59
|
self.conductor: Conductor | None = None
|
|
60
60
|
self.participants: list[Light] = []
|
|
61
61
|
|
|
62
|
+
@property
|
|
63
|
+
@abstractmethod
|
|
64
|
+
def name(self) -> str:
|
|
65
|
+
"""Return the name of the effect.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
The effect name as a string
|
|
69
|
+
"""
|
|
70
|
+
raise NotImplementedError("Subclasses must implement name property")
|
|
71
|
+
|
|
62
72
|
async def async_perform(self, participants: list[Light]) -> None:
|
|
63
73
|
"""Perform common setup and play the effect.
|
|
64
74
|
|
|
@@ -127,6 +127,15 @@ class EffectColorloop(LIFXEffect):
|
|
|
127
127
|
self._running = False
|
|
128
128
|
self._stop_event = asyncio.Event()
|
|
129
129
|
|
|
130
|
+
@property
|
|
131
|
+
def name(self) -> str:
|
|
132
|
+
"""Return the name of the effect.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
The effect name 'colorloop'
|
|
136
|
+
"""
|
|
137
|
+
return "colorloop"
|
|
138
|
+
|
|
130
139
|
async def async_play(self) -> None:
|
|
131
140
|
"""Execute the colorloop effect continuously."""
|
|
132
141
|
self._running = True
|
|
@@ -136,6 +136,15 @@ class EffectPulse(LIFXEffect):
|
|
|
136
136
|
if self.cycles < 1:
|
|
137
137
|
raise ValueError(f"Cycles must be 1 or higher, got {self.cycles}")
|
|
138
138
|
|
|
139
|
+
@property
|
|
140
|
+
def name(self) -> str:
|
|
141
|
+
"""Return the name of the effect.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
The effect name 'pulse'
|
|
145
|
+
"""
|
|
146
|
+
return "pulse"
|
|
147
|
+
|
|
139
148
|
async def async_play(self) -> None:
|
|
140
149
|
"""Execute the pulse effect on all participants."""
|
|
141
150
|
# Determine colors for each light
|
|
@@ -186,11 +186,11 @@ class TestMatrixLight:
|
|
|
186
186
|
assert colors[0].saturation > 0.9
|
|
187
187
|
assert colors[0].brightness > 0.9
|
|
188
188
|
|
|
189
|
-
async def
|
|
189
|
+
async def test_get_effect(self, emulator_devices) -> None:
|
|
190
190
|
"""Test getting current tile effect."""
|
|
191
191
|
matrix = emulator_devices[6]
|
|
192
192
|
async with matrix:
|
|
193
|
-
effect = await matrix.
|
|
193
|
+
effect = await matrix.get_effect()
|
|
194
194
|
|
|
195
195
|
assert isinstance(effect, MatrixEffect)
|
|
196
196
|
assert isinstance(effect.effect_type, FirmwareEffect)
|
|
@@ -204,14 +204,14 @@ class TestMatrixLight:
|
|
|
204
204
|
matrix = emulator_devices[6]
|
|
205
205
|
async with matrix:
|
|
206
206
|
# Fetch tile effect
|
|
207
|
-
effect = await matrix.
|
|
207
|
+
effect = await matrix.get_effect()
|
|
208
208
|
|
|
209
209
|
# Should be cached in property
|
|
210
210
|
assert matrix.tile_effect is not None
|
|
211
211
|
assert isinstance(matrix.tile_effect, MatrixEffect)
|
|
212
212
|
assert matrix.tile_effect == effect
|
|
213
213
|
|
|
214
|
-
async def
|
|
214
|
+
async def test_set_effect_morph(self, emulator_devices) -> None:
|
|
215
215
|
"""Test setting MORPH effect."""
|
|
216
216
|
matrix = emulator_devices[6]
|
|
217
217
|
async with matrix:
|
|
@@ -223,18 +223,18 @@ class TestMatrixLight:
|
|
|
223
223
|
HSBK(240, 1.0, 1.0, 3500), # Blue
|
|
224
224
|
]
|
|
225
225
|
|
|
226
|
-
await matrix.
|
|
226
|
+
await matrix.set_effect(
|
|
227
227
|
effect_type=FirmwareEffect.MORPH,
|
|
228
228
|
speed=5000,
|
|
229
229
|
palette=rainbow,
|
|
230
230
|
)
|
|
231
231
|
|
|
232
232
|
# Verify effect was set
|
|
233
|
-
effect = await matrix.
|
|
233
|
+
effect = await matrix.get_effect()
|
|
234
234
|
assert effect.effect_type == FirmwareEffect.MORPH
|
|
235
235
|
assert len(effect.palette) == 4
|
|
236
236
|
|
|
237
|
-
async def
|
|
237
|
+
async def test_set_effect_flame(self, emulator_devices) -> None:
|
|
238
238
|
"""Test setting FLAME effect."""
|
|
239
239
|
matrix = emulator_devices[6]
|
|
240
240
|
async with matrix:
|
|
@@ -246,17 +246,17 @@ class TestMatrixLight:
|
|
|
246
246
|
HSBK.from_rgb(255, 215, 0), # Gold
|
|
247
247
|
]
|
|
248
248
|
|
|
249
|
-
await matrix.
|
|
249
|
+
await matrix.set_effect(
|
|
250
250
|
effect_type=FirmwareEffect.FLAME,
|
|
251
251
|
speed=3000,
|
|
252
252
|
palette=fire_palette,
|
|
253
253
|
)
|
|
254
254
|
|
|
255
255
|
# Verify effect was set
|
|
256
|
-
effect = await matrix.
|
|
256
|
+
effect = await matrix.get_effect()
|
|
257
257
|
assert effect.effect_type == FirmwareEffect.FLAME
|
|
258
258
|
|
|
259
|
-
async def
|
|
259
|
+
async def test_set_effect_sky_sunrise(self, ceiling_device) -> None:
|
|
260
260
|
"""Test setting SKY effect with SUNRISE.
|
|
261
261
|
|
|
262
262
|
SKY effects are only supported on LIFX Ceiling devices
|
|
@@ -265,18 +265,18 @@ class TestMatrixLight:
|
|
|
265
265
|
"""
|
|
266
266
|
matrix = ceiling_device
|
|
267
267
|
async with matrix:
|
|
268
|
-
await matrix.
|
|
268
|
+
await matrix.set_effect(
|
|
269
269
|
effect_type=FirmwareEffect.SKY,
|
|
270
270
|
speed=2000,
|
|
271
271
|
sky_type=TileEffectSkyType.SUNRISE,
|
|
272
272
|
)
|
|
273
273
|
|
|
274
274
|
# Verify effect was set
|
|
275
|
-
effect = await matrix.
|
|
275
|
+
effect = await matrix.get_effect()
|
|
276
276
|
assert effect.effect_type == FirmwareEffect.SKY
|
|
277
277
|
assert effect.sky_type == TileEffectSkyType.SUNRISE
|
|
278
278
|
|
|
279
|
-
async def
|
|
279
|
+
async def test_set_effect_sky_sunset(self, ceiling_device) -> None:
|
|
280
280
|
"""Test setting SKY effect with SUNSET.
|
|
281
281
|
|
|
282
282
|
SKY effects are only supported on LIFX Ceiling devices
|
|
@@ -285,18 +285,18 @@ class TestMatrixLight:
|
|
|
285
285
|
"""
|
|
286
286
|
matrix = ceiling_device
|
|
287
287
|
async with matrix:
|
|
288
|
-
await matrix.
|
|
288
|
+
await matrix.set_effect(
|
|
289
289
|
effect_type=FirmwareEffect.SKY,
|
|
290
290
|
speed=2000,
|
|
291
291
|
sky_type=TileEffectSkyType.SUNSET,
|
|
292
292
|
)
|
|
293
293
|
|
|
294
294
|
# Verify effect was set
|
|
295
|
-
effect = await matrix.
|
|
295
|
+
effect = await matrix.get_effect()
|
|
296
296
|
assert effect.effect_type == FirmwareEffect.SKY
|
|
297
297
|
assert effect.sky_type == TileEffectSkyType.SUNSET
|
|
298
298
|
|
|
299
|
-
async def
|
|
299
|
+
async def test_set_effect_sky_clouds(self, ceiling_device) -> None:
|
|
300
300
|
"""Test setting SKY effect with CLOUDS and saturation parameters.
|
|
301
301
|
|
|
302
302
|
SKY effects are only supported on LIFX Ceiling devices
|
|
@@ -305,7 +305,7 @@ class TestMatrixLight:
|
|
|
305
305
|
"""
|
|
306
306
|
matrix = ceiling_device
|
|
307
307
|
async with matrix:
|
|
308
|
-
await matrix.
|
|
308
|
+
await matrix.set_effect(
|
|
309
309
|
effect_type=FirmwareEffect.SKY,
|
|
310
310
|
speed=4000,
|
|
311
311
|
sky_type=TileEffectSkyType.CLOUDS,
|
|
@@ -314,30 +314,30 @@ class TestMatrixLight:
|
|
|
314
314
|
)
|
|
315
315
|
|
|
316
316
|
# Verify effect was set
|
|
317
|
-
effect = await matrix.
|
|
317
|
+
effect = await matrix.get_effect()
|
|
318
318
|
assert effect.effect_type == FirmwareEffect.SKY
|
|
319
319
|
assert effect.sky_type == TileEffectSkyType.CLOUDS
|
|
320
320
|
assert effect.cloud_saturation_min == 50
|
|
321
321
|
assert effect.cloud_saturation_max == 200
|
|
322
322
|
|
|
323
|
-
async def
|
|
323
|
+
async def test_set_effect_off(self, emulator_devices) -> None:
|
|
324
324
|
"""Test turning off tile effect."""
|
|
325
325
|
matrix = emulator_devices[6]
|
|
326
326
|
async with matrix:
|
|
327
327
|
# First set an effect
|
|
328
|
-
await matrix.
|
|
328
|
+
await matrix.set_effect(
|
|
329
329
|
effect_type=FirmwareEffect.MORPH,
|
|
330
330
|
speed=3000,
|
|
331
331
|
)
|
|
332
332
|
|
|
333
333
|
# Then turn it off
|
|
334
|
-
await matrix.
|
|
334
|
+
await matrix.set_effect(
|
|
335
335
|
effect_type=FirmwareEffect.OFF,
|
|
336
336
|
speed=0,
|
|
337
337
|
)
|
|
338
338
|
|
|
339
339
|
# Verify effect was turned off
|
|
340
|
-
effect = await matrix.
|
|
340
|
+
effect = await matrix.get_effect()
|
|
341
341
|
assert effect.effect_type == FirmwareEffect.OFF
|
|
342
342
|
|
|
343
343
|
async def test_get64_large_tile(self, ceiling_device) -> None:
|
|
@@ -13,6 +13,11 @@ from lifx.effects.const import DEFAULT_BRIGHTNESS
|
|
|
13
13
|
class ConcreteEffect(LIFXEffect):
|
|
14
14
|
"""Concrete implementation for testing abstract base class."""
|
|
15
15
|
|
|
16
|
+
@property
|
|
17
|
+
def name(self) -> str:
|
|
18
|
+
"""Return the name of the effect."""
|
|
19
|
+
return "test"
|
|
20
|
+
|
|
16
21
|
async def async_play(self) -> None:
|
|
17
22
|
"""Minimal implementation for testing."""
|
|
18
23
|
pass
|
|
@@ -392,6 +392,11 @@ async def test_conductor_exception_during_async_perform():
|
|
|
392
392
|
|
|
393
393
|
# Create a custom effect that raises exception during async_perform
|
|
394
394
|
class FailingEffect(LIFXEffect):
|
|
395
|
+
@property
|
|
396
|
+
def name(self) -> str:
|
|
397
|
+
"""Return the name of the effect."""
|
|
398
|
+
return "failing"
|
|
399
|
+
|
|
395
400
|
async def async_play(self):
|
|
396
401
|
raise RuntimeError("Effect failed during execution")
|
|
397
402
|
|
|
@@ -10,6 +10,11 @@ from lifx.effects.models import PreState, RunningEffect
|
|
|
10
10
|
class DummyEffect(LIFXEffect):
|
|
11
11
|
"""Dummy effect for testing."""
|
|
12
12
|
|
|
13
|
+
@property
|
|
14
|
+
def name(self) -> str:
|
|
15
|
+
"""Return the name of the effect."""
|
|
16
|
+
return "dummy"
|
|
17
|
+
|
|
13
18
|
async def async_play(self) -> None:
|
|
14
19
|
"""Dummy play method."""
|
|
15
20
|
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|