lifx-async 4.7.1__tar.gz → 4.7.3__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.1 → lifx_async-4.7.3}/.github/workflows/ci.yml +6 -6
- {lifx_async-4.7.1 → lifx_async-4.7.3}/.github/workflows/docs.yml +1 -1
- {lifx_async-4.7.1 → lifx_async-4.7.3}/PKG-INFO +1 -1
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/api/devices.md +175 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/api/high-level.md +26 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/api/network.md +11 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/changelog.md +21 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/mkdocs.yml +1 -4
- {lifx_async-4.7.1 → lifx_async-4.7.3}/pyproject.toml +1 -1
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/api.py +3 -2
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/devices/ceiling.py +60 -4
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_ceiling.py +236 -1
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_state_hev.py +1 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_state_infrared.py +1 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_effects/test_integration.py +56 -9
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_network/test_connection.py +4 -2
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_theme/test_canvas.py +4 -2
- {lifx_async-4.7.1 → lifx_async-4.7.3}/uv.lock +1 -1
- {lifx_async-4.7.1 → lifx_async-4.7.3}/.claude/settings.json +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/.github/dependabot.yml +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/.github/labeler.yml +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/.github/workflows/pr-automation.yml +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/.gitignore +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/.pre-commit-config.yaml +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/CLAUDE.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/LICENSE +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/README.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/context7.json +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/api/colors.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/api/effects.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/api/exceptions.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/api/index.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/api/protocol.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/api/themes.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/architecture/effects-architecture.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/architecture/overview.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/faq.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/getting-started/effects.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/getting-started/installation.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/getting-started/quickstart.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/getting-started/themes.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/index.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/migration/effect-api-changes.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/stylesheets/extra.css +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/user-guide/advanced-usage.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/user-guide/ceiling-lights.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/user-guide/effects-custom.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/user-guide/effects-troubleshooting.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/user-guide/protocol-deep-dive.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/user-guide/themes.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/docs/user-guide/troubleshooting.md +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/examples/01_simple_discovery.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/examples/02_simple_control.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/examples/03_waveforms.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/examples/04_logging.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/examples/06_pulse_effect.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/examples/07_colorloop_effect.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/examples/08_custom_effect.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/examples/09_background_effect.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/examples/10_find_specific_devices.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/examples/11_matrix_basic.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/examples/12_matrix_effects.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/examples/13_matrix_large.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/renovate.json +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/color.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/const.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/devices/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/devices/base.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/devices/hev.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/devices/infrared.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/devices/light.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/devices/matrix.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/devices/multizone.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/effects/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/effects/base.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/effects/colorloop.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/effects/conductor.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/effects/const.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/effects/models.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/effects/pulse.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/effects/state_manager.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/exceptions.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/network/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/network/connection.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/network/discovery.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/network/message.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/network/transport.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/products/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/products/generator.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/products/quirks.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/products/registry.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/protocol/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/protocol/base.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/protocol/generator.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/protocol/header.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/protocol/models.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/protocol/packets.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/protocol/protocol_types.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/protocol/serializer.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/py.typed +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/theme/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/theme/canvas.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/theme/generators.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/theme/library.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/src/lifx/theme/theme.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/conftest.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_api/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_api/test_api_apply_theme.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_api/test_api_batch_errors.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_api/test_api_batch_operations.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_api/test_api_discovery.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_api/test_api_organization.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_color.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/conftest.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_base.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_hev.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_infrared.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_light.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_mac_address.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_matrix.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_multizone.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_state_ceiling.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_state_light.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_state_management.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_state_matrix.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_devices/test_state_multizone.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_effects/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_effects/test_base.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_effects/test_capability_filtering.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_effects/test_colorloop.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_effects/test_models.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_effects/test_pulse.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_effects/test_state_manager.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_network/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_network/test_concurrent_requests.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_network/test_discovery_devices.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_network/test_discovery_errors.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_network/test_message.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_network/test_message_advanced.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_network/test_transport.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_products/test_product_generator.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_products/test_registry.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_protocol/test_generated.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_protocol/test_header.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_protocol/test_protocol_generator.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_protocol/test_serializer.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_theme/__init__.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_theme/conftest.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_theme/test_apply_theme.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_theme/test_generators.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_theme/test_library.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/tests/test_theme/test_theme.py +0 -0
- {lifx_async-4.7.1 → lifx_async-4.7.3}/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.3 (2025-12-16)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- **devices**: Capture component colors before set_power turns off light
|
|
10
|
+
([`a99abee`](https://github.com/Djelibeybi/lifx-async/commit/a99abeeeb4f6cad1e49410204b8e7a567765b3ed))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## v4.7.2 (2025-12-16)
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- **api**: Close device connections in DeviceGroup context manager
|
|
18
|
+
([`054bfee`](https://github.com/Djelibeybi/lifx-async/commit/054bfee88e548d38c1e7c49277d3bb334b55adcc))
|
|
19
|
+
|
|
20
|
+
### Documentation
|
|
21
|
+
|
|
22
|
+
- **api**: Add dataclass documentation and improve navigation
|
|
23
|
+
([`c859c87`](https://github.com/Djelibeybi/lifx-async/commit/c859c8711335bdf5357412ccf4364075ce0df535))
|
|
24
|
+
|
|
25
|
+
|
|
5
26
|
## v4.7.1 (2025-12-13)
|
|
6
27
|
|
|
7
28
|
### Bug Fixes
|
|
@@ -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
|
|
|
@@ -622,6 +619,65 @@ class CeilingLight(MatrixLight):
|
|
|
622
619
|
determined_colors = await self._determine_downlight_brightness()
|
|
623
620
|
await self.set_downlight_colors(determined_colors, duration)
|
|
624
621
|
|
|
622
|
+
async def set_power(self, level: bool | int, duration: float = 0.0) -> None:
|
|
623
|
+
"""Set light power state, capturing component colors before turning off.
|
|
624
|
+
|
|
625
|
+
Overrides Light.set_power() to capture the current uplight and downlight
|
|
626
|
+
colors before turning off the entire light. This allows subsequent calls
|
|
627
|
+
to turn_uplight_on() or turn_downlight_on() to restore the colors that
|
|
628
|
+
were active just before the light was turned off.
|
|
629
|
+
|
|
630
|
+
The captured colors preserve hue, saturation, and kelvin values even if
|
|
631
|
+
a component was already off (brightness=0). The brightness will be
|
|
632
|
+
determined at turn-on time using the standard brightness inference logic.
|
|
633
|
+
|
|
634
|
+
Args:
|
|
635
|
+
level: True/65535 to turn on, False/0 to turn off
|
|
636
|
+
duration: Transition duration in seconds (default 0.0)
|
|
637
|
+
|
|
638
|
+
Raises:
|
|
639
|
+
ValueError: If integer value is not 0 or 65535
|
|
640
|
+
LifxDeviceNotFoundError: If device is not connected
|
|
641
|
+
LifxTimeoutError: If device does not respond
|
|
642
|
+
LifxUnsupportedCommandError: If device doesn't support this command
|
|
643
|
+
|
|
644
|
+
Example:
|
|
645
|
+
```python
|
|
646
|
+
# Turn off entire ceiling light (captures colors for later)
|
|
647
|
+
await ceiling.set_power(False)
|
|
648
|
+
|
|
649
|
+
# Later, turn on just the uplight with its previous color
|
|
650
|
+
await ceiling.turn_uplight_on()
|
|
651
|
+
|
|
652
|
+
# Or turn on just the downlight with its previous colors
|
|
653
|
+
await ceiling.turn_downlight_on()
|
|
654
|
+
```
|
|
655
|
+
"""
|
|
656
|
+
# Determine if we're turning off
|
|
657
|
+
if isinstance(level, bool):
|
|
658
|
+
turning_off = not level
|
|
659
|
+
elif isinstance(level, int):
|
|
660
|
+
if level not in (0, 65535):
|
|
661
|
+
raise ValueError(f"Power level must be 0 or 65535, got {level}")
|
|
662
|
+
turning_off = level == 0
|
|
663
|
+
else:
|
|
664
|
+
raise TypeError(f"Expected bool or int, got {type(level).__name__}")
|
|
665
|
+
|
|
666
|
+
# If turning off, capture current colors for both components
|
|
667
|
+
if turning_off:
|
|
668
|
+
# Always capture colors - even if brightness is 0, the hue/sat/kelvin
|
|
669
|
+
# are still useful for turn_on. Brightness will be determined at
|
|
670
|
+
# turn-on time using the standard inference logic.
|
|
671
|
+
self._stored_uplight_state = await self.get_uplight_color()
|
|
672
|
+
self._stored_downlight_state = await self.get_downlight_colors()
|
|
673
|
+
|
|
674
|
+
# Persist if enabled
|
|
675
|
+
if self._state_file:
|
|
676
|
+
self._save_state_to_file()
|
|
677
|
+
|
|
678
|
+
# Call parent to perform actual power change
|
|
679
|
+
await super().set_power(level, duration)
|
|
680
|
+
|
|
625
681
|
async def turn_downlight_off(
|
|
626
682
|
self, colors: HSBK | list[HSBK] | None = None, duration: float = 0.0
|
|
627
683
|
) -> None:
|