Ceiling Lights¶
LIFX Ceiling lights are unique fixtures that combine two lighting components in one device:
- Downlight: Main illumination with multiple addressable zones (63 or 127 zones)
- Uplight: Ambient/indirect lighting via a single zone
The CeilingLight class provides high-level control over these components while inheriting full matrix functionality from MatrixLight.
Supported Devices¶
| Product | Zones | Layout |
|---|---|---|
| LIFX Ceiling (US/Intl) | 64 | 8x8 grid, zone 63 = uplight |
| LIFX Ceiling Capsule (US/Intl) | 128 | 16x8 grid, zone 127 = uplight |
Quick Start¶
from lifx import CeilingLight
from lifx.color import HSBK
async def main():
async with await CeilingLight.from_ip("192.168.1.100") as ceiling:
# Set downlight to warm white
await ceiling.set_downlight_colors(
HSBK(hue=0, saturation=0, brightness=1.0, kelvin=3000)
)
# Set uplight to a dim, warm ambient glow
await ceiling.set_uplight_color(
HSBK(hue=30, saturation=0.2, brightness=0.3, kelvin=2700)
)
Component Control¶
Setting Colors¶
Downlight¶
Set all downlight zones to the same color:
# Single color for all zones
await ceiling.set_downlight_colors(
HSBK(hue=0, saturation=0, brightness=0.8, kelvin=4000)
)
Or set each zone individually:
# Create a gradient across all zones
zone_count = len(range(*ceiling.downlight_zones.indices(256)))
colors = [
HSBK(hue=(i * 360 / zone_count), saturation=1.0, brightness=0.5, kelvin=3500)
for i in range(zone_count)
]
await ceiling.set_downlight_colors(colors)
Uplight¶
Reading Current Colors¶
# Get current uplight color
uplight_color = await ceiling.get_uplight_color()
print(f"Uplight: H={uplight_color.hue}, B={uplight_color.brightness}")
# Get all downlight colors
downlight_colors = await ceiling.get_downlight_colors()
print(f"Downlight zones: {len(downlight_colors)}")
Turning Components On/Off¶
The turn_*_on() and turn_*_off() methods provide smart state management:
# Turn off uplight (stores current color for later restoration)
await ceiling.turn_uplight_off()
# Turn uplight back on (restores previous color)
await ceiling.turn_uplight_on()
# Turn on with a specific color
await ceiling.turn_uplight_on(
color=HSBK(hue=0, saturation=0, brightness=1.0, kelvin=3500)
)
The same pattern works for downlights:
# Turn off downlight
await ceiling.turn_downlight_off()
# Turn downlight back on
await ceiling.turn_downlight_on()
# Turn on with specific colors
await ceiling.turn_downlight_on(
colors=HSBK(hue=0, saturation=0, brightness=0.8, kelvin=4000)
)
Checking Component State¶
# Check if components are on
if ceiling.uplight_is_on:
print("Uplight is on")
if ceiling.downlight_is_on:
print("Downlight is on")
State Properties Require Recent Data
The uplight_is_on and downlight_is_on properties rely on cached data.
Call get_uplight_color() or get_downlight_colors() first to ensure
accurate state.
Device State¶
After connecting to a CeilingLight, you can access the complete device state via the state property, which returns a CeilingLightState dataclass:
from lifx import CeilingLight, CeilingLightState
async with await CeilingLight.from_ip("192.168.1.100") as ceiling:
state: CeilingLightState = ceiling.state
# Access ceiling-specific state
print(f"Uplight color: {state.uplight_color}")
print(f"Uplight is on: {state.uplight_is_on}")
print(f"Downlight zones: {len(state.downlight_colors)}")
print(f"Downlight is on: {state.downlight_is_on}")
# Access inherited state from MatrixLightState/LightState
print(f"Device label: {state.label}")
print(f"Power: {'on' if state.power else 'off'}")
print(f"Model: {state.model}")
CeilingLightState Attributes¶
CeilingLightState extends MatrixLightState with ceiling-specific attributes:
| Attribute | Type | Description |
|---|---|---|
uplight_color |
HSBK |
Current color of the uplight component |
downlight_colors |
list[HSBK] |
Colors for each downlight zone (63 or 127) |
uplight_is_on |
bool |
True if uplight brightness > 0 |
downlight_is_on |
bool |
True if any downlight zone brightness > 0 |
uplight_zone |
int |
Zone index for uplight (63 or 127) |
downlight_zones |
slice |
Slice for downlight zones |
Plus all attributes inherited from MatrixLightState: chain, tile_colors, tile_count, effect, and from LightState: color, power, label, model, serial, mac_address, capabilities, etc.
Zone Layout¶
Access the component zone indices directly:
async with await CeilingLight.from_ip("192.168.1.100") as ceiling:
# Get uplight zone index (63 or 127 depending on model)
uplight_idx = ceiling.uplight_zone
print(f"Uplight zone: {uplight_idx}")
# Get downlight zones as a slice
downlight_slice = ceiling.downlight_zones
print(f"Downlight zones: {downlight_slice}") # slice(0, 63) or slice(0, 127)
# Calculate number of downlight zones
zone_count = len(range(*downlight_slice.indices(256)))
print(f"Number of downlight zones: {zone_count}")
State Persistence¶
CeilingLight supports optional state persistence to preserve component colors across sessions:
async with await CeilingLight.from_ip(
"192.168.1.100",
state_file="~/.lifx/ceiling_state.json"
) as ceiling:
# Colors are automatically loaded from file on connection
# and saved when using turn_*_off() methods
await ceiling.turn_uplight_off() # Saves current color to file
# ... later ...
await ceiling.turn_uplight_on() # Restores from file if available
The state file stores colors per device serial number, supporting multiple devices:
{
"d073d5123456": {
"uplight": {
"hue": 30.0,
"saturation": 0.2,
"brightness": 0.4,
"kelvin": 2700
},
"downlight": [
{"hue": 0.0, "saturation": 0.0, "brightness": 0.8, "kelvin": 4000}
]
}
}
Brightness Determination¶
When calling turn_uplight_on() or turn_downlight_on() without a color parameter, CeilingLight uses the following priority to determine brightness:
- Stored state: If a color was previously saved (via
turn_*_off()orset_*_color()) - Infer from other component: Average brightness of the other component
- Default: 80% brightness
This ensures a reasonable brightness level even when no state is available.
Transition Duration¶
All color-setting methods support smooth transitions:
# 2-second transition to new color
await ceiling.set_uplight_color(
HSBK(hue=0, saturation=0, brightness=1.0, kelvin=3500),
duration=2.0 # seconds
)
# Instant change (default)
await ceiling.set_downlight_colors(
HSBK(hue=240, saturation=1.0, brightness=0.5, kelvin=3500),
duration=0.0
)
MatrixLight Compatibility¶
CeilingLight extends MatrixLight, so all matrix operations are available:
async with await CeilingLight.from_ip("192.168.1.100") as ceiling:
# Use MatrixLight methods directly
all_colors = await ceiling.get_all_tile_colors()
tile_chain = await ceiling.get_tile_chain()
# Set raw matrix colors (bypasses component abstraction)
await ceiling.set_matrix_colors(0, colors)
# Apply effects
from lifx.protocol.protocol_types import TileEffectType
await ceiling.set_tile_effect(
effect_type=TileEffectType.MORPH,
speed=5000,
)
Example: Night Mode¶
Create a subtle night light with dim uplight and downlight off:
from lifx import CeilingLight
from lifx.color import HSBK
async def night_mode(ip: str):
async with await CeilingLight.from_ip(ip) as ceiling:
# Store current colors before turning off
await ceiling.turn_downlight_off()
# Set uplight to very dim warm glow
await ceiling.set_uplight_color(
HSBK(hue=30, saturation=0.3, brightness=0.05, kelvin=2200),
duration=2.0
)
Example: Daytime Productivity¶
Bright, cool white for focus:
async def daytime_mode(ip: str):
async with await CeilingLight.from_ip(ip) as ceiling:
# Bright cool downlight for task lighting
await ceiling.set_downlight_colors(
HSBK(hue=0, saturation=0, brightness=1.0, kelvin=5500),
duration=1.0
)
# Turn off uplight during the day
await ceiling.turn_uplight_off(duration=1.0)
Example: Evening Ambiance¶
Warm tones with accent uplight:
async def evening_mode(ip: str):
async with await CeilingLight.from_ip(ip) as ceiling:
# Dimmed warm downlight
await ceiling.set_downlight_colors(
HSBK(hue=30, saturation=0.1, brightness=0.4, kelvin=2700),
duration=2.0
)
# Colorful uplight accent
await ceiling.set_uplight_color(
HSBK(hue=280, saturation=0.6, brightness=0.3, kelvin=3500),
duration=2.0
)
Sunrise and Sunset Effects¶
LIFX Ceiling lights have a round or oval shape, making them ideal candidates for the sunrise and sunset effects with the origin="center" setting. This makes the sun expand outward from the center of the light rather than rising from the bottom edge.
from lifx import CeilingLight
from lifx.effects import Conductor, EffectSunrise, EffectSunset
async def wake_up_light(ip: str):
"""Simulate a sunrise on a Ceiling light."""
async with await CeilingLight.from_ip(ip) as ceiling:
conductor = Conductor()
# 30-minute sunrise expanding from the center
effect = EffectSunrise(
duration=1800,
brightness=1.0,
origin="center"
)
await conductor.start(effect, [ceiling])
# Effect completes automatically — light stays at daylight
async def goodnight_light(ip: str):
"""Simulate a sunset on a Ceiling light, then power off."""
async with await CeilingLight.from_ip(ip) as ceiling:
conductor = Conductor()
# 30-minute sunset contracting to center, then off
effect = EffectSunset(
power_on=True,
duration=1800,
brightness=1.0,
power_off=True,
origin="center"
)
await conductor.start(effect, [ceiling])
# Effect completes automatically — light powers off
The origin parameter accepts two values:
"bottom"(default): Center of the bottom row — designed for rectangular tile arrays"center": Middle of the canvas — designed for round/oval Ceiling lights
Choosing the right origin
For LIFX Ceiling and LIFX Ceiling Capsule devices, always use origin="center" for the most natural-looking sunrise and sunset transitions.
API Reference¶
See CeilingLight API Reference for complete method documentation.