Device Classes¶
Device classes provide direct control over LIFX devices. All device classes support async context managers for automatic resource cleanup.
State and Info Classes¶
Device state and information dataclasses returned by device methods.
DeviceState¶
Base device state dataclass returned by Device.state.
DeviceState
dataclass
¶
DeviceState(
model: str,
label: str,
serial: str,
mac_address: str,
capabilities: DeviceCapabilities,
power: int,
host_firmware: FirmwareInfo,
wifi_firmware: FirmwareInfo,
location: CollectionInfo,
group: CollectionInfo,
last_updated: float,
*,
wifi_info: WifiInfo = (lambda: WifiInfo(signal=None, host_firmware=None))(),
thread_info: ThreadInfo | None = None,
)
Base device state.
| ATTRIBUTE | DESCRIPTION |
|---|---|
model |
Friendly product name (e.g., "LIFX A19")
TYPE:
|
label |
Device label (user-assigned name)
TYPE:
|
serial |
Device serial number (6 bytes)
TYPE:
|
mac_address |
Device MAC address (formatted string)
TYPE:
|
capabilities |
Device capabilities from product registry
TYPE:
|
power |
Power level (0 = off, 65535 = on)
TYPE:
|
host_firmware |
Host firmware version
TYPE:
|
wifi_firmware |
WiFi firmware version
TYPE:
|
location |
Location tuple (UUID bytes, label, updated_at)
TYPE:
|
group |
Group tuple (UUID bytes, label, updated_at)
TYPE:
|
last_updated |
Timestamp of last state refresh
TYPE:
|
wifi_info |
WiFi signal and RSSI. Signal and RSSI are None unless the
device was created with
TYPE:
|
thread_info |
Thread mesh information, or None unless the device was
created with
TYPE:
|
| METHOD | DESCRIPTION |
|---|---|
is_fresh |
Check if state is fresh (recently updated). |
Attributes¶
as_dict
property
¶
as_dict: dict[
str,
str
| int
| float
| dict[str, bool | int]
| dict[str, str | int]
| dict[str, float | int | str | None]
| dict[str, Any]
| None,
]
Return DeviceState as a dictionary.
Methods:¶
DeviceVersion¶
Device version information returned by Device.get_version().
DeviceVersion
dataclass
¶
DeviceInfo¶
Device runtime information returned by Device.get_info().
DeviceInfo
dataclass
¶
WifiInfo¶
WiFi module information returned by Device.get_wifi_info(), including the
firmware-aware rssi_unit (dB through firmware 2.77, otherwise dBm).
Also available as device.state.wifi_info. Neither state initialisation nor
refresh_state() queries the device for WiFi signal strength unless the device
was created with fetch_wifi_info=True (or fetch_radio_info=True on a device
evidenced as WiFi), so signal and rssi are None by default while
rssi_unit is always populated from the host firmware version:
device = await Device.connect(ip="192.168.1.100", fetch_wifi_info=True)
async with device:
print(f"{device.state.wifi_info.rssi} {device.state.wifi_info.rssi_unit}")
When enabled, the query joins the same parallel batch as the other state requests, so it costs no extra round trip.
fetch_wifi_info is also a settable property, so a device can start or stop
collecting readings at any point. It takes effect from the next state
initialisation or refresh:
async with await Device.connect(ip="192.168.1.100") as device:
device.fetch_wifi_info = True
await device.refresh_state()
print(device.state.wifi_info.rssi)
device.fetch_wifi_info = False # stop collecting
Turning it off is equally immediate: the next refresh stores None for
signal and rssi rather than leaving the last reading behind a freshly
stamped last_updated.
For a one-off reading, call get_wifi_info() directly — it is a single
request, where a refresh also re-fetches colour, power, label and every zone or
tile:
async with await Device.connect(ip="192.168.1.100") as device:
wifi_info = await device.get_wifi_info()
print(f"{wifi_info.rssi} {wifi_info.rssi_unit}")
get_wifi_info() and get_wifi_firmware() raise LifxUnsupportedCommandError
once a device is evidenced as Thread, because WiFi and Thread are mutually
exclusive firmware installs and Thread firmware cannot answer either query.
Use get_thread_info() for a Thread device's signal reading.
The opt-in fetch_wifi_info reading is unaffected: a Thread device that does
not answer simply leaves signal and rssi as None.
WifiInfo
dataclass
¶
WifiInfo(signal: float | None, host_firmware: InitVar[FirmwareInfo | None])
Device WiFi module information.
| ATTRIBUTE | DESCRIPTION |
|---|---|
signal |
WiFi signal strength, or None when the signal was not fetched
TYPE:
|
host_firmware |
Init-only firmware version used to determine whether
RSSI is reported in dB or dBm. It is not retained on the instance:
:class:
TYPE:
|
rssi |
WiFi RSSI derived from signal, or None when signal is None
TYPE:
|
rssi_unit |
Unit reported by the firmware (
TYPE:
|
| METHOD | DESCRIPTION |
|---|---|
__post_init__ |
Calculate RSSI from signal and classify the RSSI unit. |
Attributes¶
Methods:¶
__post_init__
¶
__post_init__(host_firmware: FirmwareInfo | None) -> None
Calculate RSSI from signal and classify the RSSI unit.
Source code in src/lifx/devices/base.py
ThreadInfo¶
Thread radio information returned by Device.get_thread_info(), flattened
from the ThreadStateInfo reply: the device's own Routing Locator (RLOC16, the
16-bit address the mesh routes to it by, see the
OpenThread primer),
the network name, its routing role, and the health of its link to the next hop
toward the Thread leader (next_hop), which LIFX note may or may not be
the border router.
The reading is never cached, so every call is a single request to the device:
async with await Device.connect(ip="192.168.1.100") as device:
thread_info = await device.get_thread_info()
print(f"{thread_info.role.name} on {thread_info.network_name}")
print(f"{thread_info.rssi} {thread_info.rssi_unit}")
Also available as device.state.thread_info, which is None unless the device
was created with fetch_thread_info=True, in which case the query joins the
same parallel batch as the other state requests on every initialisation and
refresh. Like fetch_wifi_info, it is a settable property that takes effect
from the next fetch, and a device that does not answer leaves the field None
rather than failing the refresh. On a device evidenced as WiFi the query is
refused before any packet is sent.
A consumer that does not yet know a device's radio can set fetch_radio_info
instead. At each fetch it sends the WiFi signal query on a device evidenced as
WiFi and the Thread query on a device evidenced as Thread, and neither while
connectivity is still unknown, so nothing is sent that the firmware cannot
answer:
async for device in discover_mdns():
device.fetch_radio_info = True # before `async with`
async with device:
radio = device.state.thread_info or device.state.wifi_info
print(f"{device.state.label}: {radio.rssi} {radio.rssi_unit}")
rssi is derived as link_margin_db - 100. LIFX advise that this is a close
enough approximation to compare with WifiInfo.rssi; the protocol
specification itself does not define it. rssi_unit is always dBm.
get_thread_info() raises LifxUnsupportedCommandError once a device is
evidenced as WiFi, the mirror image of the WiFi queries above. A device that
has not yet answered any request and carries no discovery metadata is queried and
answers for itself, so from_ip() on a Thread device works without a prior
discovery.
ThreadInfo
dataclass
¶
ThreadInfo(
rloc: int,
network_name: str,
role: ThreadRoutingRole,
next_hop: int,
link_quality_in: int,
link_quality_out: int,
link_margin_db: int,
)
Device Thread radio information.
Flattens the ThreadStateInfo reply so a consumer reads the numbers
directly rather than walking the nested link-health structure. The link
health describes the device's link to its next hop toward the Thread
leader, not necessarily to its parent or to the border router.
| ATTRIBUTE | DESCRIPTION |
|---|---|
rloc |
The device's own 16-bit Routing Locator (RLOC16), the address the Thread mesh routes to it by. See https://openthread.io/guides/thread-primer/ipv6-addressing#routing-locator-rloc
TYPE:
|
network_name |
Thread network name, decoded from the 16-byte field
TYPE:
|
role |
The device's routing role in the Thread mesh
TYPE:
|
next_hop |
RLOC16 of the neighbour the link health describes: the device's next hop toward the Thread leader, which LIFX note may or may not be the border router
TYPE:
|
link_quality_in |
Inbound link quality indicator, 0 (unknown) to 3 (best)
TYPE:
|
link_quality_out |
Outbound link quality indicator, 0 (unknown) to 3 (best)
TYPE:
|
link_margin_db |
Link margin above the receiver noise floor, in dB
TYPE:
|
rssi |
Approximate received signal strength in dBm, derived as
TYPE:
|
rssi_unit |
Always
TYPE:
|
| METHOD | DESCRIPTION |
|---|---|
__post_init__ |
Derive the approximate RSSI from the link margin. |
FirmwareInfo¶
Firmware version information returned by Device.get_host_firmware() and Device.get_wifi_firmware().
get_wifi_firmware() is refused on a device evidenced as Thread; see WifiInfo.
FirmwareInfo
dataclass
¶
CollectionInfo¶
Location and group collection information returned by Device.get_location() and Device.get_group().
CollectionInfo
dataclass
¶
DeviceCapabilities¶
Device capabilities from product registry, available via Device.capabilities.
DeviceCapabilities
dataclass
¶
DeviceCapabilities(
has_color: bool,
has_multizone: bool,
has_chain: bool,
has_matrix: bool,
has_infrared: bool,
has_hev: bool,
has_extended_multizone: bool,
kelvin_min: int | None,
kelvin_max: int | None,
)
Device capabilities from product registry.
| ATTRIBUTE | DESCRIPTION |
|---|---|
has_color |
Supports color control
TYPE:
|
has_multizone |
Supports multizone control (strips, beams)
TYPE:
|
has_chain |
Supports chaining (tiles)
TYPE:
|
has_matrix |
Supports 2D matrix control (tiles, candle, path)
TYPE:
|
has_infrared |
Supports infrared LED
TYPE:
|
has_hev |
Supports HEV (High Energy Visible) cleaning cycles
TYPE:
|
has_extended_multizone |
Supports extended multizone protocol
TYPE:
|
kelvin_min |
Minimum color temperature (Kelvin)
TYPE:
|
kelvin_max |
Maximum color temperature (Kelvin)
TYPE:
|
Base Device¶
The Device class provides common operations available on all LIFX devices.
Device
¶
Device(
serial: str,
ip: str,
port: int = LIFX_UDP_PORT,
timeout: float = DEFAULT_REQUEST_TIMEOUT,
max_retries: int | None = DEFAULT_MAX_RETRIES,
*,
fetch_wifi_info: bool = False,
fetch_thread_info: bool = False,
fetch_radio_info: bool = False,
fetch_ambient_light: bool = False,
)
Bases: Generic[StateT]
Base class for LIFX devices.
This class provides common functionality for all LIFX devices:
- Connection management
- Basic device queries (label, power, version, info)
- State caching for reduced network traffic
Properties return cached values or None if never fetched. Use get_*() methods to fetch fresh data from the device.
Example
device = Device(serial="d073d5123456", ip="192.168.1.100")
async with device:
# Get device label
label = await device.get_label()
print(f"Device: {label}")
# Use cached label value
if device.label is not None:
print(f"Cached label: {device.label}")
# Turn on device
await device.set_power(True)
# Get power state
is_on = await device.get_power()
if is_on is not None:
print(f"Power: {'ON' if is_on else 'OFF'}")
| PARAMETER | DESCRIPTION |
|---|---|
serial
|
Device serial number as 12-digit hex string (e.g., "d073d5123456")
TYPE:
|
ip
|
Device IP address
TYPE:
|
port
|
Device UDP port
TYPE:
|
timeout
|
Overall timeout for network requests in seconds
TYPE:
|
max_retries
|
Maximum number of retransmits per network request (default: None, retransmit until the timeout)
TYPE:
|
fetch_wifi_info
|
Query the device for WiFi signal strength whenever
state is initialized or refreshed. When False (the default),
TYPE:
|
fetch_thread_info
|
Query the device for Thread mesh information
whenever state is initialized or refreshed. Off by default so
no unrequested packet is sent;
TYPE:
|
fetch_radio_info
|
Send whichever radio query matches the device's evidenced connectivity at each fetch: the WiFi signal on a WiFi device, Thread information on a Thread device, and neither while connectivity is still unknown. Off by default.
TYPE:
|
fetch_ambient_light
|
Query the ambient light sensor whenever state is
initialized or refreshed, leaving
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If any parameter is invalid |
| METHOD | DESCRIPTION |
|---|---|
adopt_cached_metadata |
Adopt metadata already fetched by a temporary device instance. |
from_ip |
Create and return an instance for the given IP address. |
connect |
Create a device instance with the correct type for the given IP. |
get_mac_address |
Calculate and return the MAC address for this device. |
ensure_capabilities |
Ensure device capabilities are populated. |
get_label |
Get device label/name. |
set_label |
Set device label/name. |
get_power |
Get device power state. |
set_power |
Set device power state. |
get_version |
Get device version information. |
get_info |
Get device runtime information. |
get_wifi_info |
Get device WiFi module information. |
get_host_firmware |
Get device host (WiFi module) firmware information. |
get_wifi_firmware |
Get device WiFi module firmware information. |
get_thread_info |
Get device Thread radio information. |
get_location |
Get device location information. |
set_location |
Set device location information. |
get_group |
Get device group information. |
set_group |
Set device group information. |
set_reboot |
Reboot the device. |
close |
Close device connection and cleanup resources. |
refresh_state |
Refresh device state from hardware. |
| ATTRIBUTE | DESCRIPTION |
|---|---|
capabilities |
Get device product capabilities.
TYPE:
|
state |
Get device state if available.
TYPE:
|
fetch_wifi_info |
Whether state fetches include the WiFi signal strength.
TYPE:
|
fetch_thread_info |
Whether state fetches include Thread mesh information.
TYPE:
|
fetch_radio_info |
Whether state fetches include the reading for the device's own radio.
TYPE:
|
fetch_ambient_light |
Whether state fetches include the ambient light sensor.
TYPE:
|
label |
Get cached label if available.
TYPE:
|
connectivity |
How this device's radio reaches the network.
TYPE:
|
version |
Get cached version if available.
TYPE:
|
host_firmware |
Get cached host firmware if available.
TYPE:
|
wifi_firmware |
Get cached wifi firmware if available.
TYPE:
|
location |
Get cached location name if available.
TYPE:
|
group |
Get cached group name if available.
TYPE:
|
model |
Get LIFX friendly model name if available.
TYPE:
|
mac_address |
Get cached MAC address if available.
TYPE:
|
Source code in src/lifx/devices/base.py
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 | |
Attributes¶
capabilities
property
¶
capabilities: ProductInfo | None
Get device product capabilities.
Returns product information including supported features like:
- color, infrared, multizone, extended_multizone
- matrix (for tiles), chain, relays, buttons, hev
- temperature_range
Capabilities are automatically loaded when using device as context manager.
| RETURNS | DESCRIPTION |
|---|---|
ProductInfo | None
|
ProductInfo if capabilities have been loaded, None otherwise. |
state
property
¶
Get device state if available.
State is populated by the connect() factory method or by calling _initialize_state() directly. Returns None if state has not been initialized.
| RETURNS | DESCRIPTION |
|---|---|
StateT | None
|
State with current device state, or None if not initialized |
fetch_wifi_info
property
writable
¶
fetch_wifi_info: bool
Whether state fetches include the WiFi signal strength.
Toggle this to start or stop collecting state.wifi_info readings.
It takes effect from the next state initialization or refresh, which
stores None for signal and rssi while disabled rather than leaving an
unbounded-age reading behind a freshly stamped last_updated.
fetch_thread_info
property
writable
¶
fetch_thread_info: bool
Whether state fetches include Thread mesh information.
Toggle this to start or stop collecting state.thread_info. It takes
effect from the next state initialization or refresh, which stores None
while disabled rather than leaving a stale reading behind a freshly
stamped last_updated. On a device evidenced as WiFi the query is
refused before any packet is sent and the field stays None.
fetch_radio_info
property
writable
¶
fetch_radio_info: bool
Whether state fetches include the reading for the device's own radio.
With this set, each state initialization or refresh sends the WiFi
signal query on a device evidenced as WiFi and the Thread information
query on a device evidenced as Thread. While connectivity is unknown,
before any response and without an mDNS record, neither is
sent, so the first reading arrives with the first refresh after the
device has answered. :attr:fetch_wifi_info and
:attr:fetch_thread_info remain independent explicit switches.
fetch_ambient_light
property
writable
¶
fetch_ambient_light: bool
Whether state fetches include the ambient light sensor.
Toggle this to start or stop collecting state.ambient_light
readings. It takes effect from the next state initialization or
refresh, which stores None while disabled rather than leaving an
unbounded-age reading behind a freshly stamped last_updated. Only
lights expose the sensor, so this is ignored by the base Device
class.
label
property
¶
label: str | None
Get cached label if available.
Use get_label() to fetch from device.
| RETURNS | DESCRIPTION |
|---|---|
str | None
|
Device label or None if never fetched. |
connectivity
property
¶
How this device's radio reaches the network.
The device's own frame address report is authoritative: once any
correlated response has been observed, its thread_connection bit
determines the value in both directions. Until then the value comes
from discovery metadata (the mDNS TXT record), defaulting to
:attr:Connectivity.WIFI.
This makes the value correct for devices found over UDP broadcast,
:meth:from_ip, or a won find_by_serial() race, none of which
carry an mDNS TXT record.
The value does not authenticate the device or change its routing,
retry, or tuning behaviour. It does gate the radio-specific queries:
:meth:get_wifi_info and :meth:get_wifi_firmware are refused once
the device is evidenced as Thread, and :meth:get_thread_info once it
is evidenced as WiFi, because each firmware install can only answer
its own radio's packets.
version
property
¶
version: DeviceVersion | None
Get cached version if available.
Use get_version() to fetch from device.
| RETURNS | DESCRIPTION |
|---|---|
DeviceVersion | None
|
Device version or None if never fetched. |
host_firmware
property
¶
host_firmware: FirmwareInfo | None
Get cached host firmware if available.
Use get_host_firmware() to fetch from device.
| RETURNS | DESCRIPTION |
|---|---|
FirmwareInfo | None
|
Firmware info or None if never fetched. |
wifi_firmware
property
¶
wifi_firmware: FirmwareInfo | None
Get cached wifi firmware if available.
Use get_wifi_firmware() to fetch from device.
| RETURNS | DESCRIPTION |
|---|---|
FirmwareInfo | None
|
Firmware info or None if never fetched. |
location
property
¶
location: str | None
Get cached location name if available.
Use get_location() to fetch from device.
| RETURNS | DESCRIPTION |
|---|---|
str | None
|
Location name or None if never fetched. |
group
property
¶
group: str | None
Get cached group name if available.
Use get_group() to fetch from device.
| RETURNS | DESCRIPTION |
|---|---|
str | None
|
Group name or None if never fetched. |
model
property
¶
model: str | None
Get LIFX friendly model name if available.
| RETURNS | DESCRIPTION |
|---|---|
str | None
|
Model string from product registry. |
Methods:¶
adopt_cached_metadata
¶
adopt_cached_metadata(source: Device) -> None
Adopt metadata already fetched by a temporary device instance.
Device factories use a base Device to identify the correct concrete
class. This transfers only registry-derived or firmware-keyed metadata,
which the library treats as read-only; live state and connection
lifecycle remain owned by the new instance.
Source code in src/lifx/devices/base.py
from_ip
async
classmethod
¶
from_ip(
ip: str,
port: int = LIFX_UDP_PORT,
serial: str | None = None,
timeout: float = DEFAULT_REQUEST_TIMEOUT,
max_retries: int | None = DEFAULT_MAX_RETRIES,
*,
fetch_wifi_info: bool = False,
fetch_thread_info: bool = False,
fetch_radio_info: bool = False,
fetch_ambient_light: bool = False,
) -> Self
Create and return an instance for the given IP address.
This is a convenience class method for connecting to a known device by IP address. The returned instance can be used as a context manager.
| PARAMETER | DESCRIPTION |
|---|---|
ip
|
IP address of the device
TYPE:
|
port
|
Port number (default LIFX_UDP_PORT)
TYPE:
|
serial
|
Serial number as 12-digit hex string
TYPE:
|
timeout
|
Request timeout for this device instance
TYPE:
|
max_retries
|
Maximum number of retry attempts
TYPE:
|
fetch_wifi_info
|
Query WiFi signal strength during state initialization
TYPE:
|
fetch_thread_info
|
Query Thread mesh information during state initialization
TYPE:
|
fetch_radio_info
|
Query whichever radio matches the device's evidenced connectivity during state initialization
TYPE:
|
fetch_ambient_light
|
Query the ambient light sensor during state initialization (lights only)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Self
|
Device instance ready to use with async context manager |
Example
Source code in src/lifx/devices/base.py
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 | |
connect
async
classmethod
¶
connect(
ip: str,
serial: str | None = None,
port: int = LIFX_UDP_PORT,
timeout: float = DEFAULT_REQUEST_TIMEOUT,
max_retries: int | None = DEFAULT_MAX_RETRIES,
*,
fetch_wifi_info: bool = False,
fetch_thread_info: bool = False,
fetch_radio_info: bool = False,
fetch_ambient_light: bool = False,
) -> (
Light
| HevLight
| InfraredLight
| MultiZoneLight
| MatrixLight
| CeilingLight
)
Create a device instance with the correct type for the given IP.
This factory method queries the device to determine its product type and returns the appropriate subclass (Light, MatrixLight, etc.).
State is NOT initialized on return. Use async with to enter the
context manager, which calls __aenter__() → _initialize_state()
and guarantees that device.state is non-None.
| PARAMETER | DESCRIPTION |
|---|---|
ip
|
IP address of the device
TYPE:
|
serial
|
Optional serial number (12-digit hex, with or without colons). If None, queries device to get serial.
TYPE:
|
port
|
Port number (default LIFX_UDP_PORT)
TYPE:
|
timeout
|
Request timeout for this device instance
TYPE:
|
max_retries
|
Maximum number of retry attempts
TYPE:
|
fetch_wifi_info
|
Query WiFi signal strength during state initialization
TYPE:
|
fetch_thread_info
|
Query Thread mesh information during state initialization
TYPE:
|
fetch_radio_info
|
Query whichever radio matches the device's evidenced connectivity during state initialization
TYPE:
|
fetch_ambient_light
|
Query the ambient light sensor during state initialization (lights only)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Light | HevLight | InfraredLight | MultiZoneLight | MatrixLight | CeilingLight
|
Device instance of the correct subclass, ready to use with |
Light | HevLight | InfraredLight | MultiZoneLight | MatrixLight | CeilingLight
|
|
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device cannot be found or contacted |
LifxTimeoutError
|
If device does not respond |
ValueError
|
If serial format is invalid |
Example
# Connect by IP (serial auto-detected)
device = await Device.connect(ip="192.168.1.100")
async with device:
# State is initialized here by __aenter__()
print(f"{device.state.model}: {device.state.label}")
if device.state.is_on:
print("Device is on")
# Connect with known serial
device = await Device.connect(ip="192.168.1.100", serial="d073d5123456")
async with device:
await device.set_power(True)
Source code in src/lifx/devices/base.py
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 | |
get_mac_address
async
¶
get_mac_address() -> str
Calculate and return the MAC address for this device.
The MAC usually equals the serial. Firmware with
version_major == 3 and version_minor >= 70 is the exception: its MAC
is the serial with the final octet incremented by one (wrapping at 256).
The bound is deliberately narrower than "major version 3" and comes from LIFX. Devices on earlier 3.x firmware report a MAC identical to their serial -- consistent with LIFX Tiles on 3.50, whose real ARP MAC matched the serial while a major-only rule predicted serial + 1.
The result is memoised against the firmware it was derived from. Because the rule now turns on the minor version, an ordinary in-place update across the 3.70 boundary changes the correct answer -- so a cache keyed on nothing but "already computed" would hand a long-lived caller a MAC the device no longer has.
Source code in src/lifx/devices/base.py
ensure_capabilities
async
¶
Ensure device capabilities are populated.
Fetches device version and firmware to determine product capabilities. This is a no-op if capabilities have already been loaded (e.g. via the async context manager).
Source code in src/lifx/devices/base.py
get_label
async
¶
get_label() -> str
Get device label/name.
Always fetches from device. Use the label property to access stored value.
| RETURNS | DESCRIPTION |
|---|---|
str
|
Device label as string (max 32 bytes UTF-8) |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/base.py
set_label
async
¶
set_label(label: str) -> None
Set device label/name.
| PARAMETER | DESCRIPTION |
|---|---|
label
|
New device label (max 32 bytes UTF-8)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If label is too long |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Source code in src/lifx/devices/base.py
get_power
async
¶
get_power() -> int
Get device power state.
Always fetches from device.
| RETURNS | DESCRIPTION |
|---|---|
int
|
Power level as integer (0 for off, 65535 for on) |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Source code in src/lifx/devices/base.py
set_power
async
¶
Set device power state.
| PARAMETER | DESCRIPTION |
|---|---|
level
|
True/65535 to turn on, False/0 to turn off |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If integer value is not 0 or 65535 |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/base.py
get_version
async
¶
get_version() -> DeviceVersion
Get device version information.
Always fetches from device.
| RETURNS | DESCRIPTION |
|---|---|
DeviceVersion
|
DeviceVersion with vendor and product fields |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/base.py
get_info
async
¶
get_info() -> DeviceInfo
Get device runtime information.
Always fetches from device.
| RETURNS | DESCRIPTION |
|---|---|
DeviceInfo
|
DeviceInfo with time, uptime, and downtime |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/base.py
get_wifi_info
async
¶
get_wifi_info() -> WifiInfo
Get device WiFi module information.
Always fetches from device. If host firmware has not already been fetched, this also requests and caches it because the firmware version determines whether RSSI is reported in dB or dBm.
| RETURNS | DESCRIPTION |
|---|---|
WifiInfo
|
WifiInfo with signal strength and RSSI |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/base.py
get_host_firmware
async
¶
get_host_firmware() -> FirmwareInfo
Get device host (WiFi module) firmware information.
Always fetches from device.
| RETURNS | DESCRIPTION |
|---|---|
FirmwareInfo
|
FirmwareInfo with build timestamp and version |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/base.py
get_wifi_firmware
async
¶
get_wifi_firmware() -> FirmwareInfo
Get device WiFi module firmware information.
Always fetches from device.
| RETURNS | DESCRIPTION |
|---|---|
FirmwareInfo
|
FirmwareInfo with build timestamp and version |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/base.py
get_thread_info
async
¶
get_thread_info() -> ThreadInfo
Get device Thread radio information.
Always fetches from the device: link health is volatile, so nothing
here is cached. The query is refused once the device is evidenced as
WiFi, because WiFi and Thread are mutually exclusive firmware
installs and WiFi firmware cannot answer ThreadGetInfo. A device
that has not yet answered anything and carries no discovery metadata is
queried and answers for itself.
| RETURNS | DESCRIPTION |
|---|---|
ThreadInfo
|
ThreadInfo with routing role, network name and link health |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If the device is on WiFi firmware or does not support this command |
Example
Source code in src/lifx/devices/base.py
get_location
async
¶
get_location() -> CollectionInfo
Get device location information.
Always fetches from device.
| RETURNS | DESCRIPTION |
|---|---|
CollectionInfo
|
CollectionInfo with location UUID, label, and updated timestamp |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/base.py
set_location
async
¶
Set device location information.
Automatically discovers devices on the network to check if any device already has the target location label. If found, reuses that existing UUID to ensure devices with the same label share the same location UUID. If not found, generates a new UUID for this label.
| PARAMETER | DESCRIPTION |
|---|---|
label
|
Location label (max 32 characters)
TYPE:
|
discover_timeout
|
Timeout for device discovery in seconds
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
ValueError
|
If label is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/base.py
1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 | |
get_group
async
¶
get_group() -> CollectionInfo
Get device group information.
Always fetches from device.
| RETURNS | DESCRIPTION |
|---|---|
CollectionInfo
|
CollectionInfo with group UUID, label, and updated timestamp |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/base.py
set_group
async
¶
Set device group information.
Automatically discovers devices on the network to check if any device already has the target group label. If found, reuses that existing UUID to ensure devices with the same label share the same group UUID. If not found, generates a new UUID for this label.
| PARAMETER | DESCRIPTION |
|---|---|
label
|
Group label (max 32 characters)
TYPE:
|
discover_timeout
|
Timeout for device discovery in seconds
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
ValueError
|
If label is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/base.py
1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 | |
set_reboot
async
¶
Reboot the device.
This sends a reboot command to the device. The device will disconnect and restart. You should disconnect from the device after calling this method.
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Note
After rebooting, you may need to wait 10-30 seconds before the device comes back online and is discoverable again.
Source code in src/lifx/devices/base.py
close
async
¶
Close device connection and cleanup resources.
Cancels any pending refresh tasks and closes the network connection. Called automatically when exiting the async context manager.
Source code in src/lifx/devices/base.py
refresh_state
async
¶
Refresh device state from hardware.
On a device whose state has not been initialized yet, this delegates to
:meth:_initialize_state, which populates the whole state: the
semi-static fields (host and WiFi firmware versions, location, group)
alongside label and power, and the WiFi signal when
:attr:fetch_wifi_info is set.
On an already-initialized device this re-queries what can change without
the library knowing - label and power, plus the opt-in WiFi reading -
and stamps last_updated from those readings. The semi-static fields
are deliberately left alone: they are cached because a firmware version
or group assignment does not change under a running application.
Subclasses extend this with the volatile state their devices expose:
:class:~lifx.devices.light.Light replaces the label and power queries
with a single colour request that returns all three, and its own
subclasses add zones, tiles, infrared, HEV and ceiling components.
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
If device does not respond |
LifxDeviceNotFoundError
|
If device cannot be reached |
Source code in src/lifx/devices/base.py
Light¶
The Light class provides color control and effects for standard LIFX lights.
Light
¶
Light(
serial: str,
ip: str,
port: int = LIFX_UDP_PORT,
timeout: float = DEFAULT_REQUEST_TIMEOUT,
max_retries: int | None = DEFAULT_MAX_RETRIES,
*,
fetch_wifi_info: bool = False,
fetch_thread_info: bool = False,
fetch_radio_info: bool = False,
fetch_ambient_light: bool = False,
)
Bases: Device[LightState]
LIFX light device with color control.
Extends the base Device class with light-specific functionality:
- Color control (HSBK)
- Brightness control
- Color temperature control
- Waveform control
Example
light = Light(serial="d073d5123456", ip="192.168.1.100")
async with light:
# Set color
await light.set_color(HSBK.from_rgb(1.0, 0.0, 0.0))
# Set brightness
await light.set_brightness(0.5)
# Set temperature
await light.set_temperature(3500)
Using the simplified connect method (without knowing the serial):
| METHOD | DESCRIPTION |
|---|---|
start_effect |
Start a software effect on this light alone. |
stop_effect |
Stop every effect on this light. |
get_color |
Get current light color, power, and label. |
set_color |
Set light color. |
set_brightness |
Set light brightness only, preserving hue, saturation, and temperature. |
set_kelvin |
Set light color temperature, preserving brightness. Saturation is |
set_hue |
Set light hue only, preserving saturation, brightness, and temperature. |
set_saturation |
Set light saturation only, preserving hue, brightness, and temperature. |
get_power |
Get light power state (specific to light, not device). |
get_ambient_light_level |
Get ambient light level from device sensor. |
set_power |
Set light power state (specific to light, not device). |
set_waveform |
Apply a waveform to the light. |
set_waveform_optional |
Apply a waveform with selective color component control. |
pulse |
Pulse the light to a specific color. |
breathe |
Make the light breathe to a specific color. |
apply_theme |
Apply a theme to this light. |
apply_mood |
Paint a theme the way the LIFX app paints a mood. |
animate_mood |
Start the effect the LIFX app's Dynamic toggle starts for a mood. |
refresh_state |
Refresh light state from hardware. |
| ATTRIBUTE | DESCRIPTION |
|---|---|
animator |
The one Animator this light owns, created on first access.
TYPE:
|
state |
Get light state (guaranteed to be initialized when using Device.connect()).
TYPE:
|
min_kelvin |
Get the minimum supported kelvin value if available.
TYPE:
|
max_kelvin |
Get the maximum supported kelvin value if available.
TYPE:
|
Source code in src/lifx/devices/base.py
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 | |
Attributes¶
animator
property
¶
animator: Animator
The one Animator this light owns, created on first access.
Library effects and direct frame senders such as LedFx borrow this Animator, so every frame for the light goes through one writer and one ack gate. A single light's Animator is ready at once; a matrix or multizone light's Animator must be prepared before its first frame, which queries the device for its geometry once.
state
property
¶
state: LightState
Get light state (guaranteed to be initialized when using Device.connect()).
| RETURNS | DESCRIPTION |
|---|---|
LightState
|
LightState with current light state |
| RAISES | DESCRIPTION |
|---|---|
RuntimeError
|
If accessed before state initialization |
min_kelvin
property
¶
min_kelvin: int | None
Get the minimum supported kelvin value if available.
| RETURNS | DESCRIPTION |
|---|---|
int | None
|
Minimum kelvin value from product registry. |
max_kelvin
property
¶
max_kelvin: int | None
Get the maximum supported kelvin value if available.
| RETURNS | DESCRIPTION |
|---|---|
int | None
|
Maximum kelvin value from product registry. |
Methods:¶
start_effect
async
¶
start_effect(effect: LIFXEffect, *, enable_thread: bool = False) -> None
Start a software effect on this light alone.
A shortcut for a one-participant Conductor run: the light's prior
state is captured before the effect starts and restored when it ends
or when stop_effect() is called. Each light keeps one Conductor
for these runs, so starting another effect on the same light follows
the Conductor's rules: it replaces the running effect and inherits
its original prior state. On a Ceiling or Mirror it also replaces any
effects on the light components, and stopping it restores what was
there before any of them started.
Only software effects can be started here. Firmware effects keep
their own API, such as set_effect() on matrix and multizone
lights.
An effect that draws frames streams them to the light, and a Thread
mesh is not built for that traffic. On a light evidenced as Thread,
by its own replies or an mDNS record, it is refused unless
enable_thread is True. A light not yet heard from is not refused,
and neither is an effect that streams no frames, such as EffectPulse
or EffectColorloop.
| PARAMETER | DESCRIPTION |
|---|---|
effect
|
The software effect to run
TYPE:
|
enable_thread
|
Stream frames to a light evidenced as Thread anyway. Off by default.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
TypeError
|
If |
LifxUnsupportedCommandError
|
If the effect draws frames, the
light is evidenced as Thread and |
Example
Source code in src/lifx/devices/light.py
stop_effect
async
¶
Stop every effect on this light.
Stops any running firmware effect, then any software effect the light
or one of its light components is part of, and restores the prior
state of each. The software effect
may have been started with start_effect() or on any Conductor: if
the light is one participant of a multi-light run, it leaves that run
and the other participants carry on.
After animate_mood(), the light gets back what it showed before
its mood animation started, once: a second call restores nothing
more.
Source code in src/lifx/devices/light.py
get_color
async
¶
Get current light color, power, and label.
Always fetches from device. Use the color property to access stored value.
Returns a tuple containing:
- color: HSBK color
- power: Power level as integer (0 for off, 65535 for on)
- label: Device label/name
| RETURNS | DESCRIPTION |
|---|---|
tuple[HSBK, int, str]
|
Tuple of (color, power, label) |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/light.py
set_color
async
¶
Set light color.
| PARAMETER | DESCRIPTION |
|---|---|
color
|
HSBK color to set
TYPE:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/light.py
set_brightness
async
¶
Set light brightness only, preserving hue, saturation, and temperature.
| PARAMETER | DESCRIPTION |
|---|---|
brightness
|
Brightness level (0.0-1.0)
TYPE:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If brightness is out of range |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
Example
Source code in src/lifx/devices/light.py
set_kelvin
async
¶
Set light color temperature, preserving brightness. Saturation is automatically set to 0 to switch the light to color temperature mode.
| PARAMETER | DESCRIPTION |
|---|---|
kelvin
|
Color temperature in Kelvin (1500-9000)
TYPE:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If kelvin is out of range |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
Example
Source code in src/lifx/devices/light.py
set_hue
async
¶
Set light hue only, preserving saturation, brightness, and temperature.
| PARAMETER | DESCRIPTION |
|---|---|
hue
|
Hue in degrees (0-360)
TYPE:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If hue is out of range |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
Example
Source code in src/lifx/devices/light.py
set_saturation
async
¶
Set light saturation only, preserving hue, brightness, and temperature.
| PARAMETER | DESCRIPTION |
|---|---|
saturation
|
Saturation level (0.0-1.0)
TYPE:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If saturation is out of range |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
Example
Source code in src/lifx/devices/light.py
get_power
async
¶
get_power() -> int
Get light power state (specific to light, not device).
Always fetches from device.
This overrides Device.get_power() as it queries the light-specific power state (packet type 116/118) instead of device power (packet type 20/22).
| RETURNS | DESCRIPTION |
|---|---|
int
|
Power level as integer (0 for off, 65535 for on) |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Source code in src/lifx/devices/light.py
get_ambient_light_level
async
¶
get_ambient_light_level() -> float
Get ambient light level from device sensor.
Always fetches from device (volatile property, not cached).
This method queries the device's ambient light sensor to get the current lux reading. Devices without ambient light sensors will return 0.0.
| RETURNS | DESCRIPTION |
|---|---|
float
|
Ambient light level in lux (0.0 if device has no sensor) |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/light.py
set_power
async
¶
Set light power state (specific to light, not device).
This overrides Device.set_power() as it uses the light-specific power packet (type 117) which supports transition duration.
| PARAMETER | DESCRIPTION |
|---|---|
level
|
True/65535 to turn on, False/0 to turn off |
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If integer value is not 0 or 65535 |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/light.py
set_waveform
async
¶
set_waveform(
color: HSBK,
period: float,
cycles: float,
waveform: LightWaveform,
transient: bool = True,
skew_ratio: float = 0.5,
) -> None
Apply a waveform to the light.
Waveforms create repeating color transitions. Useful for pulsing, breathing, or blinking.
Cycles may be fractional; 0.5 is a half cycle. On a colour bulb, a half cycle moves towards the target for half a period, then a transient waveform jumps straight back to the original colour (no fade back), while a non-transient one stays at the target.
| PARAMETER | DESCRIPTION |
|---|---|
color
|
Target color for the waveform
TYPE:
|
period
|
Period of one cycle in seconds. Zero requests an immediate transition.
TYPE:
|
cycles
|
Number of cycles, must be greater than 0 (may be fractional)
TYPE:
|
waveform
|
Waveform type (SAW, SINE, HALF_SINE, TRIANGLE, PULSE)
TYPE:
|
transient
|
If True, return to the original color once the waveform completes (default True)
TYPE:
|
skew_ratio
|
Waveform skew (0.0-1.0, default 0.5 for symmetric)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If parameters are out of range |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
from lifx.protocol.protocol_types import LightWaveform
# Pulse red 5 times
await light.set_waveform(
color=HSBK.from_rgb(1.0, 0.0, 0.0),
period=1.0,
cycles=5,
waveform=LightWaveform.PULSE,
)
# Breathe white once
await light.set_waveform(
color=HSBK(0, 0, 1.0, 3500),
period=2.0,
cycles=1,
waveform=LightWaveform.SINE,
transient=False,
)
Source code in src/lifx/devices/light.py
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 | |
set_waveform_optional
async
¶
set_waveform_optional(
color: HSBK,
period: float,
cycles: float,
waveform: LightWaveform,
transient: bool = True,
skew_ratio: float = 0.5,
set_hue: bool = True,
set_saturation: bool = True,
set_brightness: bool = True,
set_kelvin: bool = True,
) -> None
Apply a waveform with selective color component control.
Similar to set_waveform() but allows fine-grained control over which color components (hue, saturation, brightness, kelvin) are affected by the waveform. This enables pulsing brightness while keeping hue constant, or cycling hue while maintaining brightness.
Cycles may be fractional; 0.5 is a half cycle. On a colour bulb, a half cycle moves towards the target for half a period, then a transient waveform jumps straight back to the original colour (no fade back), while a non-transient one stays at the target.
| PARAMETER | DESCRIPTION |
|---|---|
color
|
Target color for the waveform
TYPE:
|
period
|
Period of one cycle in seconds. Zero requests an immediate transition.
TYPE:
|
cycles
|
Number of cycles, must be greater than 0 (may be fractional)
TYPE:
|
waveform
|
Waveform type (SAW, SINE, HALF_SINE, TRIANGLE, PULSE)
TYPE:
|
transient
|
If True, return to the original color once the waveform completes (default True)
TYPE:
|
skew_ratio
|
Waveform skew (0.0-1.0, default 0.5 for symmetric)
TYPE:
|
set_hue
|
Apply waveform to hue component (default True)
TYPE:
|
set_saturation
|
Apply waveform to saturation component (default True)
TYPE:
|
set_brightness
|
Apply waveform to brightness component (default True)
TYPE:
|
set_kelvin
|
Apply waveform to kelvin component (default True)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If parameters are out of range |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
from lifx.protocol.protocol_types import LightWaveform
# Pulse brightness only, keeping hue/saturation constant
await light.set_waveform_optional(
color=HSBK(0, 1.0, 1.0, 3500),
period=1.0,
cycles=5,
waveform=LightWaveform.SINE,
set_hue=False,
set_saturation=False,
set_brightness=True,
set_kelvin=False,
)
# Cycle hue while maintaining brightness
await light.set_waveform_optional(
color=HSBK(180, 1.0, 1.0, 3500),
period=5.0,
cycles=1000,
waveform=LightWaveform.SAW,
set_hue=True,
set_saturation=False,
set_brightness=False,
set_kelvin=False,
)
Source code in src/lifx/devices/light.py
842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 | |
pulse
async
¶
Pulse the light to a specific color.
Convenience method using the PULSE waveform.
| PARAMETER | DESCRIPTION |
|---|---|
color
|
Target color to pulse to
TYPE:
|
period
|
Period of one pulse in seconds (default 1.0)
TYPE:
|
cycles
|
Number of pulses (default 1)
TYPE:
|
transient
|
If True, return to the original color once the waveform completes (default True)
TYPE:
|
Example
Source code in src/lifx/devices/light.py
breathe
async
¶
Make the light breathe to a specific color.
Convenience method using the SINE waveform.
| PARAMETER | DESCRIPTION |
|---|---|
color
|
Target color to breathe to
TYPE:
|
period
|
Period of one breath in seconds (default 2.0)
TYPE:
|
cycles
|
Number of breaths (default 1)
TYPE:
|
Example
Source code in src/lifx/devices/light.py
apply_theme
async
¶
Apply a theme to this light.
Selects a random color from the theme and applies it to the light.
| PARAMETER | DESCRIPTION |
|---|---|
theme
|
Theme to apply
TYPE:
|
power_on
|
Turn on the light
TYPE:
|
duration
|
Transition duration in seconds
TYPE:
|
Example
Source code in src/lifx/devices/light.py
apply_mood
async
¶
apply_mood(theme: Theme) -> None
Paint a theme the way the LIFX app paints a mood.
The recipe comes from theme.static_mode. The mood is rescaled so
its brightest colour matches the light's current brightness, fades in
over 0.3 seconds, and turns the light on only when it is off. If a
mood effect is already running, it restarts with this theme instead.
A bulb shows one of the theme's colours. Use DeviceGroup to deal
the colours across several bulbs.
| PARAMETER | DESCRIPTION |
|---|---|
theme
|
Theme to paint
TYPE:
|
Source code in src/lifx/devices/light.py
animate_mood
async
¶
animate_mood(theme: Theme) -> None
Start the effect the LIFX app's Dynamic toggle starts for a mood.
A bulb steps through the theme's colours. A strip paints the mood and runs firmware MOVE. A matrix light runs firmware MORPH, or paints the mood and scrolls it for a MOVE mood; a Mirror, Spot or Path always runs MORPH. The colours are rescaled to the light's brightness, and the light is turned on if it is off.
Stop it with stop_effect(), which puts back what the light showed
before its mood animation started. Starting another mood keeps that
state rather than capturing the animation.
| PARAMETER | DESCRIPTION |
|---|---|
theme
|
Theme to animate
TYPE:
|
Source code in src/lifx/devices/light.py
refresh_state
async
¶
Refresh light state from hardware.
Fetches color (which includes power and label), plus the WiFi signal
and ambient light reading when :attr:fetch_wifi_info and
:attr:fetch_ambient_light are set, and updates state. Initializes
state first when the device has none yet.
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
If device does not respond |
LifxDeviceNotFoundError
|
If device cannot be reached |
Source code in src/lifx/devices/light.py
LightState¶
Light device state dataclass returned by Light.state.
ambient_light holds the most recent lux reading, -1.0 when that reading was
taken while the light was on (the sensor measures the light's own output, not
the room), or None when the sensor was not queried. Like wifi_info, it is
only fetched when the device was created with fetch_ambient_light=True, or
once the fetch_ambient_light property is set on the device:
light = await Device.connect(ip="192.168.1.100", fetch_ambient_light=True)
async with light:
print(f"Ambient light: {light.state.ambient_light} lux")
light.fetch_ambient_light = False # stop collecting
LightState
dataclass
¶
LightState(
model: str,
label: str,
serial: str,
mac_address: str,
capabilities: DeviceCapabilities,
power: int,
host_firmware: FirmwareInfo,
wifi_firmware: FirmwareInfo,
location: CollectionInfo,
group: CollectionInfo,
last_updated: float,
color: HSBK,
*,
wifi_info: WifiInfo = (lambda: WifiInfo(signal=None, host_firmware=None))(),
thread_info: ThreadInfo | None = None,
ambient_light: float | None = None,
)
Bases: DeviceState
Light device state with color control.
| ATTRIBUTE | DESCRIPTION |
|---|---|
color |
Current HSBK color
TYPE:
|
ambient_light |
Ambient light level in lux, or None when the sensor was
not queried. Devices without a sensor report 0.0, as does a device
in complete darkness. A reading taken while the light is on measures
the light's own output rather than the room, and is stored as
:data:
TYPE:
|
Attributes¶
as_dict
property
¶
as_dict: Any
Return LightState as a dict.
Extends :attr:DeviceState.as_dict so the curated capability and
firmware expansion applies to light states too. HSBK is not a
dataclass, so color is expanded via :attr:HSBK.as_dict to keep
the result serialisable.
Subclasses extend this and add their own fields explicitly rather than
calling dataclasses.asdict, which would both bypass that curation
and deep-copy every HSBK just for the override to discard it.
HEV Light¶
The HevLight class extends Light with anti-bacterial cleaning cycle control for LIFX HEV devices.
HevLight
¶
HevLight(
serial: str,
ip: str,
port: int = LIFX_UDP_PORT,
timeout: float = DEFAULT_REQUEST_TIMEOUT,
max_retries: int | None = DEFAULT_MAX_RETRIES,
*,
fetch_wifi_info: bool = False,
fetch_thread_info: bool = False,
fetch_radio_info: bool = False,
fetch_ambient_light: bool = False,
)
Bases: Light
LIFX HEV light with anti-bacterial cleaning capabilities.
Extends the Light class with HEV (High Energy Visible) cycle control. HEV uses UV-C light to sanitize surfaces and air with anti-bacterial properties.
Example
light = HevLight(serial="d073d5123456", ip="192.168.1.100")
async with light:
# Start a 2-hour cleaning cycle
await light.set_hev_cycle(enable=True, duration_seconds=7200)
# Check cycle status
state = await light.get_hev_cycle()
if state.is_running:
print(f"Cleaning: {state.remaining_s}s remaining")
# Configure defaults
await light.set_hev_config(indication=True, duration_seconds=7200)
Using the simplified connect method:
See :class:~lifx.devices.base.Device for parameter documentation. The
signature is spelled out rather than forwarded as *args, **kwargs so
callers get the same type checking the base class offers.
| METHOD | DESCRIPTION |
|---|---|
get_hev_cycle |
Get current HEV cycle state. |
set_hev_cycle |
Start or stop a HEV cleaning cycle. |
get_hev_config |
Get HEV cycle configuration. |
set_hev_config |
Configure HEV cycle defaults. |
get_last_hev_result |
Get result of the last HEV cleaning cycle. |
refresh_state |
Refresh HEV light state from hardware. |
| ATTRIBUTE | DESCRIPTION |
|---|---|
state |
Get HEV light state (guaranteed when using Device.connect()).
TYPE:
|
hev_config |
Get cached HEV configuration if available.
TYPE:
|
hev_result |
Get cached last HEV cycle result if available.
TYPE:
|
Source code in src/lifx/devices/hev.py
Attributes¶
state
property
¶
state: HevLightState
Get HEV light state (guaranteed when using Device.connect()).
| RETURNS | DESCRIPTION |
|---|---|
HevLightState
|
HevLightState with current HEV light state |
| RAISES | DESCRIPTION |
|---|---|
RuntimeError
|
If accessed before state initialization |
hev_result
property
¶
Get cached last HEV cycle result if available.
| RETURNS | DESCRIPTION |
|---|---|
LightLastHevCycleResult | None
|
Result or None if never fetched. |
LightLastHevCycleResult | None
|
Use get_last_hev_result() to fetch from device. |
Methods:¶
get_hev_cycle
async
¶
get_hev_cycle() -> HevCycleState
Get current HEV cycle state.
Always fetches from device. Use the hev_cycle property to access stored value.
| RETURNS | DESCRIPTION |
|---|---|
HevCycleState
|
HevCycleState with duration, remaining time, and last power state |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/hev.py
set_hev_cycle
async
¶
Start or stop a HEV cleaning cycle.
If a duration is not provided, the light will use whatever the default duration is currently stored in the HEV configuration. See the get_hev_config() and set_hev_config() methods for details.
| PARAMETER | DESCRIPTION |
|---|---|
enable
|
True to start cycle, False to stop
TYPE:
|
duration_seconds
|
Duration of the cleaning cycle in seconds (optional)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If duration is negative |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/hev.py
get_hev_config
async
¶
get_hev_config() -> HevConfig
Get HEV cycle configuration.
| RETURNS | DESCRIPTION |
|---|---|
HevConfig
|
HevConfig with indication and default duration settings |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/hev.py
set_hev_config
async
¶
Configure HEV cycle defaults.
| PARAMETER | DESCRIPTION |
|---|---|
indication
|
Whether to show visual indication during cleaning
TYPE:
|
duration_seconds
|
Default duration for cleaning cycles in seconds
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If duration is negative |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/hev.py
get_last_hev_result
async
¶
Get result of the last HEV cleaning cycle.
| RETURNS | DESCRIPTION |
|---|---|
LightLastHevCycleResult
|
LightLastHevCycleResult enum value indicating success or interruption reason |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/hev.py
refresh_state
async
¶
Refresh HEV light state from hardware.
Fetches color, HEV cycle, config, and last result.
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
If device does not respond |
LifxDeviceNotFoundError
|
If device cannot be reached |
Source code in src/lifx/devices/hev.py
HevLightState¶
HEV light device state dataclass returned by HevLight.state.
HevLightState
dataclass
¶
HevLightState(
model: str,
label: str,
serial: str,
mac_address: str,
capabilities: DeviceCapabilities,
power: int,
host_firmware: FirmwareInfo,
wifi_firmware: FirmwareInfo,
location: CollectionInfo,
group: CollectionInfo,
last_updated: float,
color: HSBK,
hev_cycle: HevCycleState,
hev_config: HevConfig,
hev_result: LightLastHevCycleResult,
*,
wifi_info: WifiInfo = (lambda: WifiInfo(signal=None, host_firmware=None))(),
thread_info: ThreadInfo | None = None,
ambient_light: float | None = None,
)
Bases: LightState
HEV light device state with anti-bacterial capabilities.
| ATTRIBUTE | DESCRIPTION |
|---|---|
hev_cycle |
Current HEV cycle state
TYPE:
|
hev_config |
Default HEV configuration
TYPE:
|
hev_result |
Last HEV cycle result
TYPE:
|
| METHOD | DESCRIPTION |
|---|---|
from_light_state |
Create HevLightState from LightState. |
Attributes¶
as_dict
property
¶
as_dict: Any
Return HevLightState as dict.
hev_cycle and hev_config are plain dataclasses, so
dataclasses.asdict expands them without any HSBK to deep-copy.
Methods:¶
from_light_state
classmethod
¶
from_light_state(
light_state: LightState,
hev_cycle: HevCycleState,
hev_config: HevConfig,
hev_result: LightLastHevCycleResult,
) -> HevLightState
Create HevLightState from LightState.
Source code in src/lifx/devices/hev.py
Infrared Light¶
The InfraredLight class extends Light with infrared LED control for night vision on LIFX A19 + Night Vision devices.
InfraredLight
¶
InfraredLight(
serial: str,
ip: str,
port: int = LIFX_UDP_PORT,
timeout: float = DEFAULT_REQUEST_TIMEOUT,
max_retries: int | None = DEFAULT_MAX_RETRIES,
*,
fetch_wifi_info: bool = False,
fetch_thread_info: bool = False,
fetch_radio_info: bool = False,
fetch_ambient_light: bool = False,
)
Bases: Light
LIFX infrared light with IR LED control.
Extends the Light class with infrared brightness control. Infrared LEDs automatically activate in low-light conditions to provide illumination for night vision cameras.
Example
light = InfraredLight(serial="d073d5123456", ip="192.168.1.100")
async with light:
# Set infrared brightness to 50%
await light.set_infrared(0.5)
# Get current infrared brightness
brightness = await light.get_infrared()
print(f"IR brightness: {brightness * 100}%")
Using the simplified connect method:
See :class:~lifx.devices.base.Device for parameter documentation. The
signature is spelled out rather than forwarded as *args, **kwargs so
callers get the same type checking the base class offers.
| METHOD | DESCRIPTION |
|---|---|
get_infrared |
Get current infrared brightness. |
set_infrared |
Set infrared brightness. |
refresh_state |
Refresh infrared light state from hardware. |
| ATTRIBUTE | DESCRIPTION |
|---|---|
state |
Get infrared light state (guaranteed when using Device.connect()).
TYPE:
|
infrared |
Get cached infrared brightness if available.
TYPE:
|
Source code in src/lifx/devices/infrared.py
Attributes¶
state
property
¶
state: InfraredLightState
Get infrared light state (guaranteed when using Device.connect()).
| RETURNS | DESCRIPTION |
|---|---|
InfraredLightState
|
InfraredLightState with current infrared light state |
| RAISES | DESCRIPTION |
|---|---|
RuntimeError
|
If accessed before state initialization |
Methods:¶
get_infrared
async
¶
get_infrared() -> float
Get current infrared brightness.
| RETURNS | DESCRIPTION |
|---|---|
float
|
Infrared brightness (0.0-1.0) |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/infrared.py
set_infrared
async
¶
set_infrared(brightness: float) -> None
Set infrared brightness.
| PARAMETER | DESCRIPTION |
|---|---|
brightness
|
Infrared brightness (0.0-1.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If brightness is out of range |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/infrared.py
refresh_state
async
¶
Refresh infrared light state from hardware.
Fetches color and infrared brightness.
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
If device does not respond |
LifxDeviceNotFoundError
|
If device cannot be reached |
Source code in src/lifx/devices/infrared.py
InfraredLightState¶
Infrared light device state dataclass returned by InfraredLight.state.
InfraredLightState
dataclass
¶
InfraredLightState(
model: str,
label: str,
serial: str,
mac_address: str,
capabilities: DeviceCapabilities,
power: int,
host_firmware: FirmwareInfo,
wifi_firmware: FirmwareInfo,
location: CollectionInfo,
group: CollectionInfo,
last_updated: float,
color: HSBK,
infrared: float,
*,
wifi_info: WifiInfo = (lambda: WifiInfo(signal=None, host_firmware=None))(),
thread_info: ThreadInfo | None = None,
ambient_light: float | None = None,
)
Bases: LightState
Infrared light device state with IR control.
| ATTRIBUTE | DESCRIPTION |
|---|---|
infrared |
Infrared brightness (0.0-1.0)
TYPE:
|
| METHOD | DESCRIPTION |
|---|---|
from_light_state |
Create InfraredLightState from LightState. |
Attributes¶
Methods:¶
from_light_state
classmethod
¶
from_light_state(
light_state: LightState, infrared: float
) -> InfraredLightState
Create InfraredLightState from LightState.
Source code in src/lifx/devices/infrared.py
MultiZone Light¶
The MultiZoneLight class controls LIFX strips and beams with multiple color zones.
MultiZoneLight
¶
MultiZoneLight(
serial: str,
ip: str,
port: int = LIFX_UDP_PORT,
timeout: float = DEFAULT_REQUEST_TIMEOUT,
max_retries: int | None = DEFAULT_MAX_RETRIES,
*,
fetch_wifi_info: bool = False,
fetch_thread_info: bool = False,
fetch_radio_info: bool = False,
fetch_ambient_light: bool = False,
)
Bases: Light
LIFX MultiZone light device (strips, beams).
Extends the Light class with zone-specific functionality:
- Individual zone color control
- Multi-zone effects (move, etc.)
- Extended color zone support for efficient bulk updates
Example
from lifx import Direction
light = MultiZoneLight(serial="d073d5123456", ip="192.168.1.100")
async with light:
# Get number of zones
zone_count = await light.get_zone_count()
print(f"Device has {zone_count} zones")
# Set all zones to red
await light.set_color_zones(
start=0, end=zone_count - 1, color=HSBK.from_rgb(1.0, 0.0, 0.0)
)
# Get colors for first 5 zones
colors = await light.get_color_zones(0, 4)
# Apply a moving effect
await light.set_move_effect(Direction.FORWARD, 5.0)
Using the simplified connect method:
See :class:~lifx.devices.base.Device for parameter documentation. The
signature is spelled out rather than forwarded as *args, **kwargs so
callers get the same type checking the base class offers.
| METHOD | DESCRIPTION |
|---|---|
get_zone_count |
Get the number of zones in the device. |
get_color_zones |
Get colors for a range of zones using GetColorZones. |
get_extended_color_zones |
Get colors for a range of zones using GetExtendedColorZones. |
get_all_color_zones |
Get colors for all zones, automatically using the best method. |
set_color_zones |
Set color for a range of zones. |
set_extended_color_zones |
Set colors for multiple zones efficiently (up to 82 zones per call). |
get_effect |
Get current multizone effect. |
set_effect |
Set multizone effect. |
set_move_effect |
Start the firmware Move effect in one call. |
set_all_color_zones |
Set zone colors from a full-length color list. |
apply_theme |
Apply a theme across zones. |
animate_mood |
Paint the mood, then run firmware MOVE at the app's speed. |
refresh_state |
Refresh multizone light state from hardware. |
| ATTRIBUTE | DESCRIPTION |
|---|---|
state |
Get multizone light state (guaranteed when using Device.connect()).
TYPE:
|
zone_count |
Get cached zone count if available.
TYPE:
|
multizone_effect |
Get cached multizone effect if available.
TYPE:
|
Source code in src/lifx/devices/multizone.py
Attributes¶
state
property
¶
state: MultiZoneLightState
Get multizone light state (guaranteed when using Device.connect()).
| RETURNS | DESCRIPTION |
|---|---|
MultiZoneLightState
|
MultiZoneLightState with current multizone light state |
| RAISES | DESCRIPTION |
|---|---|
RuntimeError
|
If accessed before state initialization |
multizone_effect
property
¶
multizone_effect: MultiZoneEffect | None | None
Get cached multizone effect if available.
| RETURNS | DESCRIPTION |
|---|---|
MultiZoneEffect | None | None
|
Effect or None if never fetched. |
MultiZoneEffect | None | None
|
Use get_effect() to fetch from device. |
Methods:¶
get_zone_count
async
¶
get_zone_count() -> int
Get the number of zones in the device.
Always fetches from the device. Use the zone_count property to
access the most recently stored value without a network request.
| RETURNS | DESCRIPTION |
|---|---|
int
|
Number of zones |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Source code in src/lifx/devices/multizone.py
get_color_zones
async
¶
Get colors for a range of zones using GetColorZones.
Always fetches from device.
Use zones property to access stored values.
| PARAMETER | DESCRIPTION |
|---|---|
start
|
Start zone index (inclusive, default 0)
TYPE:
|
end
|
End zone index (inclusive, default 255)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[HSBK]
|
List of HSBK colors, one per zone |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If zone indices are invalid |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/multizone.py
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 | |
get_extended_color_zones
async
¶
Get colors for a range of zones using GetExtendedColorZones.
Always fetches from device.
Use zones property to access stored values.
| PARAMETER | DESCRIPTION |
|---|---|
start
|
Start zone index (inclusive, default 0)
TYPE:
|
end
|
End zone index (inclusive, default 255)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[HSBK]
|
List of HSBK colors, one per zone |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If zone indices are invalid |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/multizone.py
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 | |
get_all_color_zones
async
¶
Get colors for all zones, automatically using the best method.
This method automatically chooses between get_extended_color_zones() and get_color_zones() based on device capabilities. Always returns all zones on the device.
Always fetches from device.
| RETURNS | DESCRIPTION |
|---|---|
list[HSBK]
|
List of HSBK colors for all zones |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
Example
Source code in src/lifx/devices/multizone.py
set_color_zones
async
¶
set_color_zones(
start: int,
end: int,
color: HSBK,
duration: float = 0.0,
apply: MultiZoneApplicationRequest = APPLY,
) -> None
Set color for a range of zones.
| PARAMETER | DESCRIPTION |
|---|---|
start
|
Start zone index (inclusive)
TYPE:
|
end
|
End zone index (inclusive)
TYPE:
|
color
|
HSBK color to set
TYPE:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
apply
|
Application mode (default APPLY) - NO_APPLY: Don't apply immediately (use for batching) - APPLY: Apply this change and any pending changes - APPLY_ONLY: Apply only this change
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If zone indices are invalid |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
# Set zones 0-9 to red
await light.set_color_zones(0, 9, HSBK.from_rgb(1.0, 0.0, 0.0))
# Set with transition
await light.set_color_zones(
0, 9, HSBK.from_rgb(0.0, 1.0, 0.0), duration=2.0
)
# Batch updates
await light.set_color_zones(
0, 4, color1, apply=MultiZoneApplicationRequest.NO_APPLY
)
await light.set_color_zones(
5, 9, color2, apply=MultiZoneApplicationRequest.APPLY
)
Source code in src/lifx/devices/multizone.py
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 | |
set_extended_color_zones
async
¶
set_extended_color_zones(
zone_index: int,
colors: list[HSBK],
duration: float = 0.0,
apply: MultiZoneApplicationRequest = APPLY,
*,
fast: bool = False,
) -> None
Set colors for multiple zones efficiently (up to 82 zones per call).
This is more efficient than set_color_zones when setting different colors for many zones at once.
| PARAMETER | DESCRIPTION |
|---|---|
zone_index
|
Starting zone index
TYPE:
|
colors
|
List of HSBK colors to set (max 82) |
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
apply
|
Application mode (default APPLY)
TYPE:
|
fast
|
If True, send fire-and-forget without waiting for response. Use for high-frequency animations (>20 updates/second).
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If colors list is too long or zone index is invalid |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond (only when fast=False) |
LifxUnsupportedCommandError
|
If device doesn't support this command (only when fast=False) |
Example
# Create a rainbow effect across zones
colors = [
HSBK(hue=i * 36, saturation=1.0, brightness=1.0, kelvin=3500)
for i in range(10)
]
await light.set_extended_color_zones(0, colors)
# High-speed animation loop
for frame in animation_frames:
await light.set_extended_color_zones(0, frame, fast=True)
await asyncio.sleep(0.033) # ~30 FPS
Source code in src/lifx/devices/multizone.py
827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 | |
get_effect
async
¶
get_effect() -> MultiZoneEffect
Get current multizone effect.
Always fetches from device.
Use the multizone_effect property to access stored value.
| RETURNS | DESCRIPTION |
|---|---|
MultiZoneEffect
|
MultiZoneEffect with either FirmwareEffect.OFF or FirmwareEffect.MOVE |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxProtocolError
|
If response is invalid |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/multizone.py
934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 | |
set_effect
async
¶
set_effect(effect: MultiZoneEffect) -> None
Set multizone effect.
| PARAMETER | DESCRIPTION |
|---|---|
effect
|
MultiZone effect configuration
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
from lifx.protocol.protocol_types import Direction, FirmwareEffect
# Apply a move effect moving forward
effect = MultiZoneEffect(
effect_type=FirmwareEffect.MOVE,
speed=5000, # 5 seconds per cycle
duration=0, # Infinite
)
effect.direction = Direction.FORWARD
await light.set_effect(effect)
# Or use parameters directly
effect = MultiZoneEffect(
effect_type=FirmwareEffect.MOVE,
speed=5000,
parameters=[0, int(Direction.REVERSED), 0, 0, 0, 0, 0, 0],
)
await light.set_effect(effect)
Source code in src/lifx/devices/multizone.py
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 | |
set_move_effect
async
¶
set_move_effect(
direction: Direction | str,
speed: float,
duration: float = 0,
palette: list[HSBK] | None = None,
) -> None
Start the firmware Move effect in one call.
Move rotates the colours already on the strip; it carries no palette
of its own on the wire. With no palette, the strip's colours are read
first and left as they are when they differ. When every zone shows
one colour a three-colour palette is generated (following the LIFX
app) and passed to :meth:apply_theme, which shuffles the palette
and blends between its colours across the zones, so the strip shows
a blend of the palette rather than each colour in order. An explicit
palette is passed to :meth:apply_theme unchanged, without first
reading the strip's colours through :meth:get_all_color_zones. The
raw set_effect(MultiZoneEffect) path never paints.
| PARAMETER | DESCRIPTION |
|---|---|
direction
|
A |
speed
|
Number of seconds per full cycle.
TYPE:
|
duration
|
Number of seconds the effect runs for;
TYPE:
|
palette
|
Up to 16 colours to paint before Move starts. |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If direction, speed, duration or an explicit palette is invalid. |
TypeError
|
If speed or duration is a non-numeric value. |
LifxUnsupportedCommandError
|
If device doesn't support this command |
LifxTimeoutError
|
If device does not respond |
LifxDeviceNotFoundError
|
If device is not connected |
Source code in src/lifx/devices/multizone.py
set_all_color_zones
async
¶
set_all_color_zones(
colors: list[HSBK],
start: int = 0,
end: int | None = None,
duration: float = 0.0,
apply: MultiZoneApplicationRequest = APPLY,
) -> None
Set zone colors from a full-length color list.
Automatically chooses between SetExtendedColorZones and SetColorZones
based on device capabilities, the counterpart to
:meth:get_all_color_zones.
colors is indexed by absolute zone number, so colors[i] is the
color for zone i. start and end select which zones are
actually written; zones outside that window are never addressed and
keep whatever they were showing. This makes read-modify-write natural:
fetch every zone, change the ones you care about, and write back only
those.
Extended writes are chunked at 82 colors per packet; legacy writes are run-length encoded into ranges, so a flat color costs one packet but a gradient costs one packet per zone. Either way every packet but the last is sent with NO_APPLY, so the device buffers the whole update and applies it in a single step.
| PARAMETER | DESCRIPTION |
|---|---|
colors
|
One color per zone, indexed by zone number |
start
|
First zone to write (inclusive, default 0)
TYPE:
|
end
|
Last zone to write (inclusive, defaults to the last color)
TYPE:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
apply
|
Application mode for the final packet (default APPLY). Pass NO_APPLY to buffer this write and apply it with a later call. APPLY_ONLY is rejected: it tells the device to discard the colors carried by the message and flush only what is already buffered, which would silently drop part of this write.
TYPE:
|
The window is checked against the zone count only when that count is
already cached; it is never fetched just to validate. A device that
went through connect() or the async context manager always has it,
so the unchecked case is a hand-constructed light whose first zone
operation is a write — there the device itself ignores zones it does
not have.
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If colors is empty, the window is invalid or falls outside the list, the window exceeds the cached zone count, or apply is APPLY_ONLY |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/multizone.py
1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 | |
apply_theme
async
¶
apply_theme(
theme: Theme,
power_on: bool = False,
duration: float = 0,
strategy: str | None = None,
) -> None
Apply a theme across zones.
Distributes theme colors evenly across the light's zones with smooth color blending between theme colors.
| PARAMETER | DESCRIPTION |
|---|---|
theme
|
Theme to apply
TYPE:
|
power_on
|
Turn on the light
TYPE:
|
duration
|
Transition duration in seconds
TYPE:
|
strategy
|
Color distribution strategy (not used yet, for future)
TYPE:
|
Example
Source code in src/lifx/devices/multizone.py
animate_mood
async
¶
animate_mood(theme: Theme) -> None
Paint the mood, then run firmware MOVE at the app's speed.
Every multizone light runs MOVE for any mood: strips have no MORPH.
Source code in src/lifx/devices/multizone.py
refresh_state
async
¶
Refresh multizone light state from hardware.
Fetches color, zones, and effect.
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
If device does not respond |
LifxDeviceNotFoundError
|
If device cannot be reached |
Source code in src/lifx/devices/multizone.py
MultiZoneLightState¶
MultiZone light device state dataclass returned by MultiZoneLight.state.
MultiZoneLightState
dataclass
¶
MultiZoneLightState(
model: str,
label: str,
serial: str,
mac_address: str,
capabilities: DeviceCapabilities,
power: int,
host_firmware: FirmwareInfo,
wifi_firmware: FirmwareInfo,
location: CollectionInfo,
group: CollectionInfo,
last_updated: float,
color: HSBK,
zones: list[HSBK],
zone_count: int,
effect: FirmwareEffect,
*,
wifi_info: WifiInfo = (lambda: WifiInfo(signal=None, host_firmware=None))(),
thread_info: ThreadInfo | None = None,
ambient_light: float | None = None,
)
Bases: LightState
MultiZone light device state with zone-based control.
| ATTRIBUTE | DESCRIPTION |
|---|---|
zones |
List of HSBK colors for each zone |
zone_count |
Total number of zones
TYPE:
|
effect |
Current multizone effect configuration
TYPE:
|
| METHOD | DESCRIPTION |
|---|---|
from_light_state |
Create MatrixLightState from LightState. |
Attributes¶
Methods:¶
from_light_state
classmethod
¶
from_light_state(
light_state: LightState, zones: list[HSBK], effect: FirmwareEffect
) -> MultiZoneLightState
Create MatrixLightState from LightState.
Source code in src/lifx/devices/multizone.py
MultiZoneEffect¶
Configuration dataclass for multizone effects (MOVE). Used with MultiZoneLight.set_effect() and returned by MultiZoneLight.get_effect(). MultiZoneEffect.move() builds a Move effect from typed arguments, and MultiZoneLight.set_move_effect() builds and sends one in a single call.
MultiZoneEffect
dataclass
¶
MultiZoneEffect(
effect_type: FirmwareEffect,
speed: int,
duration: int = 0,
parameters: list[int] | None = None,
)
MultiZone effect configuration.
| ATTRIBUTE | DESCRIPTION |
|---|---|
effect_type |
Type of effect (OFF, MOVE). A device can report a value
outside these, which reads back as an
TYPE:
|
speed |
Effect speed in milliseconds
TYPE:
|
duration |
Total effect duration (0 for infinite)
TYPE:
|
parameters |
Effect-specific parameters (8 uint32 values) |
Use :meth:move to build a Move effect from a direction and float
seconds. The raw constructor and its parameters list are unchanged
for callers who already encode them directly (for example, Home
Assistant).
| METHOD | DESCRIPTION |
|---|---|
move |
Build a Move effect from a direction and float seconds. |
Attributes¶
direction
property
writable
¶
direction: Direction | None
Get direction for MOVE effect.
| RETURNS | DESCRIPTION |
|---|---|
Direction | None
|
Direction enum value if effect is MOVE, None otherwise |
Methods:¶
move
classmethod
¶
move(
direction: Direction | str, speed: float, duration: float = 0
) -> MultiZoneEffect
Build a Move effect from a direction and float seconds.
| PARAMETER | DESCRIPTION |
|---|---|
direction
|
A |
speed
|
Number of seconds per full cycle, rounded to the nearest whole millisecond.
TYPE:
|
duration
|
Number of seconds the effect runs for;
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
MultiZoneEffect
|
A |
MultiZoneEffect
|
|
MultiZoneEffect
|
encoded internally. |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If direction is not a |
TypeError
|
If speed or duration is a |
Example
Source code in src/lifx/devices/multizone.py
Matrix Light¶
The MatrixLight class controls LIFX matrix devices (tiles, candle, path) with 2D zone control.
MatrixLight
¶
MatrixLight(
serial: str,
ip: str,
port: int = LIFX_UDP_PORT,
timeout: float = DEFAULT_REQUEST_TIMEOUT,
max_retries: int | None = DEFAULT_MAX_RETRIES,
*,
fetch_wifi_info: bool = False,
fetch_thread_info: bool = False,
fetch_radio_info: bool = False,
fetch_ambient_light: bool = False,
)
Bases: Light
LIFX Matrix Light Device.
MatrixLight devices have 2D arrays of controllable color zones arranged in tiles. Most MatrixLight devices (LIFX Candle, LIFX Path) have a single tile. The discontinued LIFX Tile product supported up to 5 tiles in a chain (has_chain).
Zone Addressing:
- Colors are applied row-by-row starting at top-left (0,0)
- For tiles ≤64 zones: Single set64() call to frame buffer 0
-
For tiles >64 zones (e.g., 16x8 = 128 zones):
-
First set64(): rect=(0,0), 64 colors, frame buffer 1
- Second set64(): rect=(0,4), 64 colors, frame buffer 1
- copy_frame_buffer(): Copy buffer 1 → buffer 0
Example
async with await Device.connect("192.168.1.100") as matrix: ... assert isinstance(matrix, MatrixLight) ... # Get device chain info ... chain = await matrix.get_device_chain() ... print(f"Device has {len(chain)} tile(s)") ... ... # Set colors on first tile (8x8 = 64 zones) ... colors = [HSBK.from_rgb(1.0, 0.0, 0.0)] * 64 ... await matrix.set64(tile_index=0, colors=colors, width=8)
See :class:~lifx.devices.base.Device for parameter documentation. The
signature is spelled out rather than forwarded as *args, **kwargs so
callers get the same type checking the base class offers.
| METHOD | DESCRIPTION |
|---|---|
get_device_chain |
Get device chain details (list of Tile objects). |
set_user_position |
Position tiles in the chain (only for devices with has_chain capability). |
get64 |
Get up to 64 zones of color state from a tile. |
get_all_tile_colors |
Get colors for all tiles in the chain. |
set64 |
Set up to 64 zones of color on a tile. |
copy_frame_buffer |
Copy frame buffer (for tiles with >64 zones). |
set_matrix_colors |
Convenience method to set all colors on a tile. |
get_effect |
Get current running matrix effect. |
supports_sky_effect |
Check whether this device can run the SKY firmware effect. |
set_effect |
Set matrix effect with configuration. |
apply_theme |
Apply a theme across matrix tiles using Canvas interpolation. |
animate_mood |
Run firmware MORPH, or paint and scroll a MOVE mood. |
refresh_state |
Refresh matrix light state from hardware. |
| ATTRIBUTE | DESCRIPTION |
|---|---|
state |
Get matrix light state (guaranteed when using Device.connect()).
TYPE:
|
device_chain |
Get cached device chain. |
tile_count |
Get number of tiles in the chain.
TYPE:
|
tile_effect |
Get cached tile effect.
TYPE:
|
Source code in src/lifx/devices/matrix.py
Attributes¶
state
property
¶
state: MatrixLightState
Get matrix light state (guaranteed when using Device.connect()).
| RETURNS | DESCRIPTION |
|---|---|
MatrixLightState
|
MatrixLightState with current matrix light state |
| RAISES | DESCRIPTION |
|---|---|
RuntimeError
|
If accessed before state initialization |
device_chain
property
¶
Get cached device chain.
Returns None if not yet fetched. Use get_device_chain() to fetch.
tile_count
property
¶
tile_count: int | None
Get number of tiles in the chain.
Returns None if device chain not yet fetched.
tile_effect
property
¶
tile_effect: MatrixEffect | None
Get cached tile effect.
Returns None if not yet fetched. Use get_tile_effect() to fetch.
Methods:¶
get_device_chain
async
¶
Get device chain details (list of Tile objects).
This method fetches the device chain information and caches it.
| RETURNS | DESCRIPTION |
|---|---|
list[TileInfo]
|
List of TileInfo objects describing each tile in the chain |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
chain = await matrix.get_device_chain() for tile in chain: ... print(f"Tile {tile.tile_index}: {tile.width}x{tile.height}")
Source code in src/lifx/devices/matrix.py
set_user_position
async
¶
Position tiles in the chain (only for devices with has_chain capability).
Positions are in tile-position units, not pixels: 1.0 is always 8
pixels, regardless of this tile's own width or height. user_x grows
to the right and user_y grows upwards. To move a tile a given
number of pixels, divide by 8 — moving one 8x8 tile's width to the right
is user_x += 1.0, and a 5x6 Candle's width is user_x += 5 / 8.
| PARAMETER | DESCRIPTION |
|---|---|
tile_index
|
Index of the tile to position (0-based)
TYPE:
|
user_x
|
Horizontal position in tile-position units (1.0 = 8 pixels, growing right)
TYPE:
|
user_y
|
Vertical position in tile-position units (1.0 = 8 pixels, growing up)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
If the device never acknowledges the write |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Note
Only applicable for multi-tile devices (has_chain capability). Most MatrixLight devices have a single tile and don't need positioning.
Example
Place the second tile one 8-pixel tile-width to the right¶
await matrix.set_user_position(tile_index=1, user_x=1.0, user_y=0.0)
Source code in src/lifx/devices/matrix.py
get64
async
¶
get64(
tile_index: int = 0,
length: int = 1,
x: int = 0,
y: int = 0,
width: int | None = None,
) -> list[HSBK]
Get up to 64 zones of color state from a tile.
For devices with ≤64 zones, returns all zones. For devices with >64 zones, returns up to 64 zones due to protocol limitations.
| PARAMETER | DESCRIPTION |
|---|---|
tile_index
|
Index of the tile (0-based). Defaults to 0.
TYPE:
|
length
|
Number of tiles to query (usually 1). Defaults to 1.
TYPE:
|
x
|
X coordinate of the rectangle (0-based). Defaults to 0.
TYPE:
|
y
|
Y coordinate of the rectangle (0-based). Defaults to 0.
TYPE:
|
width
|
Width of the rectangle in zones. Defaults to tile width.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[HSBK]
|
List of HSBK colors for the requested zones. For tiles with ≤64 zones, |
list[HSBK]
|
returns the actual zone count (e.g., 64 for 8x8, 16 for 4x4). For tiles |
list[HSBK]
|
with >64 zones (e.g., 128 for 16x8 Ceiling), returns 64 (protocol limit). |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Get all colors from first tile (no parameters needed)¶
colors = await matrix.get64()
Get colors from specific region¶
colors = await matrix.get64(y=4) # Start at row 4
Source code in src/lifx/devices/matrix.py
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 | |
get_all_tile_colors
async
¶
Get colors for all tiles in the chain.
Fetches colors from each tile in the device chain and returns them as a list of color lists (one per tile). This is the matrix equivalent of MultiZoneLight's get_all_color_zones().
A chain of uniform tiles of 64 zones or fewer is read with a single
Get64 carrying length equal to the chain length, which the device
answers with one State64 per tile — one round trip instead of one per
tile. Everything else (single-tile devices, and tiles over 64 zones such
as a 16x8 Ceiling) is queried a tile at a time, sequentially, to avoid
overwhelming the device with concurrent requests.
Always fetches from device.
| RETURNS | DESCRIPTION |
|---|---|
list[list[HSBK]]
|
List of color lists, one per tile. Each inner list contains |
list[list[HSBK]]
|
all colors for that tile (64 for 8x8 tiles, 128 for 16x8 Ceiling). |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
# Get colors for all tiles
all_colors = await matrix.get_all_tile_colors()
print(f"Device has {len(all_colors)} tiles")
for i, tile_colors in enumerate(all_colors):
print(f"Tile {i}: {len(tile_colors)} colors")
# Flatten to single list if needed
flat_colors = [c for tile in all_colors for c in tile]
Source code in src/lifx/devices/matrix.py
set64
async
¶
set64(
tile_index: int,
length: int,
x: int,
y: int,
width: int,
duration: int,
colors: list[HSBK],
fb_index: int = 0,
) -> None
Set up to 64 zones of color on a tile.
Colors are applied row-by-row starting at position (x, y). For tiles >64 zones, use multiple set64() calls with copy_frame_buffer().
| PARAMETER | DESCRIPTION |
|---|---|
tile_index
|
Index of the tile (0-based)
TYPE:
|
length
|
Number of tiles to update (usually 1)
TYPE:
|
x
|
X coordinate of the rectangle (0-based)
TYPE:
|
y
|
Y coordinate of the rectangle (0-based)
TYPE:
|
width
|
Width of the rectangle in zones
TYPE:
|
duration
|
Transition duration in milliseconds
TYPE:
|
colors
|
List of HSBK colors (up to 64) |
fb_index
|
Frame buffer index (0 for display, 1 for temp buffer)
TYPE:
|
The write waits for the device's acknowledgement and is retransmitted if the device drops it, so the next write cannot overtake it. Use the Animation layer for streaming frames.
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
If the device never acknowledges the write |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Set 8x8 tile to red¶
colors = [HSBK.from_rgb(1.0, 0.0, 0.0)] * 64 await matrix.set64( ... tile_index=0, length=1, x=0, y=0, width=8, duration=0, colors=colors ... )
Source code in src/lifx/devices/matrix.py
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 | |
copy_frame_buffer
async
¶
copy_frame_buffer(
tile_index: int,
source_fb: int = 1,
target_fb: int = 0,
duration: float = 0.0,
length: int = 1,
) -> None
Copy frame buffer (for tiles with >64 zones).
This is used for tiles with more than 64 zones. After setting colors in the temporary buffer (fb=1), copy to the display buffer (fb=0).
| PARAMETER | DESCRIPTION |
|---|---|
tile_index
|
Index of the tile (0-based)
TYPE:
|
source_fb
|
Source frame buffer index (usually 1)
TYPE:
|
target_fb
|
Target frame buffer index (usually 0)
TYPE:
|
duration
|
time in seconds to transition if target_fb is 0
TYPE:
|
length
|
Number of tiles to update starting from tile_index (default 1)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If tile_index is not in the device chain |
LifxTimeoutError
|
If the device never acknowledges the copy |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
For 16x8 tile (128 zones):¶
1. Set first 64 zones to buffer 1¶
await matrix.set64( ... tile_index=0, ... length=1, ... x=0, ... y=0, ... width=16, ... duration=0, ... colors=colors[:64], ... fb_index=1, ... )
2. Set second 64 zones to buffer 1¶
await matrix.set64( ... tile_index=0, ... length=1, ... x=0, ... y=4, ... width=16, ... duration=0, ... colors=colors[64:], ... fb_index=1, ... )
3. Copy buffer 1 to buffer 0 (display)¶
await matrix.copy_frame_buffer( ... tile_index=0, source_fb=1, target_fb=0, duration=2.0 ... )
For a chain of 5 tiles, update all simultaneously:¶
await matrix.copy_frame_buffer( ... tile_index=0, source_fb=1, target_fb=0, length=5 ... )
Source code in src/lifx/devices/matrix.py
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 | |
set_matrix_colors
async
¶
Convenience method to set all colors on a tile.
If all colors are the same, uses SetColor() packet which sets all zones across all tiles. Otherwise, automatically handles tiles with >64 zones using frame buffer strategy.
| PARAMETER | DESCRIPTION |
|---|---|
tile_index
|
Index of the tile (0-based)
TYPE:
|
colors
|
List of HSBK colors (length must match tile total_zones) |
duration
|
Transition duration in milliseconds
TYPE:
|
Example
Set entire tile to solid red (uses SetColor packet)¶
colors = [HSBK.from_rgb(1.0, 0.0, 0.0)] * 64 await matrix.set_matrix_colors(tile_index=0, colors=colors)
Set 8x8 tile to gradient (uses set64 with zones)¶
colors = [HSBK(i * 360 / 64, 1.0, 1.0, 3500) for i in range(64)] await matrix.set_matrix_colors(tile_index=0, colors=colors)
Source code in src/lifx/devices/matrix.py
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 | |
get_effect
async
¶
get_effect() -> MatrixEffect
Get current running matrix effect.
The reported duration counts down while the effect runs, so it is the time remaining rather than the duration the effect was started with.
| RETURNS | DESCRIPTION |
|---|---|
MatrixEffect
|
MatrixEffect describing the current effect state |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
effect = await matrix.get_effect() print(f"Effect type: {effect.effect_type}")
Source code in src/lifx/devices/matrix.py
supports_sky_effect
async
¶
supports_sky_effect() -> bool
Check whether this device can run the SKY firmware effect.
SKY requires both the matrix capability and a host firmware major
version of at least SKY_EFFECT_MIN_FIRMWARE_MAJOR: matrix devices on
earlier firmware reject or ignore it. See lifx.products.quirks for
the products this has been confirmed on.
Products missing from the bundled registry snapshot have no known capabilities, so they are reported as unsupported.
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if the device has matrix capability and its host firmware |
bool
|
supports the SKY effect |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
Source code in src/lifx/devices/matrix.py
set_effect
async
¶
set_effect(
effect_type: FirmwareEffect,
speed: float = 3.0,
duration: int = 0,
palette: list[HSBK] | None = None,
sky_type: TileEffectSkyType = SUNRISE,
cloud_saturation_min: int = 0,
cloud_saturation_max: int = 0,
) -> None
Set matrix effect with configuration.
| PARAMETER | DESCRIPTION |
|---|---|
effect_type
|
Type of effect (OFF, MORPH, FLAME, SKY, COLOR_SWEEP)
TYPE:
|
speed
|
Effect speed in seconds (default: 3), rounded to the
nearest millisecond. For SKY sunrise and sunset, it sets how
long the transition takes. 0 means the 3 second default,
except for COLOR_SWEEP and SKY with a non-zero
TYPE:
|
duration
|
Total effect duration in nanoseconds (0 for infinite)
TYPE:
|
palette
|
Colour palette for the effect. For MORPH, a palette longer
than 16 colours is reduced the way the LIFX app reduces a mood:
by the area each run of colours covers, then shuffled. Other
effects take at most 16. An explicit palette is sent as given (bar
that MORPH reduction), with no extra read.
|
sky_type
|
Sky effect type (SUNRISE, SUNSET, CLOUDS)
TYPE:
|
cloud_saturation_min
|
Minimum cloud saturation (0-255, for CLOUDS)
TYPE:
|
cloud_saturation_max
|
Maximum cloud saturation (0-255, for CLOUDS)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
LifxUnsupportedCommandError
|
If SKY is requested on a device that is known not to support it, either because it lacks the matrix capability or because its host firmware is too old |
LifxTimeoutError
|
If MORPH is requested with no palette and the colour read times out |
LifxProtocolError
|
If MORPH is requested with no palette and the colour read gets a malformed reply, or the device reports no colours |
ValueError
|
If speed is negative (checked before rounding), or a
non-zero speed rounds to 0 ms for an active effect that does
not play once at speed 0, or another field fails
|
Example
Set MORPH effect with rainbow palette¶
rainbow = [ ... HSBK(0, 1.0, 1.0, 3500), # Red ... HSBK(60, 1.0, 1.0, 3500), # Yellow ... HSBK(120, 1.0, 1.0, 3500), # Green ... HSBK(240, 1.0, 1.0, 3500), # Blue ... ] await matrix.set_effect( ... effect_type=FirmwareEffect.MORPH, ... speed=5.0, ... palette=rainbow, ... )
Set effect without a palette¶
await matrix.set_effect( ... effect_type=FirmwareEffect.FLAME, ... speed=3.0, ... )
Source code in src/lifx/devices/matrix.py
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 | |
apply_theme
async
¶
Apply a theme across matrix tiles using Canvas interpolation.
Distributes theme colors across the tile matrix with smooth color blending using the Canvas API for visually pleasing transitions.
Every device is rendered at its own reported pixel geometry, so non-8x8 products (Candle 5x6, Ceiling 16x8) get the right number of colours.
Position and orientation are used only on a chain-capable device: the
LIFX Tile, the only product that is arranged into a layout and the only
one whose reported orientation is applied. There, each tile is placed
on the canvas with :func:lifx.geometry.tile_origin_pixels so it gets
a distinct slice of the theme, and a physically rotated panel is
remapped to match. Every other matrix device is a single fixed panel
whose accelerometer readings are not used, so it renders at the canvas
origin and is never remapped.
| PARAMETER | DESCRIPTION |
|---|---|
theme
|
Theme to apply
TYPE:
|
power_on
|
Turn on the light
TYPE:
|
duration
|
Transition duration in seconds
TYPE:
|
Example
Source code in src/lifx/devices/matrix.py
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 | |
animate_mood
async
¶
animate_mood(theme: Theme) -> None
Run firmware MORPH, or paint and scroll a MOVE mood.
The prior state is captured before anything is painted, and handed to the scroll, so its tiles are never read back mid-fade.
Source code in src/lifx/devices/matrix.py
refresh_state
async
¶
Refresh matrix light state from hardware.
Fetches color, tiles, tile colors for all tiles, and effect.
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
If device does not respond |
LifxDeviceNotFoundError
|
If device cannot be reached |
Source code in src/lifx/devices/matrix.py
MatrixLightState¶
Matrix light device state dataclass returned by MatrixLight.state.
MatrixLightState
dataclass
¶
MatrixLightState(
model: str,
label: str,
serial: str,
mac_address: str,
capabilities: DeviceCapabilities,
power: int,
host_firmware: FirmwareInfo,
wifi_firmware: FirmwareInfo,
location: CollectionInfo,
group: CollectionInfo,
last_updated: float,
color: HSBK,
chain: list[TileInfo],
tile_orientations: dict[int, str],
tile_colors: list[HSBK],
tile_count: int,
effect: FirmwareEffect,
*,
wifi_info: WifiInfo = (lambda: WifiInfo(signal=None, host_firmware=None))(),
thread_info: ThreadInfo | None = None,
ambient_light: float | None = None,
)
Bases: LightState
Matrix light device state with tile-based control.
| ATTRIBUTE | DESCRIPTION |
|---|---|
tiles |
List of tile information for each tile in the chain
|
tile_colors |
List of HSBK colors for all pixels across all tiles |
tile_count |
Total number of tiles in chain
TYPE:
|
effect |
Current matrix effect configuration
TYPE:
|
| METHOD | DESCRIPTION |
|---|---|
from_light_state |
Create MatrixLightState from LightState. |
Attributes¶
as_dict
property
¶
as_dict: Any
Return MatrixLightState as dict.
tile_orientations is keyed by tile index. JSON object keys are
always strings, so the keys are stringified here rather than letting
json.dumps coerce them and break lookups after a round trip.
Methods:¶
from_light_state
classmethod
¶
from_light_state(
light_state: LightState,
chain: list[TileInfo],
tile_orientations: dict[int, str],
tile_colors: list[HSBK],
effect: FirmwareEffect,
) -> MatrixLightState
Create MatrixLightState from LightState.
Source code in src/lifx/devices/matrix.py
TileInfo¶
Information dataclass for a single tile in the device chain. Returned as part of MatrixLightState.chain.
TileInfo
dataclass
¶
TileInfo(
tile_index: int,
accel_meas_x: int,
accel_meas_y: int,
accel_meas_z: int,
user_x: float,
user_y: float,
width: int,
height: int,
supported_frame_buffers: int,
device_version_vendor: int,
device_version_product: int,
device_version_version: int,
firmware_build: int,
firmware_version_minor: int,
firmware_version_major: int,
)
Information about a single tile in the device chain.
| ATTRIBUTE | DESCRIPTION |
|---|---|
tile_index |
Index of this tile in the chain (0-based)
TYPE:
|
accel_meas_x |
Accelerometer measurement X
TYPE:
|
accel_meas_y |
Accelerometer measurement Y
TYPE:
|
accel_meas_z |
Accelerometer measurement Z
TYPE:
|
user_x |
User-defined X position
TYPE:
|
user_y |
User-defined Y position
TYPE:
|
width |
Tile width in zones
TYPE:
|
height |
Tile height in zones
TYPE:
|
supported_frame_buffers |
frame buffer count
TYPE:
|
device_version_vendor |
Device vendor ID
TYPE:
|
device_version_product |
Device product ID
TYPE:
|
device_version_version |
Device version
TYPE:
|
firmware_build |
Firmware build timestamp
TYPE:
|
firmware_version_minor |
Firmware minor version
TYPE:
|
firmware_version_major |
Firmware major version
TYPE:
|
| METHOD | DESCRIPTION |
|---|---|
from_protocol |
Create TileInfo from protocol TileStateDevice. |
Attributes¶
requires_frame_buffer
property
¶
requires_frame_buffer: bool
Check if tile has more than 64 zones (requires frame buffer strategy).
nearest_orientation
property
¶
nearest_orientation: str
Determine the orientation of the tile from accelerometer data.
Methods:¶
from_protocol
classmethod
¶
Create TileInfo from protocol TileStateDevice.
| PARAMETER | DESCRIPTION |
|---|---|
tile_index
|
Index of this tile in the chain (0-based)
TYPE:
|
protocol_tile
|
Protocol TileStateDevice object
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
TileInfo
|
TileInfo instance |
Source code in src/lifx/devices/matrix.py
MatrixEffect¶
Configuration dataclass for firmware effects (MORPH, FLAME, SKY, COLOR_SWEEP). Used with MatrixLight.set_effect() and returned by MatrixLight.get_effect().
SKY requires the matrix capability plus host firmware 4.x or later — confirmed on Ceiling, Luna, Tube, Path and the E26 Candle. Check with await matrix.supports_sky_effect(); set_effect() raises LifxUnsupportedCommandError when either requirement is unmet.
MORPH started with no palette builds one from the device's own colours, because the firmware does not start MORPH with an empty palette. set_effect() first reads the tiles with get_all_tile_colors(). A device showing one colour gets a generated three-colour palette, and a device showing several gets those colours (all of them in the order first seen when there are 16 or fewer, otherwise 16 pixels sampled evenly across the device). If that read times out, set_effect() raises LifxTimeoutError; if the reply is malformed, or the device reports no tile colours at all, it raises LifxProtocolError naming the device. Either way it sends nothing. Pass palette= to choose the colours yourself. FLAME and SKY with no palette send none and read nothing. COLOR_SWEEP runs on the Mirror only: with no palette it sweeps through colour temperatures, and with a palette it sweeps through the palette colours instead.
speed is in seconds. For a SKY sunrise or sunset it sets how long the transition takes. A speed of 0 normally means the 3 second default. COLOR_SWEEP and SKY with a non-zero duration are the exception: speed 0 plays the effect once across duration. With no duration, speed 0 keeps the 3 second default for both, because a Mirror given COLOR_SWEEP at speed 0 with no duration repeats the sweep every second or two.
from lifx import FirmwareEffect, TileEffectSkyType
# Play a sunset once over 10 minutes
await matrix.set_effect(
FirmwareEffect.SKY,
speed=0,
duration=600_000_000_000, # nanoseconds
sky_type=TileEffectSkyType.SUNSET,
)
MatrixEffect
dataclass
¶
MatrixEffect(
effect_type: FirmwareEffect,
speed: int,
duration: int = 0,
palette: list[HSBK] | None = None,
sky_type: TileEffectSkyType = SUNRISE,
cloud_saturation_min: int = 0,
cloud_saturation_max: int = 0,
from_device: InitVar[bool] = False,
)
Matrix effect configuration.
| ATTRIBUTE | DESCRIPTION |
|---|---|
effect_type |
Type of effect (OFF, MORPH, FLAME, SKY, COLOR_SWEEP). A
device can report a value outside these, which reads back as an
TYPE:
|
speed |
Effect speed in milliseconds. Must be positive for an active
effect, except COLOR_SWEEP and SKY with a non-zero
TYPE:
|
duration |
Effect duration in nanoseconds (0 for infinite). A value read back from a device is the time remaining, not the total
TYPE:
|
palette |
Color palette for the effect (max 16 colors) |
sky_type |
Sky effect type (SUNRISE, SUNSET, CLOUDS). A device can
report a value outside these, which reads back as an
TYPE:
|
cloud_saturation_min |
Minimum cloud saturation (0-255, for CLOUDS sky type)
TYPE:
|
cloud_saturation_max |
Maximum cloud saturation (0-255, for CLOUDS sky type)
TYPE:
|
from_device |
Set when building this object from a device response. The validation and default-filling below are rules for values the caller is about to send: applying them to values the firmware reported would reject legitimate device state, or silently rewrite it to something the device never reported.
TYPE:
|
Ceiling Light¶
The CeilingLight class extends MatrixLight with independent control over uplight and downlight components for LIFX Ceiling fixtures.
CeilingLight
¶
CeilingLight(
serial: str,
ip: str,
port: int = LIFX_UDP_PORT,
timeout: float = DEFAULT_REQUEST_TIMEOUT,
max_retries: int | None = DEFAULT_MAX_RETRIES,
state_file: str | None = None,
*,
fetch_wifi_info: bool = False,
fetch_thread_info: bool = False,
fetch_radio_info: bool = False,
fetch_ambient_light: bool = False,
)
Bases: ComponentMatrixLight
LIFX Ceiling Light with independent uplight and downlight control.
CeilingLight extends MatrixLight to provide semantic control over uplight and downlight components while maintaining full backward compatibility with the MatrixLight API.
The uplight component is the last zone in the matrix, and the downlight component consists of all other zones.
Example
from lifx.devices import CeilingLight
from lifx.color import HSBK
async with await Device.connect("192.168.1.100") as ceiling:
assert isinstance(ceiling, CeilingLight)
# Independent component control
await ceiling.set_downlight_colors(HSBK(hue=0, sat=0, bri=1.0, kelvin=3500))
await ceiling.set_uplight_color(HSBK(hue=30, sat=0.2, bri=0.3, kelvin=2700))
# Turn components on/off
await ceiling.turn_downlight_on()
await ceiling.turn_uplight_off()
# Check component state
if ceiling.uplight_is_on:
print("Uplight is on")
state_file keeps its original position: inserting a parameter ahead
of it would silently rebind existing positional callers. New options are
keyword-only for the same reason.
| PARAMETER | DESCRIPTION |
|---|---|
serial
|
Device serial number
TYPE:
|
ip
|
Device IP address
TYPE:
|
port
|
Device UDP port (default: 56700)
TYPE:
|
timeout
|
Overall timeout for network requests in seconds
TYPE:
|
max_retries
|
Maximum number of retry attempts for network requests
TYPE:
|
state_file
|
Optional path to JSON file for state persistence
TYPE:
|
fetch_wifi_info
|
Query WiFi signal strength during state initialization
TYPE:
|
fetch_thread_info
|
Query Thread mesh information during state initialization
TYPE:
|
fetch_radio_info
|
Query whichever radio matches the device's evidenced connectivity during state initialization
TYPE:
|
fetch_ambient_light
|
Query the ambient light sensor during state initialization
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
LifxError
|
If device is not a supported Ceiling product |
| METHOD | DESCRIPTION |
|---|---|
refresh_state |
Refresh ceiling light state from hardware. |
from_ip |
Create CeilingLight from IP address. |
get_uplight_color |
Get current uplight component color from device. |
get_downlight_colors |
Get current downlight component colors from device. |
set_uplight_color |
Set uplight component color. |
set_downlight_colors |
Set downlight component colors. |
turn_uplight_on |
Turn uplight component on. |
turn_uplight_off |
Turn uplight component off. |
turn_downlight_on |
Turn downlight component on. |
set_power |
Set light power state, capturing component colors before turning off. |
set_color |
Set light color, updating component state tracking. |
turn_downlight_off |
Turn downlight component off. |
| ATTRIBUTE | DESCRIPTION |
|---|---|
uplight |
The uplight as an effect participant.
TYPE:
|
downlight |
The downlight as an effect participant.
TYPE:
|
state |
Get Ceiling light state.
TYPE:
|
uplight_zone |
Zone index of the uplight component.
TYPE:
|
downlight_zones |
Slice representing the downlight component zones.
TYPE:
|
downlight_zone_count |
Number of downlight zones.
TYPE:
|
uplight_is_on |
True if uplight component is currently on.
TYPE:
|
downlight_is_on |
True if downlight component is currently on.
TYPE:
|
Source code in src/lifx/devices/ceiling.py
Attributes¶
uplight
property
¶
uplight: LightComponent
The uplight as an effect participant.
It carries start_effect(), stop_effect() and animator. A
software effect started on it draws on a single pixel, while the
downlight keeps its colours and stays under the existing downlight
methods. Reading it changes nothing.
downlight
property
¶
downlight: LightComponent
The downlight as an effect participant.
It carries start_effect(), stop_effect() and animator. A
software effect started on it draws on the full grid, with the uplight
cell dropped, while the uplight keeps its colours and stays under the
existing uplight methods. Reading it changes nothing.
state
property
¶
state: CeilingLightState
Get Ceiling light state.
| RETURNS | DESCRIPTION |
|---|---|
CeilingLightState
|
CeilingLightState with current state information. |
| RAISES | DESCRIPTION |
|---|---|
RuntimeError
|
If accessed before state initialization. |
uplight_is_on
property
¶
uplight_is_on: bool
True if uplight component is currently on.
Calculated as: power_level > 0 AND uplight brightness > 0
Note
Requires recent data from device. Call refresh_state() to update cached values before checking this property.
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if uplight component is on, False otherwise |
downlight_is_on
property
¶
downlight_is_on: bool
True if downlight component is currently on.
Calculated as: power_level > 0 AND NOT all downlight zones have brightness == 0
Note
Requires recent data from device. Call refresh_state() to update cached values before checking this property.
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if downlight component is on, False otherwise |
Methods:¶
refresh_state
async
¶
Refresh ceiling light state from hardware.
Fetches color, tiles, tile colors, effect, and ceiling component state.
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
If device does not respond |
LifxDeviceNotFoundError
|
If device cannot be reached |
Source code in src/lifx/devices/ceiling.py
from_ip
async
classmethod
¶
from_ip(
ip: str,
port: int = LIFX_UDP_PORT,
serial: str | None = None,
timeout: float = DEFAULT_REQUEST_TIMEOUT,
max_retries: int | None = DEFAULT_MAX_RETRIES,
*,
fetch_wifi_info: bool = False,
fetch_thread_info: bool = False,
fetch_radio_info: bool = False,
fetch_ambient_light: bool = False,
state_file: str | None = None,
) -> CeilingLight
Create CeilingLight from IP address.
| PARAMETER | DESCRIPTION |
|---|---|
ip
|
Device IP address
TYPE:
|
port
|
Port number (default LIFX_UDP_PORT)
TYPE:
|
serial
|
Serial number as 12-digit hex string
TYPE:
|
timeout
|
Request timeout for this device instance
TYPE:
|
max_retries
|
Maximum number of retries for requests
TYPE:
|
fetch_wifi_info
|
Query WiFi signal strength during state initialization
TYPE:
|
fetch_thread_info
|
Query Thread mesh information during state initialization
TYPE:
|
fetch_radio_info
|
Query whichever radio matches the device's evidenced connectivity during state initialization
TYPE:
|
fetch_ambient_light
|
Query the ambient light sensor during state initialization
TYPE:
|
state_file
|
Optional path to JSON file for state persistence
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
CeilingLight
|
CeilingLight instance |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
Device not found at IP |
LifxTimeoutError
|
Device did not respond |
LifxError
|
Device is not a supported Ceiling product |
Source code in src/lifx/devices/ceiling.py
get_uplight_color
async
¶
get_uplight_color() -> HSBK
Get current uplight component color from device.
| RETURNS | DESCRIPTION |
|---|---|
HSBK
|
HSBK color of uplight zone |
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
Device did not respond |
Source code in src/lifx/devices/ceiling.py
get_downlight_colors
async
¶
Get current downlight component colors from device.
| RETURNS | DESCRIPTION |
|---|---|
list[HSBK]
|
List of HSBK colors for each downlight zone (63 or 127 zones) |
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
Device did not respond |
Source code in src/lifx/devices/ceiling.py
set_uplight_color
async
¶
Set uplight component color.
| PARAMETER | DESCRIPTION |
|---|---|
color
|
HSBK color to set
TYPE:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If color.brightness == 0 (use turn_uplight_off instead) |
LifxTimeoutError
|
Device did not respond |
Note
Also updates stored state for future restoration.
Source code in src/lifx/devices/ceiling.py
set_downlight_colors
async
¶
Set downlight component colors.
| PARAMETER | DESCRIPTION |
|---|---|
colors
|
Either:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If any color.brightness == 0 (use turn_downlight_off instead) |
ValueError
|
If list length doesn't match downlight zone count |
LifxTimeoutError
|
Device did not respond |
Note
Also updates stored state for future restoration.
Source code in src/lifx/devices/ceiling.py
turn_uplight_on
async
¶
Turn uplight component on.
If the entire light is off, this will set the color instantly and then turn on the light with the specified duration, so the light fades to the target color instead of flashing to its previous state.
| PARAMETER | DESCRIPTION |
|---|---|
color
|
Optional HSBK color, or a list whose first item is used. If provided:
If None or an empty list, uses brightness determination logic |
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If color.brightness == 0 |
LifxTimeoutError
|
Device did not respond |
Source code in src/lifx/devices/ceiling.py
turn_uplight_off
async
¶
Turn uplight component off.
| PARAMETER | DESCRIPTION |
|---|---|
color
|
Optional HSBK color, or a list whose first item is used, to store for future turn_on. If provided, stores this color (with brightness=0 on the device). If None or an empty list, stores current color from device before turning off. |
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If color.brightness == 0 |
LifxTimeoutError
|
Device did not respond |
Note
Sets uplight zone brightness to 0 on device while preserving H, S, K. If the downlight component is already off, the entire device is powered off instead and the uplight zone keeps its brightness, so a later set_power(True) brings the uplight back rather than turning on a light with every zone at zero brightness.
Source code in src/lifx/devices/ceiling.py
turn_downlight_on
async
¶
Turn downlight component on.
If the entire light is off, this will set the colors instantly and then turn on the light with the specified duration, so the light fades to the target colors instead of flashing to its previous state.
| PARAMETER | DESCRIPTION |
|---|---|
colors
|
Optional colors. Can be:
If provided, updates stored state. |
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If any color.brightness == 0 |
ValueError
|
If list length doesn't match downlight zone count |
LifxTimeoutError
|
Device did not respond |
Source code in src/lifx/devices/ceiling.py
set_power
async
¶
Set light power state, capturing component colors before turning off.
Overrides Light.set_power() to capture the current uplight and downlight colors before turning off the entire light. This allows subsequent calls to turn_uplight_on() or turn_downlight_on() to restore the colors that were active just before the light was turned off.
The captured colors preserve hue, saturation, and kelvin values even if a component was already off (brightness=0). The brightness will be determined at turn-on time using the standard brightness inference logic.
| PARAMETER | DESCRIPTION |
|---|---|
level
|
True/65535 to turn on, False/0 to turn off |
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If integer value is not 0 or 65535 |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/ceiling.py
set_color
async
¶
Set light color, updating component state tracking.
Overrides Light.set_color() to track the color change in the ceiling light's component state. When set_color() is called, all zones (uplight and downlight) are set to the same color. This override ensures that the cached component colors stay in sync so that subsequent component control methods (like turn_uplight_on or turn_downlight_on) use the correct color values.
| PARAMETER | DESCRIPTION |
|---|---|
color
|
HSBK color to set for the entire light
TYPE:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
from lifx.color import HSBK
# Set entire ceiling light to warm white
await ceiling.set_color(
HSBK(hue=0, saturation=0, brightness=1.0, kelvin=2700)
)
# Later component control will use this color
await ceiling.turn_uplight_off() # Uplight off
await ceiling.turn_uplight_on() # Restores to warm white
Source code in src/lifx/devices/ceiling.py
turn_downlight_off
async
¶
Turn downlight component off.
| PARAMETER | DESCRIPTION |
|---|---|
colors
|
Optional colors to store for future turn_on. Can be:
If provided, stores these colors (with brightness=0 on device). |
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If any color.brightness == 0 |
ValueError
|
If list length doesn't match downlight zone count |
LifxTimeoutError
|
Device did not respond |
Note
Sets all downlight zone brightness to 0 on device while preserving H, S, K. If the uplight component is already off, the entire device is powered off instead and the downlight zones keep their brightness, so a later set_power(True) brings the downlight back rather than turning on a light with every zone at zero brightness.
Source code in src/lifx/devices/ceiling.py
LightComponent¶
ceiling.uplight, ceiling.downlight, mirror.front and mirror.back return a LightComponent: one light component as an effect participant, carrying only start_effect(), stop_effect() and animator.
LightComponent
¶
One light component of a light, as an effect participant.
Read it from the light, for example ceiling.downlight or
mirror.front. It carries
only effect control: the light component's colours and power stay on the
light's existing methods, such as set_uplight_color().
Example
| PARAMETER | DESCRIPTION |
|---|---|
light
|
The light the light component belongs to
TYPE:
|
name
|
The light component's name, such as
TYPE:
|
| METHOD | DESCRIPTION |
|---|---|
start_effect |
Start a software effect on this light component alone. |
stop_effect |
Stop the software effect on this light component only. |
| ATTRIBUTE | DESCRIPTION |
|---|---|
light |
The light this light component belongs to.
TYPE:
|
name |
The light component's name, such as
TYPE:
|
animator |
The light's one Animator, which this light component draws through.
TYPE:
|
Source code in src/lifx/devices/component/participant.py
Attributes¶
animator
property
¶
animator: Animator
The light's one Animator, which this light component draws through.
A software effect on this light component writes its frames into the light component's slot on the light's Animator, which sends the tile composed from every slot.
Methods:¶
start_effect
async
¶
start_effect(effect: LIFXEffect, *, enable_thread: bool = False) -> None
Start a software effect on this light component alone.
The effect draws on the light component's own shape: a Ceiling
uplight is a single pixel, a Ceiling downlight is the full grid
with the uplight cell dropped, and a Mirror ring is 25 pixels in zone
order that wrap. The other light component keeps its
colours, and its colour and power methods keep working while the
effect runs. On a light that is off, only this light component turns
on and the other stays dark. Calling this light component's own
colour or power methods stops the effect first. A whole-light effect
running on the light moves onto the other light component and carries
on there. On a light evidenced as Thread, by its own replies or an
mDNS record, the effect is refused unless enable_thread is True:
a Thread mesh is not built for a steady stream of frames.
EffectColorloop streams none, so it is never refused.
| PARAMETER | DESCRIPTION |
|---|---|
effect
|
The software effect to run. It must draw frames: an effect such as EffectPulse, which sends waveforms to the whole light, cannot draw on a light component.
TYPE:
|
enable_thread
|
Stream frames to a light evidenced as Thread anyway. Off by default.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
TypeError
|
If |
LifxUnsupportedCommandError
|
If the light is evidenced as Thread
and |
Source code in src/lifx/devices/component/participant.py
stop_effect
async
¶
Stop the software effect on this light component only.
The light component gets its colours from before the effect back, or turns off again if it was dark or its light was off. An effect on the other light component, or on other lights in the same run, carries on. A whole-light effect running on the light moves onto the other light component, and this light component gets its colours from before that effect back.
Source code in src/lifx/devices/component/participant.py
CeilingLightState¶
The CeilingLightState dataclass extends MatrixLightState with ceiling-specific component information. It is returned by CeilingLight.state after connecting to a device.
CeilingLightState
dataclass
¶
CeilingLightState(
model: str,
label: str,
serial: str,
mac_address: str,
capabilities: DeviceCapabilities,
power: int,
host_firmware: FirmwareInfo,
wifi_firmware: FirmwareInfo,
location: CollectionInfo,
group: CollectionInfo,
last_updated: float,
color: HSBK,
chain: list[TileInfo],
tile_orientations: dict[int, str],
tile_colors: list[HSBK],
tile_count: int,
effect: FirmwareEffect,
uplight_color: HSBK,
downlight_colors: list[HSBK],
uplight_is_on: bool,
downlight_is_on: bool,
uplight_zone: int,
downlight_zones: slice,
stored_uplight_color: HSBK | None = None,
stored_downlight_colors: list[HSBK] | None = None,
last_uplight_color: HSBK | None = None,
last_downlight_colors: list[HSBK] | None = None,
*,
wifi_info: WifiInfo = (lambda: WifiInfo(signal=None, host_firmware=None))(),
thread_info: ThreadInfo | None = None,
ambient_light: float | None = None,
)
Bases: MatrixLightState
Ceiling light device state with uplight/downlight component control.
Extends MatrixLightState with ceiling-specific component information.
| ATTRIBUTE | DESCRIPTION |
|---|---|
uplight_color |
Current HSBK color of the uplight component
TYPE:
|
downlight_colors |
List of HSBK colors for each downlight zone |
uplight_is_on |
Whether uplight component is on (brightness > 0)
TYPE:
|
downlight_is_on |
Whether downlight component is on (any zone brightness > 0)
TYPE:
|
uplight_zone |
Zone index for the uplight component
TYPE:
|
downlight_zones |
Slice representing downlight component zones
TYPE:
|
stored_uplight_color |
Stored uplight color for restoration after turning off
TYPE:
|
stored_downlight_colors |
Stored downlight colors for restoration after turning off |
last_uplight_color |
Last known uplight color, updated after every operation
TYPE:
|
last_downlight_colors |
Last known downlight colors, updated after every operation |
| METHOD | DESCRIPTION |
|---|---|
from_matrix_state |
Create CeilingLightState from MatrixLightState. |
Attributes¶
as_dict
property
¶
as_dict: Any
Return CeilingLightState as dict.
downlight_zones is expanded from a :class:slice into a
{"start": ..., "stop": ..., "step": ...} mapping so the result is
serialisable.
Ceiling layouts define the zones as slice(0, N), which leaves
slice.step set to None even though it steps by one, so the step is
normalised to 1 here.
The uplight/downlight colors are expanded via :attr:HSBK.as_dict;
the stored and last-known fields stay None when unset.
Methods:¶
from_matrix_state
classmethod
¶
from_matrix_state(
matrix_state: MatrixLightState,
uplight_color: HSBK,
downlight_colors: list[HSBK],
uplight_zone: int,
downlight_zones: slice,
*,
stored_uplight_color: HSBK | None = None,
stored_downlight_colors: list[HSBK] | None = None,
) -> CeilingLightState
Create CeilingLightState from MatrixLightState.
| PARAMETER | DESCRIPTION |
|---|---|
matrix_state
|
Base MatrixLightState to extend
TYPE:
|
uplight_color
|
Current uplight zone color
TYPE:
|
downlight_colors
|
Current downlight zone colors |
uplight_zone
|
Zone index for uplight component
TYPE:
|
downlight_zones
|
Slice representing downlight component zones
TYPE:
|
stored_uplight_color
|
Stored uplight color for restoration
TYPE:
|
stored_downlight_colors
|
Stored downlight colors for restoration |
| RETURNS | DESCRIPTION |
|---|---|
CeilingLightState
|
CeilingLightState with all matrix state plus ceiling |
CeilingLightState
|
components |
Source code in src/lifx/devices/ceiling.py
Mirror Light¶
The MirrorLight class extends MatrixLight with independent control over the front and back components of a LIFX Mirror. Both components are multi-zone rings, so each can hold its own gradient or theme — see the Mirror Lights User Guide.
MirrorLight
¶
MirrorLight(
serial: str,
ip: str,
port: int = LIFX_UDP_PORT,
timeout: float = DEFAULT_REQUEST_TIMEOUT,
max_retries: int | None = DEFAULT_MAX_RETRIES,
state_file: str | None = None,
*,
fetch_wifi_info: bool = False,
fetch_thread_info: bool = False,
fetch_radio_info: bool = False,
fetch_ambient_light: bool = False,
ring_origin: RingOrigin | int = "top",
)
Bases: ComponentMatrixLight
LIFX Mirror Light with independent front and back control.
MirrorLight extends MatrixLight to provide semantic control over the front and back components while maintaining full backward compatibility with the MatrixLight API.
Both components are multi-zone rings, so each can hold its own gradient or theme.
Example
from lifx.devices import MirrorLight
from lifx.color import HSBK
from lifx.theme import get_theme
async with await MirrorLight.from_ip("192.168.1.100") as mirror:
# Bright task light on the front, warm backwash behind
await mirror.set_front_colors(
HSBK(hue=0, saturation=0, brightness=1.0, kelvin=4500)
)
await mirror.set_back_colors(
HSBK(hue=30, saturation=0.4, brightness=0.3, kelvin=2700)
)
# Or a different theme on each component
await mirror.apply_front_theme(get_theme("evening"))
await mirror.apply_back_theme(get_theme("galaxy"))
# Turn components on/off
await mirror.turn_back_off()
state_file keeps its original position: inserting a parameter ahead
of it would silently rebind existing positional callers. New options are
keyword-only for the same reason.
| PARAMETER | DESCRIPTION |
|---|---|
serial
|
Device serial number
TYPE:
|
ip
|
Device IP address
TYPE:
|
port
|
Device UDP port (default: 56700)
TYPE:
|
timeout
|
Overall timeout for network requests in seconds
TYPE:
|
max_retries
|
Maximum number of retry attempts for network requests
TYPE:
|
state_file
|
Optional path to JSON file for state persistence
TYPE:
|
fetch_wifi_info
|
Query WiFi signal strength during state initialization
TYPE:
|
fetch_thread_info
|
Query Thread mesh information during state initialization
TYPE:
|
fetch_radio_info
|
Query whichever radio matches the device's evidenced connectivity during state initialization
TYPE:
|
fetch_ambient_light
|
Query the ambient light sensor during state initialization
TYPE:
|
ring_origin
|
Where software effects start on each ring: "top",
"bottom", "left" or "right", or a front zone number from 0 to 24.
See the
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If |
| METHOD | DESCRIPTION |
|---|---|
refresh_state |
Refresh mirror light state from hardware. |
from_ip |
Create MirrorLight from IP address. |
get_front_colors |
Get current front component colors from device. |
get_back_colors |
Get current back component colors from device. |
set_front_colors |
Set front component colors. |
set_back_colors |
Set back component colors. |
turn_front_on |
Turn front component on. |
turn_back_on |
Turn back component on. |
turn_front_off |
Turn front component off. |
turn_back_off |
Turn back component off. |
apply_front_theme |
Apply a theme across the front component only. |
apply_back_theme |
Apply a theme across the back component only. |
set_power |
Set light power state, capturing component colors before turning off. |
set_color |
Set light color, updating component state tracking. |
| ATTRIBUTE | DESCRIPTION |
|---|---|
ring_origin |
Where a software effect starts on each ring.
TYPE:
|
state |
Get Mirror light state.
TYPE:
|
layout |
Component layout for this Mirror product.
TYPE:
|
front |
The front ring as an effect participant.
TYPE:
|
back |
The back ring as an effect participant.
TYPE:
|
front_positions |
Set64 buffer positions of the front zones, in zone order. |
back_positions |
Set64 buffer positions of the back zones, in zone order. |
front_zone_count |
Number of front zones.
TYPE:
|
back_zone_count |
Number of back zones.
TYPE:
|
front_is_on |
True if front component is currently on.
TYPE:
|
back_is_on |
True if back component is currently on.
TYPE:
|
Source code in src/lifx/devices/mirror.py
Attributes¶
ring_origin
property
writable
¶
ring_origin: RingOrigin | int
Where a software effect starts on each ring.
Frame pixel 0 lands on this spot of both rings and the pixels run
clockwise from it, so it is also where a pattern's seam sits. It is
"top" (top centre, front zone 9) by default, or "bottom" (zone 22),
"left" (zone 3) or "right" (zone 15), or a front zone number from 0 to
24. The back ring's index 24 - k sits level with front zone k,
so both rings start at the same spot.
The origin is read when an effect's writer is created, so changing it applies from the next effect start. An effect that is already running keeps the origin it started with.
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
On assignment, if the value is not a named spot or a front zone number from 0 to 24 |
state
property
¶
state: MirrorLightState
Get Mirror light state.
| RETURNS | DESCRIPTION |
|---|---|
MirrorLightState
|
MirrorLightState with current state information. |
| RAISES | DESCRIPTION |
|---|---|
RuntimeError
|
If accessed before state initialization. |
layout
property
¶
Component layout for this Mirror product.
| RETURNS | DESCRIPTION |
|---|---|
MirrorComponentLayout
|
MirrorComponentLayout describing the matrix and both components |
| RAISES | DESCRIPTION |
|---|---|
LifxError
|
If device version is not available or not a Mirror |
front
property
¶
front: LightComponent
The front ring as an effect participant.
It carries start_effect(), stop_effect() and animator. A
software effect started on it draws on the ring: 25 pixels clockwise
from the ring origin that wrap, so the last pixel sits next to the
first. The back keeps its colours and stays under the existing back
methods. Reading it changes nothing.
back
property
¶
back: LightComponent
The back ring as an effect participant.
It carries start_effect(), stop_effect() and animator. A
software effect started on it draws on the ring: 25 pixels that wrap,
clockwise from the ring origin like the front, so the ring's anticlockwise zones
are taken in reverse. The front keeps its colours and stays under the
existing front methods. Reading it changes nothing.
front_positions
property
¶
Set64 buffer positions of the front zones, in zone order.
Zone numbering does not match buffer order, so component colours are gathered from and scattered to these positions.
| RETURNS | DESCRIPTION |
|---|---|
tuple[int, ...]
|
Buffer positions of the 25 front zones |
| RAISES | DESCRIPTION |
|---|---|
LifxError
|
If device version is not available or not a Mirror |
back_positions
property
¶
front_is_on
property
¶
front_is_on: bool
True if front component is currently on.
Calculated as: power_level > 0 AND any front zone brightness > 0
Note
Requires recent data from device. Call refresh_state() to update cached values before checking this property.
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if front component is on, False otherwise |
back_is_on
property
¶
back_is_on: bool
True if back component is currently on.
Calculated as: power_level > 0 AND any back zone brightness > 0
Note
Requires recent data from device. Call refresh_state() to update cached values before checking this property.
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if back component is on, False otherwise |
Methods:¶
refresh_state
async
¶
Refresh mirror light state from hardware.
Fetches color, tiles, tile colors, effect, and mirror component state.
| RAISES | DESCRIPTION |
|---|---|
RuntimeError
|
If state has not been initialized |
LifxTimeoutError
|
If device does not respond |
LifxDeviceNotFoundError
|
If device cannot be reached |
Source code in src/lifx/devices/mirror.py
from_ip
async
classmethod
¶
from_ip(
ip: str,
port: int = LIFX_UDP_PORT,
serial: str | None = None,
timeout: float = DEFAULT_REQUEST_TIMEOUT,
max_retries: int | None = DEFAULT_MAX_RETRIES,
*,
fetch_wifi_info: bool = False,
fetch_thread_info: bool = False,
fetch_radio_info: bool = False,
fetch_ambient_light: bool = False,
state_file: str | None = None,
) -> MirrorLight
Create MirrorLight from IP address.
| PARAMETER | DESCRIPTION |
|---|---|
ip
|
Device IP address
TYPE:
|
port
|
Port number (default LIFX_UDP_PORT)
TYPE:
|
serial
|
Serial number as 12-digit hex string
TYPE:
|
timeout
|
Request timeout for this device instance
TYPE:
|
max_retries
|
Maximum number of retries for requests
TYPE:
|
fetch_wifi_info
|
Query WiFi signal strength during state initialization
TYPE:
|
fetch_thread_info
|
Query Thread mesh information during state initialization
TYPE:
|
fetch_radio_info
|
Query whichever radio matches the device's evidenced connectivity during state initialization
TYPE:
|
fetch_ambient_light
|
Query the ambient light sensor during state initialization
TYPE:
|
state_file
|
Optional path to JSON file for state persistence
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
MirrorLight
|
MirrorLight instance |
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
Device not found at IP |
LifxTimeoutError
|
Device did not respond |
LifxError
|
Device is not a supported Mirror product |
Source code in src/lifx/devices/mirror.py
get_front_colors
async
¶
Get current front component colors from device.
| RETURNS | DESCRIPTION |
|---|---|
list[HSBK]
|
List of HSBK colors, one per front zone |
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
Device did not respond |
Source code in src/lifx/devices/mirror.py
get_back_colors
async
¶
Get current back component colors from device.
| RETURNS | DESCRIPTION |
|---|---|
list[HSBK]
|
List of HSBK colors, one per back zone |
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
Device did not respond |
Source code in src/lifx/devices/mirror.py
set_front_colors
async
¶
Set front component colors.
| PARAMETER | DESCRIPTION |
|---|---|
colors
|
Either:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If every color has brightness == 0 (use turn_front_off instead) |
ValueError
|
If list length doesn't match front zone count |
LifxTimeoutError
|
Device did not respond |
Note
Also updates stored state for future restoration.
Source code in src/lifx/devices/mirror.py
set_back_colors
async
¶
Set back component colors.
| PARAMETER | DESCRIPTION |
|---|---|
colors
|
Either:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If every color has brightness == 0 (use turn_back_off instead) |
ValueError
|
If list length doesn't match back zone count |
LifxTimeoutError
|
Device did not respond |
Note
Also updates stored state for future restoration.
Source code in src/lifx/devices/mirror.py
turn_front_on
async
¶
Turn front component on.
If the entire light is off, this sets the colors instantly and then turns the light on with the requested duration, so it fades to the target colors instead of flashing to its previous state.
| PARAMETER | DESCRIPTION |
|---|---|
colors
|
Optional colors. Can be:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If every color has brightness == 0 |
ValueError
|
If list length doesn't match front zone count |
LifxTimeoutError
|
Device did not respond |
Source code in src/lifx/devices/mirror.py
turn_back_on
async
¶
Turn back component on.
If the entire light is off, this sets the colors instantly and then turns the light on with the requested duration, so it fades to the target colors instead of flashing to its previous state.
| PARAMETER | DESCRIPTION |
|---|---|
colors
|
Optional colors. Can be:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If every color has brightness == 0 |
ValueError
|
If list length doesn't match back zone count |
LifxTimeoutError
|
Device did not respond |
Source code in src/lifx/devices/mirror.py
turn_front_off
async
¶
Turn front component off.
| PARAMETER | DESCRIPTION |
|---|---|
colors
|
Optional colors to store for future turn_on. Can be:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If every color has brightness == 0 |
ValueError
|
If list length doesn't match front zone count |
LifxTimeoutError
|
Device did not respond |
Note
Sets front zone brightness to 0 on device while preserving H, S, K. If the back component is already off, the entire device is powered off instead and the front zones keep their brightness, so a later set_power(True) brings the front back rather than turning on a light with every zone at zero brightness.
Source code in src/lifx/devices/mirror.py
turn_back_off
async
¶
Turn back component off.
| PARAMETER | DESCRIPTION |
|---|---|
colors
|
Optional colors to store for future turn_on. Can be:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If every color has brightness == 0 |
ValueError
|
If list length doesn't match back zone count |
LifxTimeoutError
|
Device did not respond |
Note
Sets back zone brightness to 0 on device while preserving H, S, K. If the front component is already off, the entire device is powered off instead and the back zones keep their brightness, so a later set_power(True) brings the back back rather than turning on a light with every zone at zero brightness.
Source code in src/lifx/devices/mirror.py
apply_front_theme
async
¶
Apply a theme across the front component only.
| PARAMETER | DESCRIPTION |
|---|---|
theme
|
Theme to apply
TYPE:
|
power_on
|
Turn on the light
TYPE:
|
duration
|
Transition duration in seconds
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
Device did not respond |
Example
Source code in src/lifx/devices/mirror.py
apply_back_theme
async
¶
Apply a theme across the back component only.
| PARAMETER | DESCRIPTION |
|---|---|
theme
|
Theme to apply
TYPE:
|
power_on
|
Turn on the light
TYPE:
|
duration
|
Transition duration in seconds
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
LifxTimeoutError
|
Device did not respond |
Example
Source code in src/lifx/devices/mirror.py
set_power
async
¶
Set light power state, capturing component colors before turning off.
Overrides Light.set_power() to capture the current front and back colors before turning off the entire light. This allows subsequent calls to turn_front_on() or turn_back_on() to restore the colors that were active just before the light was turned off.
The captured colors preserve hue, saturation, and kelvin values even if a component was already off (brightness=0). The brightness will be determined at turn-on time using the standard brightness inference logic.
| PARAMETER | DESCRIPTION |
|---|---|
level
|
True/65535 to turn on, False/0 to turn off |
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If integer value is not 0 or 65535 |
TypeError
|
If level is neither bool nor int |
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/mirror.py
set_color
async
¶
Set light color, updating component state tracking.
Overrides Light.set_color() to track the color change in the mirror light's component state. When set_color() is called, all zones (front and back) are set to the same color. This override ensures the cached component colors stay in sync so subsequent component control methods use the correct color values.
| PARAMETER | DESCRIPTION |
|---|---|
color
|
HSBK color to set for the entire light
TYPE:
|
duration
|
Transition duration in seconds (default 0.0)
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
LifxDeviceNotFoundError
|
If device is not connected |
LifxTimeoutError
|
If device does not respond |
LifxUnsupportedCommandError
|
If device doesn't support this command |
Example
Source code in src/lifx/devices/mirror.py
MirrorLightState¶
The MirrorLightState dataclass extends MatrixLightState with mirror-specific component information. It is returned by MirrorLight.state after connecting to a device.
MirrorLightState
dataclass
¶
MirrorLightState(
model: str,
label: str,
serial: str,
mac_address: str,
capabilities: DeviceCapabilities,
power: int,
host_firmware: FirmwareInfo,
wifi_firmware: FirmwareInfo,
location: CollectionInfo,
group: CollectionInfo,
last_updated: float,
color: HSBK,
chain: list[TileInfo],
tile_orientations: dict[int, str],
tile_colors: list[HSBK],
tile_count: int,
effect: FirmwareEffect,
front_colors: list[HSBK],
back_colors: list[HSBK],
front_is_on: bool,
back_is_on: bool,
front_positions: tuple[int, ...],
back_positions: tuple[int, ...],
stored_front_colors: list[HSBK] | None = None,
stored_back_colors: list[HSBK] | None = None,
last_front_colors: list[HSBK] | None = None,
last_back_colors: list[HSBK] | None = None,
*,
wifi_info: WifiInfo = (lambda: WifiInfo(signal=None, host_firmware=None))(),
thread_info: ThreadInfo | None = None,
ambient_light: float | None = None,
)
Bases: MatrixLightState
Mirror light device state with front/back component control.
Extends MatrixLightState with mirror-specific component information.
| ATTRIBUTE | DESCRIPTION |
|---|---|
front_colors |
List of HSBK colors for each front zone |
back_colors |
List of HSBK colors for each back zone |
front_is_on |
Whether front component is on (any zone brightness > 0)
TYPE:
|
back_is_on |
Whether back component is on (any zone brightness > 0)
TYPE:
|
front_positions |
Set64 buffer positions of the front zones |
back_positions |
Set64 buffer positions of the back zones |
stored_front_colors |
Stored front colors for restoration after turning off |
stored_back_colors |
Stored back colors for restoration after turning off |
last_front_colors |
Last known front colors, updated after every operation |
last_back_colors |
Last known back colors, updated after every operation |
| METHOD | DESCRIPTION |
|---|---|
from_matrix_state |
Create MirrorLightState from MatrixLightState. |
Attributes¶
as_dict
property
¶
as_dict: Any
Return MirrorLightState as dict.
The buffer position tuples are expanded into lists so the result is
serialisable. The component colors are expanded via
:attr:HSBK.as_dict; the stored and last-known fields stay None when
unset.
Methods:¶
from_matrix_state
classmethod
¶
from_matrix_state(
matrix_state: MatrixLightState,
front_colors: list[HSBK],
back_colors: list[HSBK],
front_positions: tuple[int, ...],
back_positions: tuple[int, ...],
*,
stored_front_colors: list[HSBK] | None = None,
stored_back_colors: list[HSBK] | None = None,
) -> MirrorLightState
Create MirrorLightState from MatrixLightState.
| PARAMETER | DESCRIPTION |
|---|---|
matrix_state
|
Base MatrixLightState to extend
TYPE:
|
front_colors
|
Current front zone colors |
back_colors
|
Current back zone colors |
front_positions
|
Set64 buffer positions of the front zones |
back_positions
|
Set64 buffer positions of the back zones |
stored_front_colors
|
Stored front colors for restoration |
stored_back_colors
|
Stored back colors for restoration |
| RETURNS | DESCRIPTION |
|---|---|
MirrorLightState
|
MirrorLightState with all matrix state plus mirror components |
Source code in src/lifx/devices/mirror.py
Device Properties¶
Connectivity¶
The connectivity property returns a Connectivity enum member, either
Connectivity.WIFI or Connectivity.THREAD. The enum derives from str, so
device.connectivity == "thread" still holds.
A LIFX device's radio operates in either WiFi or Thread mode, and changing between them requires a firmware crossgrade. The value is therefore invariant for a given device rather than a per-request transport choice.
Once the device answers any request, its own report in the frame address
(thread_connection, byte 22 bit 3) is authoritative and determines the value
in both directions. Until then the value comes from the mDNS TXT record,
defaulting to Connectivity.WIFI. This means a Thread device found over UDP
broadcast, from_ip(), or a won find_by_serial() race reports correctly
once it has answered, even though it carries no mDNS TXT record.
The value does not change the device's address, routing, retry, or tuning
behaviour. It does gate the radio-specific queries: get_wifi_info() and
get_wifi_firmware() are refused once a device is evidenced as Thread, and
get_thread_info() is refused once it is evidenced as WiFi, because each
firmware install can only answer its own radio's packets. Evidence means an
observed frame address report or an mDNS record naming either radio; the WiFi default a
device carries before either exists is not evidence, so a never-contacted
device is queried and answers for itself.
MAC Address¶
The mac_address property provides the device's MAC address, calculated from the serial number
and host firmware version. The calculation is performed automatically when the device is used
as a context manager or when get_host_firmware() is called.
Calculation Logic (based on the host firmware major and minor version):
- Firmware 3.70 and above, below 4.0: MAC address is the serial number with the least significant byte incremented by 1 (with wraparound from 0xFF to 0x00)
- Every other firmware — including earlier 3.x builds such as 3.50, verified against LIFX Tiles whose real MAC matched their serial — MAC address matches the serial number
Both version components are compared as integers, so firmware 3.9 is below the 3.70 boundary, not above it: reading the version as a decimal misclassifies it.
Devices never report their MAC on the wire and are always addressed by serial, so this value is
a convenience derivation only. It is recalculated whenever get_host_firmware() reports a
different firmware version, so it stays consistent with the rule above after an update.
The MAC address is returned in colon-separated lowercase hexadecimal format (e.g., d0:73:d5:01:02:03)
to visually distinguish it from the serial number format.
from lifx import Device
async def main():
async with await Device.connect("192.168.1.100") as device:
# MAC address is automatically calculated during setup
if device.mac_address:
print(f"Serial: {device.serial}")
print(f"MAC: {device.mac_address}")
# Returns None before host_firmware is fetched
assert device.mac_address is not None
Examples¶
Basic Light Control¶
from lifx import Colors, Device
async def main():
async with await Device.connect("192.168.1.100") as light:
# Turn on and set color
await light.set_power(True)
await light.set_color(Colors.BLUE, duration=1.0)
# Get device info
label = await light.get_label()
print(f"Controlling: {label}")
Light Waveforms¶
from lifx import Colors, Device
async def main():
async with await Device.connect("192.168.1.100") as light:
# Pulse waveform
await light.pulse(Colors.RED, period=1.0, cycles=5)
# Breathe waveform
await light.breathe(Colors.BLUE, period=2.0, cycles=3)
HEV Light Control (Anti-Bacterial Cleaning)¶
from lifx import Device, HevLight
async def main():
async with await Device.connect("192.168.1.100") as light:
assert isinstance(light, HevLight)
# Start a 2-hour cleaning cycle
await light.set_hev_cycle(enable=True, duration_seconds=7200)
# Check cycle status
state = await light.get_hev_cycle()
if state.is_running:
print(f"Cleaning: {state.remaining_s}s remaining")
# Configure default settings
await light.set_hev_config(indication=True, duration_seconds=7200)
Infrared Light Control (Night Vision)¶
from lifx import Device, InfraredLight
async def main():
async with await Device.connect("192.168.1.100") as light:
assert isinstance(light, InfraredLight)
# Set infrared brightness to 50%
await light.set_infrared(0.5)
# Get current infrared brightness
brightness = await light.get_infrared()
print(f"IR brightness: {brightness * 100}%")
Ambient Light Sensor¶
Light devices with ambient light sensors can measure the current ambient light level in lux:
from lifx import Device
async def main():
async with await Device.connect("192.168.1.100") as light:
# Ensure light is off for accurate reading
await light.set_power(False)
# Get ambient light level in lux
lux = await light.get_ambient_light_level()
if lux > 0:
print(f"Ambient light: {lux} lux")
else:
print("No ambient light sensor or completely dark")
The sensor can also be read as part of state instead of on demand. A light
created with fetch_ambient_light=True — or one that has the property set later
— queries it during state initialisation and on every refresh_state(), storing
the result in state.ambient_light:
async with await Device.connect(ip="192.168.1.100") as light:
light.fetch_ambient_light = True
await light.refresh_state()
print(f"Ambient light: {light.state.ambient_light} lux")
light.fetch_ambient_light = False # stop collecting
The query joins the same parallel batch as the other state requests, so it costs
no extra round trip. Toggling the property takes effect from the next state
initialisation or refresh: turning it off stores None rather than leaving the
last reading behind a freshly stamped last_updated.
Notes:
- Every product answers packet 401, so the query never fails on an unsupported device — it returns 0.0
- A reading of 0.0 is ambiguous: no sensor, a sensor the device cannot read, and complete darkness all report 0.0, and nothing in the response or the product registry distinguishes them
state.ambient_lightis captured whenever state refreshes, including the debounced refresh that followsset_power()/set_color(). A reading taken while the light is on measures the light's own output, so it is stored as-1.0(lifx.INVALID_AMBIENT_LIGHT_RESPONSE) rather than as a plausible-looking lux value- For accurate readings, the light should be turned off (otherwise the light's own illumination interferes with the sensor)
get_ambient_light_level()always fetches fresh from the device;state.ambient_lightis as fresh as the last state refresh, and isNoneuntil the sensor is queried at least once- If a request does fail outright,
state.ambient_lightis leftNoneand a warning is logged — state initialisation and refresh still succeed - Returns ambient light level in lux (higher values indicate brighter ambient light)
MultiZone Control¶
from lifx import Colors, Device, Direction, FirmwareEffect, MultiZoneLight
async def main():
async with await Device.connect("192.168.1.100") as light:
assert isinstance(light, MultiZoneLight)
# Get all zones - automatically uses best method
colors = await light.get_all_color_zones()
print(f"Device has {len(colors)} zones")
# Write zones back the same way. set_all_color_zones picks the
# extended or legacy packet based on device capabilities, chunks
# past the 82-colour extended packet limit, and run-length encodes
# legacy writes, so it works on any strip or beam.
colors[0] = Colors.RED
await light.set_all_color_zones(colors, duration=1.0)
# Only write part of the strip: zones outside start..end keep
# whatever they were showing.
await light.set_all_color_zones(colors, start=10, end=19)
# Set a MOVE effect
await light.set_move_effect(Direction.FORWARD, 5.0) # seconds per cycle
# Get current effect
effect = await light.get_effect()
print(f"Effect: {effect.effect_type.name}")
if effect.effect_type == FirmwareEffect.MOVE:
print(f"Direction: {effect.direction.name}")
# Stop the effect
await light.stop_effect()
Tile Control¶
from lifx import HSBK, Device, FirmwareEffect, MatrixLight
async def main():
async with await Device.connect("192.168.1.100") as light:
assert isinstance(light, MatrixLight)
# Set a gradient across the tile
colors = [
HSBK(hue=h, saturation=1.0, brightness=0.5, kelvin=3500)
for h in range(0, 360, 10)
]
await light.set_tile_colors(colors)
# Set a tile effect (MORPH, FLAME, SKY, or COLOR_SWEEP)
await light.set_effect(
effect_type=FirmwareEffect.FLAME,
speed=5.0, # seconds per cycle
)
# Get current effect
effect = await light.get_effect()
print(f"Tile effect: {effect.effect_type.name}")
# Stop the effect
await light.set_effect(effect_type=FirmwareEffect.OFF)
Ceiling Light Control¶
from lifx import HSBK, CeilingLight, Device
async def main():
async with await Device.connect("192.168.1.100") as ceiling:
assert isinstance(ceiling, CeilingLight)
# Set downlight to warm white
await ceiling.set_downlight_colors(
HSBK(hue=0, saturation=0, brightness=0.8, kelvin=3000)
)
# Set uplight to a dim ambient glow
await ceiling.set_uplight_color(
HSBK(hue=30, saturation=0.2, brightness=0.3, kelvin=2700)
)
# Turn uplight off (stores color for later restoration)
await ceiling.turn_uplight_off()
# Turn uplight back on (restores previous color)
await ceiling.turn_uplight_on()
# Check component state
if ceiling.downlight_is_on:
print("Downlight is currently on")
For detailed CeilingLight usage, see the Ceiling Lights User Guide.