lifx-async 4.7.0__tar.gz → 4.7.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.7.0 → lifx_async-4.7.2}/.github/workflows/ci.yml +6 -6
- {lifx_async-4.7.0 → lifx_async-4.7.2}/.github/workflows/docs.yml +1 -1
- {lifx_async-4.7.0 → lifx_async-4.7.2}/PKG-INFO +1 -1
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/api/devices.md +175 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/api/high-level.md +26 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/api/network.md +11 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/changelog.md +21 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/mkdocs.yml +1 -4
- {lifx_async-4.7.0 → lifx_async-4.7.2}/pyproject.toml +1 -1
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/api.py +3 -2
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/devices/ceiling.py +1 -4
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/devices/matrix.py +10 -2
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_matrix.py +31 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_state_hev.py +1 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_state_infrared.py +1 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/uv.lock +1 -1
- {lifx_async-4.7.0 → lifx_async-4.7.2}/.claude/settings.json +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/.github/dependabot.yml +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/.github/labeler.yml +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/.github/workflows/pr-automation.yml +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/.gitignore +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/.pre-commit-config.yaml +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/CLAUDE.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/LICENSE +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/README.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/context7.json +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/api/colors.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/api/effects.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/api/exceptions.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/api/index.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/api/protocol.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/api/themes.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/architecture/effects-architecture.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/architecture/overview.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/faq.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/getting-started/effects.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/getting-started/installation.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/getting-started/quickstart.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/getting-started/themes.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/index.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/migration/effect-api-changes.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/stylesheets/extra.css +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/user-guide/advanced-usage.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/user-guide/ceiling-lights.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/user-guide/effects-custom.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/user-guide/effects-troubleshooting.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/user-guide/protocol-deep-dive.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/user-guide/themes.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/docs/user-guide/troubleshooting.md +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/examples/01_simple_discovery.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/examples/02_simple_control.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/examples/03_waveforms.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/examples/04_logging.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/examples/06_pulse_effect.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/examples/07_colorloop_effect.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/examples/08_custom_effect.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/examples/09_background_effect.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/examples/10_find_specific_devices.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/examples/11_matrix_basic.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/examples/12_matrix_effects.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/examples/13_matrix_large.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/renovate.json +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/color.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/const.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/devices/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/devices/base.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/devices/hev.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/devices/infrared.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/devices/light.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/devices/multizone.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/effects/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/effects/base.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/effects/colorloop.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/effects/conductor.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/effects/const.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/effects/models.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/effects/pulse.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/effects/state_manager.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/exceptions.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/network/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/network/connection.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/network/discovery.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/network/message.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/network/transport.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/products/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/products/generator.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/products/quirks.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/products/registry.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/protocol/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/protocol/base.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/protocol/generator.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/protocol/header.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/protocol/models.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/protocol/packets.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/protocol/protocol_types.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/protocol/serializer.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/py.typed +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/theme/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/theme/canvas.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/theme/generators.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/theme/library.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/src/lifx/theme/theme.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/conftest.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_api/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_api/test_api_apply_theme.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_api/test_api_batch_errors.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_api/test_api_batch_operations.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_api/test_api_discovery.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_api/test_api_organization.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_color.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/conftest.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_base.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_ceiling.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_hev.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_infrared.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_light.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_mac_address.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_multizone.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_state_ceiling.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_state_light.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_state_management.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_state_matrix.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_devices/test_state_multizone.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_effects/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_effects/test_base.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_effects/test_capability_filtering.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_effects/test_colorloop.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_effects/test_integration.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_effects/test_models.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_effects/test_pulse.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_effects/test_state_manager.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_network/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_network/test_concurrent_requests.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_network/test_connection.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_network/test_discovery_devices.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_network/test_discovery_errors.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_network/test_message.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_network/test_message_advanced.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_network/test_transport.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_products/test_product_generator.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_products/test_registry.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_protocol/test_generated.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_protocol/test_header.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_protocol/test_protocol_generator.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_protocol/test_serializer.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_theme/__init__.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_theme/conftest.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_theme/test_apply_theme.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_theme/test_canvas.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_theme/test_generators.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_theme/test_library.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_theme/test_theme.py +0 -0
- {lifx_async-4.7.0 → lifx_async-4.7.2}/tests/test_utils.py +0 -0
|
@@ -96,7 +96,7 @@ jobs:
|
|
|
96
96
|
|
|
97
97
|
- name: Upload coverage to Codecov
|
|
98
98
|
if: matrix.os == 'ubuntu-latest'
|
|
99
|
-
uses: codecov/codecov-action@
|
|
99
|
+
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
|
|
100
100
|
with:
|
|
101
101
|
env_vars: OS,PYTHON
|
|
102
102
|
fail_ci_if_error: false
|
|
@@ -107,7 +107,7 @@ jobs:
|
|
|
107
107
|
|
|
108
108
|
- name: Upload test results to Codecov
|
|
109
109
|
if: matrix.os == 'ubuntu-latest'
|
|
110
|
-
uses: codecov/codecov-action@
|
|
110
|
+
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
|
|
111
111
|
with:
|
|
112
112
|
env_vars: OS,PYTHON
|
|
113
113
|
fail_ci_if_error: false
|
|
@@ -147,7 +147,7 @@ jobs:
|
|
|
147
147
|
run: uv run --frozen pytest
|
|
148
148
|
|
|
149
149
|
- name: Upload coverage to Codecov
|
|
150
|
-
uses: codecov/codecov-action@
|
|
150
|
+
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
|
|
151
151
|
with:
|
|
152
152
|
fail_ci_if_error: false
|
|
153
153
|
name: pytest-code-coverage-main
|
|
@@ -156,7 +156,7 @@ jobs:
|
|
|
156
156
|
verbose: true
|
|
157
157
|
|
|
158
158
|
- name: Upload test results to Codecov
|
|
159
|
-
uses: codecov/codecov-action@
|
|
159
|
+
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
|
|
160
160
|
with:
|
|
161
161
|
fail_ci_if_error: false
|
|
162
162
|
name: pytest-test-results-main
|
|
@@ -239,7 +239,7 @@ jobs:
|
|
|
239
239
|
|
|
240
240
|
- name: Upload Distribution Artifacts
|
|
241
241
|
if: github.event_name != 'workflow_dispatch'
|
|
242
|
-
uses: actions/upload-artifact@
|
|
242
|
+
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
|
243
243
|
with:
|
|
244
244
|
name: distribution-artifacts
|
|
245
245
|
path: dist
|
|
@@ -287,7 +287,7 @@ jobs:
|
|
|
287
287
|
|
|
288
288
|
- name: Download Build Artifacts from workflow
|
|
289
289
|
if: github.event_name != 'workflow_dispatch'
|
|
290
|
-
uses: actions/download-artifact@
|
|
290
|
+
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
|
291
291
|
id: artifact-download
|
|
292
292
|
with:
|
|
293
293
|
name: distribution-artifacts
|
|
@@ -49,7 +49,7 @@ jobs:
|
|
|
49
49
|
|
|
50
50
|
- name: Upload docs artifact
|
|
51
51
|
if: github.event_name == 'pull_request'
|
|
52
|
-
uses: actions/upload-artifact@
|
|
52
|
+
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
|
53
53
|
with:
|
|
54
54
|
name: docs
|
|
55
55
|
path: site/
|
|
@@ -3,6 +3,87 @@
|
|
|
3
3
|
Device classes provide direct control over LIFX devices. All device classes support async context
|
|
4
4
|
managers for automatic resource cleanup.
|
|
5
5
|
|
|
6
|
+
## State and Info Classes
|
|
7
|
+
|
|
8
|
+
Device state and information dataclasses returned by device methods.
|
|
9
|
+
|
|
10
|
+
### DeviceState
|
|
11
|
+
|
|
12
|
+
Base device state dataclass returned by `Device.state`.
|
|
13
|
+
|
|
14
|
+
::: lifx.devices.base.DeviceState
|
|
15
|
+
options:
|
|
16
|
+
show_root_heading: true
|
|
17
|
+
heading_level: 4
|
|
18
|
+
members_order: source
|
|
19
|
+
show_if_no_docstring: false
|
|
20
|
+
|
|
21
|
+
### DeviceVersion
|
|
22
|
+
|
|
23
|
+
Device version information returned by `Device.get_version()`.
|
|
24
|
+
|
|
25
|
+
::: lifx.devices.base.DeviceVersion
|
|
26
|
+
options:
|
|
27
|
+
show_root_heading: true
|
|
28
|
+
heading_level: 4
|
|
29
|
+
members_order: source
|
|
30
|
+
show_if_no_docstring: false
|
|
31
|
+
|
|
32
|
+
### DeviceInfo
|
|
33
|
+
|
|
34
|
+
Device runtime information returned by `Device.get_info()`.
|
|
35
|
+
|
|
36
|
+
::: lifx.devices.base.DeviceInfo
|
|
37
|
+
options:
|
|
38
|
+
show_root_heading: true
|
|
39
|
+
heading_level: 4
|
|
40
|
+
members_order: source
|
|
41
|
+
show_if_no_docstring: false
|
|
42
|
+
|
|
43
|
+
### WifiInfo
|
|
44
|
+
|
|
45
|
+
WiFi module information returned by `Device.get_wifi_info()`.
|
|
46
|
+
|
|
47
|
+
::: lifx.devices.base.WifiInfo
|
|
48
|
+
options:
|
|
49
|
+
show_root_heading: true
|
|
50
|
+
heading_level: 4
|
|
51
|
+
members_order: source
|
|
52
|
+
show_if_no_docstring: false
|
|
53
|
+
|
|
54
|
+
### FirmwareInfo
|
|
55
|
+
|
|
56
|
+
Firmware version information returned by `Device.get_host_firmware()` and `Device.get_wifi_firmware()`.
|
|
57
|
+
|
|
58
|
+
::: lifx.devices.base.FirmwareInfo
|
|
59
|
+
options:
|
|
60
|
+
show_root_heading: true
|
|
61
|
+
heading_level: 4
|
|
62
|
+
members_order: source
|
|
63
|
+
show_if_no_docstring: false
|
|
64
|
+
|
|
65
|
+
### CollectionInfo
|
|
66
|
+
|
|
67
|
+
Location and group collection information returned by `Device.get_location()` and `Device.get_group()`.
|
|
68
|
+
|
|
69
|
+
::: lifx.devices.base.CollectionInfo
|
|
70
|
+
options:
|
|
71
|
+
show_root_heading: true
|
|
72
|
+
heading_level: 4
|
|
73
|
+
members_order: source
|
|
74
|
+
show_if_no_docstring: false
|
|
75
|
+
|
|
76
|
+
### DeviceCapabilities
|
|
77
|
+
|
|
78
|
+
Device capabilities from product registry, available via `Device.capabilities`.
|
|
79
|
+
|
|
80
|
+
::: lifx.devices.base.DeviceCapabilities
|
|
81
|
+
options:
|
|
82
|
+
show_root_heading: true
|
|
83
|
+
heading_level: 4
|
|
84
|
+
members_order: source
|
|
85
|
+
show_if_no_docstring: false
|
|
86
|
+
|
|
6
87
|
## Base Device
|
|
7
88
|
|
|
8
89
|
The `Device` class provides common operations available on all LIFX devices.
|
|
@@ -29,6 +110,17 @@ The `Light` class provides color control and effects for standard LIFX lights.
|
|
|
29
110
|
filters:
|
|
30
111
|
- "!^_"
|
|
31
112
|
|
|
113
|
+
### LightState
|
|
114
|
+
|
|
115
|
+
Light device state dataclass returned by `Light.state`.
|
|
116
|
+
|
|
117
|
+
::: lifx.devices.light.LightState
|
|
118
|
+
options:
|
|
119
|
+
show_root_heading: true
|
|
120
|
+
heading_level: 4
|
|
121
|
+
members_order: source
|
|
122
|
+
show_if_no_docstring: false
|
|
123
|
+
|
|
32
124
|
## HEV Light
|
|
33
125
|
|
|
34
126
|
The `HevLight` class extends `Light` with anti-bacterial cleaning cycle control for LIFX HEV devices.
|
|
@@ -42,6 +134,17 @@ The `HevLight` class extends `Light` with anti-bacterial cleaning cycle control
|
|
|
42
134
|
filters:
|
|
43
135
|
- "!^_"
|
|
44
136
|
|
|
137
|
+
### HevLightState
|
|
138
|
+
|
|
139
|
+
HEV light device state dataclass returned by `HevLight.state`.
|
|
140
|
+
|
|
141
|
+
::: lifx.devices.hev.HevLightState
|
|
142
|
+
options:
|
|
143
|
+
show_root_heading: true
|
|
144
|
+
heading_level: 4
|
|
145
|
+
members_order: source
|
|
146
|
+
show_if_no_docstring: false
|
|
147
|
+
|
|
45
148
|
## Infrared Light
|
|
46
149
|
|
|
47
150
|
The `InfraredLight` class extends `Light` with infrared LED control for night vision on LIFX A19 + Night Vision devices.
|
|
@@ -55,6 +158,17 @@ The `InfraredLight` class extends `Light` with infrared LED control for night vi
|
|
|
55
158
|
filters:
|
|
56
159
|
- "!^_"
|
|
57
160
|
|
|
161
|
+
### InfraredLightState
|
|
162
|
+
|
|
163
|
+
Infrared light device state dataclass returned by `InfraredLight.state`.
|
|
164
|
+
|
|
165
|
+
::: lifx.devices.infrared.InfraredLightState
|
|
166
|
+
options:
|
|
167
|
+
show_root_heading: true
|
|
168
|
+
heading_level: 4
|
|
169
|
+
members_order: source
|
|
170
|
+
show_if_no_docstring: false
|
|
171
|
+
|
|
58
172
|
## MultiZone Light
|
|
59
173
|
|
|
60
174
|
The `MultiZoneLight` class controls LIFX strips and beams with multiple color zones.
|
|
@@ -68,6 +182,30 @@ The `MultiZoneLight` class controls LIFX strips and beams with multiple color zo
|
|
|
68
182
|
filters:
|
|
69
183
|
- "!^_"
|
|
70
184
|
|
|
185
|
+
### MultiZoneLightState
|
|
186
|
+
|
|
187
|
+
MultiZone light device state dataclass returned by `MultiZoneLight.state`.
|
|
188
|
+
|
|
189
|
+
::: lifx.devices.multizone.MultiZoneLightState
|
|
190
|
+
options:
|
|
191
|
+
show_root_heading: true
|
|
192
|
+
heading_level: 4
|
|
193
|
+
members_order: source
|
|
194
|
+
show_if_no_docstring: false
|
|
195
|
+
|
|
196
|
+
### MultiZoneEffect
|
|
197
|
+
|
|
198
|
+
Configuration dataclass for multizone effects (MOVE). Used with `MultiZoneLight.set_effect()` and returned by `MultiZoneLight.get_effect()`.
|
|
199
|
+
|
|
200
|
+
::: lifx.devices.multizone.MultiZoneEffect
|
|
201
|
+
options:
|
|
202
|
+
show_root_heading: true
|
|
203
|
+
heading_level: 4
|
|
204
|
+
members_order: source
|
|
205
|
+
show_if_no_docstring: false
|
|
206
|
+
filters:
|
|
207
|
+
- "!^_"
|
|
208
|
+
|
|
71
209
|
## Matrix Light
|
|
72
210
|
|
|
73
211
|
The `MatrixLight` class controls LIFX matrix devices (tiles, candle, path) with 2D zone control.
|
|
@@ -81,6 +219,43 @@ The `MatrixLight` class controls LIFX matrix devices (tiles, candle, path) with
|
|
|
81
219
|
filters:
|
|
82
220
|
- "!^_"
|
|
83
221
|
|
|
222
|
+
### MatrixLightState
|
|
223
|
+
|
|
224
|
+
Matrix light device state dataclass returned by `MatrixLight.state`.
|
|
225
|
+
|
|
226
|
+
::: lifx.devices.matrix.MatrixLightState
|
|
227
|
+
options:
|
|
228
|
+
show_root_heading: true
|
|
229
|
+
heading_level: 4
|
|
230
|
+
members_order: source
|
|
231
|
+
show_if_no_docstring: false
|
|
232
|
+
|
|
233
|
+
### TileInfo
|
|
234
|
+
|
|
235
|
+
Information dataclass for a single tile in the device chain. Returned as part of `MatrixLightState.chain`.
|
|
236
|
+
|
|
237
|
+
::: lifx.devices.matrix.TileInfo
|
|
238
|
+
options:
|
|
239
|
+
show_root_heading: true
|
|
240
|
+
heading_level: 4
|
|
241
|
+
members_order: source
|
|
242
|
+
show_if_no_docstring: false
|
|
243
|
+
filters:
|
|
244
|
+
- "!^_"
|
|
245
|
+
|
|
246
|
+
### MatrixEffect
|
|
247
|
+
|
|
248
|
+
Configuration dataclass for matrix effects (MORPH, FLAME, SKY). Used with `MatrixLight.set_effect()` and returned by `MatrixLight.get_effect()`.
|
|
249
|
+
|
|
250
|
+
::: lifx.devices.matrix.MatrixEffect
|
|
251
|
+
options:
|
|
252
|
+
show_root_heading: true
|
|
253
|
+
heading_level: 4
|
|
254
|
+
members_order: source
|
|
255
|
+
show_if_no_docstring: false
|
|
256
|
+
filters:
|
|
257
|
+
- "!^_"
|
|
258
|
+
|
|
84
259
|
## Ceiling Light
|
|
85
260
|
|
|
86
261
|
The `CeilingLight` class extends `MatrixLight` with independent control over uplight and downlight components for LIFX Ceiling fixtures.
|
|
@@ -34,6 +34,32 @@ recommended entry points for most users.
|
|
|
34
34
|
members_order: source
|
|
35
35
|
show_if_no_docstring: false
|
|
36
36
|
|
|
37
|
+
## Organizational Groupings
|
|
38
|
+
|
|
39
|
+
Dataclasses for organizing devices by location or group. Returned by `DeviceGroup.organize_by_location()` and `DeviceGroup.organize_by_group()`.
|
|
40
|
+
|
|
41
|
+
### LocationGrouping
|
|
42
|
+
|
|
43
|
+
Location-based device grouping returned by `DeviceGroup.organize_by_location()`.
|
|
44
|
+
|
|
45
|
+
::: lifx.api.LocationGrouping
|
|
46
|
+
options:
|
|
47
|
+
show_root_heading: true
|
|
48
|
+
heading_level: 4
|
|
49
|
+
members_order: source
|
|
50
|
+
show_if_no_docstring: false
|
|
51
|
+
|
|
52
|
+
### GroupGrouping
|
|
53
|
+
|
|
54
|
+
Group-based device grouping returned by `DeviceGroup.organize_by_group()`.
|
|
55
|
+
|
|
56
|
+
::: lifx.api.GroupGrouping
|
|
57
|
+
options:
|
|
58
|
+
show_root_heading: true
|
|
59
|
+
heading_level: 4
|
|
60
|
+
members_order: source
|
|
61
|
+
show_if_no_docstring: false
|
|
62
|
+
|
|
37
63
|
## Examples
|
|
38
64
|
|
|
39
65
|
### Simple Discovery
|
|
@@ -18,6 +18,17 @@ Functions for discovering LIFX devices on the local network.
|
|
|
18
18
|
heading_level: 3
|
|
19
19
|
members_order: source
|
|
20
20
|
|
|
21
|
+
### DiscoveryResponse
|
|
22
|
+
|
|
23
|
+
Response dataclass from custom discovery broadcasts (using packets other than GetService).
|
|
24
|
+
|
|
25
|
+
::: lifx.network.discovery.DiscoveryResponse
|
|
26
|
+
options:
|
|
27
|
+
show_root_heading: true
|
|
28
|
+
heading_level: 4
|
|
29
|
+
members_order: source
|
|
30
|
+
show_if_no_docstring: false
|
|
31
|
+
|
|
21
32
|
## UDP Transport
|
|
22
33
|
|
|
23
34
|
Low-level UDP transport for sending and receiving LIFX protocol messages.
|
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- version list -->
|
|
4
4
|
|
|
5
|
+
## v4.7.2 (2025-12-16)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- **api**: Close device connections in DeviceGroup context manager
|
|
10
|
+
([`054bfee`](https://github.com/Djelibeybi/lifx-async/commit/054bfee88e548d38c1e7c49277d3bb334b55adcc))
|
|
11
|
+
|
|
12
|
+
### Documentation
|
|
13
|
+
|
|
14
|
+
- **api**: Add dataclass documentation and improve navigation
|
|
15
|
+
([`c859c87`](https://github.com/Djelibeybi/lifx-async/commit/c859c8711335bdf5357412ccf4364075ce0df535))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## v4.7.1 (2025-12-13)
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
- **devices**: Add length parameter to copy_frame_buffer()
|
|
23
|
+
([`6a74690`](https://github.com/Djelibeybi/lifx-async/commit/6a746904665d38545e534829c2c690a61e48da54))
|
|
24
|
+
|
|
25
|
+
|
|
5
26
|
## v4.7.0 (2025-12-13)
|
|
6
27
|
|
|
7
28
|
### Features
|
|
@@ -25,19 +25,16 @@ theme:
|
|
|
25
25
|
icon: material/brightness-4
|
|
26
26
|
name: Switch to light mode
|
|
27
27
|
features:
|
|
28
|
-
- navigation.instant
|
|
29
28
|
- navigation.tracking
|
|
30
29
|
- navigation.tabs
|
|
31
30
|
- navigation.tabs.sticky
|
|
32
31
|
- navigation.sections
|
|
33
|
-
- navigation.expand
|
|
34
32
|
- navigation.path
|
|
35
33
|
- navigation.indexes
|
|
34
|
+
- navigation.top
|
|
36
35
|
- toc.follow
|
|
37
|
-
- toc.integrate
|
|
38
36
|
- search.suggest
|
|
39
37
|
- search.highlight
|
|
40
|
-
- search.share
|
|
41
38
|
- content.code.copy
|
|
42
39
|
- content.code.annotate
|
|
43
40
|
- content.tabs.link
|
|
@@ -126,8 +126,9 @@ class DeviceGroup:
|
|
|
126
126
|
exc_val: BaseException | None,
|
|
127
127
|
exc_tb: TracebackType | None,
|
|
128
128
|
) -> None:
|
|
129
|
-
"""Exit async context manager."""
|
|
130
|
-
|
|
129
|
+
"""Exit async context manager and close all device connections."""
|
|
130
|
+
for device in self._devices:
|
|
131
|
+
await device.connection.close()
|
|
131
132
|
|
|
132
133
|
def __iter__(
|
|
133
134
|
self,
|
|
@@ -23,16 +23,13 @@ import logging
|
|
|
23
23
|
import time
|
|
24
24
|
from dataclasses import asdict, dataclass
|
|
25
25
|
from pathlib import Path
|
|
26
|
-
from typing import
|
|
26
|
+
from typing import Any, cast
|
|
27
27
|
|
|
28
28
|
from lifx.color import HSBK
|
|
29
29
|
from lifx.devices.matrix import MatrixLight, MatrixLightState
|
|
30
30
|
from lifx.exceptions import LifxError
|
|
31
31
|
from lifx.products import get_ceiling_layout, is_ceiling_product
|
|
32
32
|
|
|
33
|
-
if TYPE_CHECKING:
|
|
34
|
-
pass
|
|
35
|
-
|
|
36
33
|
_LOGGER = logging.getLogger(__name__)
|
|
37
34
|
|
|
38
35
|
|
|
@@ -699,6 +699,7 @@ class MatrixLight(Light):
|
|
|
699
699
|
source_fb: int = 1,
|
|
700
700
|
target_fb: int = 0,
|
|
701
701
|
duration: float = 0.0,
|
|
702
|
+
length: int = 1,
|
|
702
703
|
) -> None:
|
|
703
704
|
"""Copy frame buffer (for tiles with >64 zones).
|
|
704
705
|
|
|
@@ -710,6 +711,7 @@ class MatrixLight(Light):
|
|
|
710
711
|
source_fb: Source frame buffer index (usually 1)
|
|
711
712
|
target_fb: Target frame buffer index (usually 0)
|
|
712
713
|
duration: time in seconds to transition if target_fb is 0
|
|
714
|
+
length: Number of tiles to update starting from tile_index (default 1)
|
|
713
715
|
|
|
714
716
|
Example:
|
|
715
717
|
>>> # For 16x8 tile (128 zones):
|
|
@@ -739,12 +741,18 @@ class MatrixLight(Light):
|
|
|
739
741
|
>>> await matrix.copy_frame_buffer(
|
|
740
742
|
... tile_index=0, source_fb=1, target_fb=0, duration=2.0
|
|
741
743
|
... )
|
|
744
|
+
|
|
745
|
+
>>> # For a chain of 5 tiles, update all simultaneously:
|
|
746
|
+
>>> await matrix.copy_frame_buffer(
|
|
747
|
+
... tile_index=0, source_fb=1, target_fb=0, length=5
|
|
748
|
+
... )
|
|
742
749
|
"""
|
|
743
750
|
_LOGGER.debug(
|
|
744
|
-
"Copying frame buffer %d -> %d for tile %d on %s",
|
|
751
|
+
"Copying frame buffer %d -> %d for tile %d (length=%d) on %s",
|
|
745
752
|
source_fb,
|
|
746
753
|
target_fb,
|
|
747
754
|
tile_index,
|
|
755
|
+
length,
|
|
748
756
|
self.label or self.serial,
|
|
749
757
|
)
|
|
750
758
|
|
|
@@ -761,7 +769,7 @@ class MatrixLight(Light):
|
|
|
761
769
|
await self.connection.send_packet(
|
|
762
770
|
packets.Tile.CopyFrameBuffer(
|
|
763
771
|
tile_index=tile_index,
|
|
764
|
-
length=
|
|
772
|
+
length=length,
|
|
765
773
|
src_fb_index=source_fb,
|
|
766
774
|
dst_fb_index=target_fb,
|
|
767
775
|
src_x=0,
|
|
@@ -373,6 +373,37 @@ class TestMatrixLight:
|
|
|
373
373
|
assert copied_colors[0].saturation == 1.0
|
|
374
374
|
assert copied_colors[0].brightness == 1.0
|
|
375
375
|
|
|
376
|
+
async def test_copy_frame_buffer_with_length(self, emulator_devices) -> None:
|
|
377
|
+
"""Test copy_frame_buffer() with explicit length parameter."""
|
|
378
|
+
matrix = emulator_devices[6]
|
|
379
|
+
async with matrix:
|
|
380
|
+
chain = await matrix.get_device_chain()
|
|
381
|
+
tile = chain[0]
|
|
382
|
+
|
|
383
|
+
# Set pattern on temp buffer (fb_index=1)
|
|
384
|
+
blue_colors = [Colors.BLUE] * 64
|
|
385
|
+
await matrix.set64(
|
|
386
|
+
tile_index=0,
|
|
387
|
+
length=1,
|
|
388
|
+
x=0,
|
|
389
|
+
y=0,
|
|
390
|
+
width=tile.width,
|
|
391
|
+
duration=0,
|
|
392
|
+
colors=blue_colors,
|
|
393
|
+
fb_index=1,
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
# Copy with explicit length=1 (same as default behavior)
|
|
397
|
+
await matrix.copy_frame_buffer(
|
|
398
|
+
tile_index=0, source_fb=1, target_fb=0, length=1
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
# Verify the copy worked
|
|
402
|
+
copied_colors = await matrix.get64()
|
|
403
|
+
assert copied_colors[0].hue == 240 # Blue
|
|
404
|
+
assert copied_colors[0].saturation == 1.0
|
|
405
|
+
assert copied_colors[0].brightness == 1.0
|
|
406
|
+
|
|
376
407
|
async def test_set_effect_without_palette(self, emulator_devices) -> None:
|
|
377
408
|
"""Test setting effect without a palette (palette_count=0)."""
|
|
378
409
|
matrix = emulator_devices[6]
|
|
@@ -217,6 +217,7 @@ class TestHevLightStateManagement:
|
|
|
217
217
|
assert hev_light._state is None
|
|
218
218
|
await hev_light.refresh_state() # type: ignore
|
|
219
219
|
assert isinstance(hev_light.state, HevLightState)
|
|
220
|
+
await hev_light.close()
|
|
220
221
|
|
|
221
222
|
|
|
222
223
|
class TestHevAcknowledgementBasedStateUpdates:
|
|
@@ -149,6 +149,7 @@ class TestInfraredLightStateManagement:
|
|
|
149
149
|
assert infrared_light._state is None
|
|
150
150
|
await infrared_light.refresh_state() # type: ignore
|
|
151
151
|
assert isinstance(infrared_light.state, InfraredLightState)
|
|
152
|
+
await infrared_light.close()
|
|
152
153
|
|
|
153
154
|
|
|
154
155
|
class TestInfraredAcknowledgementBasedStateUpdates:
|
|
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
|
|
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
|