Skip to content

Using Themes: Practical Examples

Themes enable coordinated color schemes across your LIFX devices. This guide covers practical examples and patterns.

Basic Usage

Apply Theme to All Devices

from lifx import discover, DeviceGroup, ThemeLibrary

async def apply_evening_mode():
    devices = []
    async for device in discover():
        devices.append(device)
    group = DeviceGroup(devices)

    theme = ThemeLibrary.get("evening")
    await group.apply_theme(theme, power_on=True, duration=2.0)

One Theme, Per-Device-Type Rendering

group.lights holds every colour-capable device, including strips and matrix devices, and apply_theme() dispatches polymorphically: single-zone lights get a random colour, multizone lights get distributed colours, and matrix and ceiling devices get a smooth interpolation. Painting group.multizone_lights or group.matrix_lights as well would paint those devices a second time.

from lifx import discover, DeviceGroup, ThemeLibrary

async def themed_lighting():
    devices = []
    async for device in discover():
        devices.append(device)
    group = DeviceGroup(devices)

    theme = ThemeLibrary.get("christmas")

    # Each device renders the theme according to its own geometry
    for light in group.lights:
        await light.apply_theme(theme)

Time-Based Lighting

Morning to Night Transition

from lifx import discover, DeviceGroup, ThemeLibrary
import asyncio

async def daily_lighting_schedule():
    devices = []
    async for device in discover():
        devices.append(device)
    group = DeviceGroup(devices)

    schedule = [
        ("06:00", "energizing"),   # Morning
        ("12:00", "gentle"),       # Afternoon
        ("18:00", "evening"),      # Early evening
        ("21:00", "relaxing"),     # Night
        ("23:00", "peaceful"),     # Bedtime
    ]

    for time_str, theme_name in schedule:
        theme = ThemeLibrary.get(theme_name)
        await group.apply_theme(theme, duration=2.0)
        # In production, schedule this with APScheduler or similar
        await asyncio.sleep(2.0)  # Demo delay

Holiday Decorations

Holiday Mode Manager

from lifx import discover, DeviceGroup, ThemeLibrary
from datetime import datetime

async def activate_holiday_theme():
    """Apply appropriate holiday theme based on current month."""
    month = datetime.now().month

    holiday_map = {
        3: "st_patricks_day",  # March
        10: "halloween",        # October
        11: "thanksgiving",     # November
        12: "christmas",        # December
    }

    theme_name = holiday_map.get(month)
    if not theme_name:
        return

    devices = []
    async for device in discover():
        devices.append(device)
    group = DeviceGroup(devices)

    theme = ThemeLibrary.get(theme_name)
    await group.apply_theme(theme, power_on=True)

Multi-Room Holiday Setup

from lifx import discover, DeviceGroup, ThemeLibrary

async def decorate_house_for_christmas():
    """Apply Christmas theme throughout the house."""
    devices = []
    async for device in discover():
        devices.append(device)
    group = DeviceGroup(devices)

    theme = ThemeLibrary.get("christmas")

    # Living room: full brightness
    for light in group.lights:
        if "living" in light.label.lower():
            await light.apply_theme(theme, power_on=True, duration=1.0)

    # Bedroom: dimmer
    for light in group.lights:
        if "bedroom" in light.label.lower():
            dim_theme = ThemeLibrary.get("peaceful")
            await light.apply_theme(dim_theme, power_on=True, duration=1.0)

Strips and matrix devices are already in group.lights, so they are painted by the loops above. Iterating group.multizone_lights or group.matrix_lights as well would paint them twice.

Dynamic Theme Transitions

Smooth Theme Cycling

from lifx import discover, DeviceGroup, ThemeLibrary
import asyncio

async def cycle_moods():
    """Smoothly transition between mood themes."""
    mood_themes = [
        "peaceful",
        "relaxing",
        "mellow",
        "cheerful",
        "energizing",
    ]

    devices = []
    async for device in discover():
        devices.append(device)
    group = DeviceGroup(devices)

    for theme_name in mood_themes:
        theme = ThemeLibrary.get(theme_name)
        await group.apply_theme(theme, duration=2.0)
        await asyncio.sleep(2.5)  # Wait for transition + 0.5s delay

Theme Playlist

from lifx import discover, DeviceGroup, ThemeLibrary
import asyncio

async def theme_playlist(themes: list[str], duration: float = 5.0):
    """Apply a sequence of themes with configurable timing."""
    devices = []
    async for device in discover():
        devices.append(device)
    group = DeviceGroup(devices)

    for theme_name in themes:
        try:
            theme = ThemeLibrary.get(theme_name)
            await group.apply_theme(theme, duration=1.0)
            await asyncio.sleep(duration)
        except KeyError:
            print(f"Theme '{theme_name}' not found, skipping")

# Usage:
# await theme_playlist(["evening", "relaxing", "peaceful"], duration=10.0)

Room-Specific Themes

Multi-Room Coordination

from lifx import discover, DeviceGroup, ThemeLibrary
import asyncio

async def set_room_theme(room_name: str, theme_name: str):
    """Apply theme to all lights in a specific room (group)."""
    devices = []
    async for device in discover():
        devices.append(device)
    group = DeviceGroup(devices)

    theme = ThemeLibrary.get(theme_name)
    groups = await group.organize_by_group()

    if room_name not in groups:
        print(f"Room '{room_name}' not found")
        return

    room_lights = groups[room_name]

    # room_lights.lights already includes the strips and matrix devices
    await room_lights.apply_theme(theme, power_on=True)

# Usage:
# await set_room_theme("bedroom", "peaceful")
# await set_room_theme("kitchen", "gentle")

Home Scene Presets

from lifx import discover, ThemeLibrary

async def activate_scene(scene: str):
    """Activate a pre-defined home scene."""
    scenes = {
        "movie_night": {
            "living_room": "stardust",
            "kitchen": "evening",
            "bedroom": "peaceful",
        },
        "date_night": {
            "living_room": "romance",
            "bedroom": "blissful",
        },
        "party": {
            "living_room": "party",
            "kitchen": "energizing",
        },
        "focus": {
            "home_office": "gentle",
            "kitchen": "energizing",
        },
    }

    if scene not in scenes:
        print(f"Scene '{scene}' not found")
        return

    devices = []
    async for device in discover():
        devices.append(device)
    group = DeviceGroup(devices)

    groups = await group.organize_by_group()

    for room, theme_name in scenes[scene].items():
        if room not in groups:
            continue

        room_lights = groups[room]
        theme = ThemeLibrary.get(theme_name)

        # Every colour-capable device in the room, painted exactly once
        await room_lights.apply_theme(theme, power_on=True, duration=1.5)

# Usage:
# await activate_scene("movie_night")
# await activate_scene("party")

Moods: Paint Like the LIFX App

apply_theme() renders a theme as a gradient. To get what the LIFX app shows for a theme, use apply_mood() for the still image and animate_mood() for the effect the app's Dynamic toggle starts. Both take only the theme.

from lifx import DeviceGroup
from lifx.theme import get_theme

group = DeviceGroup(devices)
van_gogh = get_theme("van_gogh")

await group.apply_mood(van_gogh)    # the still image, as a tap in the app
await group.animate_mood(van_gogh)  # the Dynamic toggle

Stop the animation by calling stop_effect() on each light of the group: DeviceGroup has no stop_effect(). Stopping puts back what each light showed before its mood animation started, power included, so a light that was off goes back off. Starting another mood on an animating light keeps that original state, and a second stop_effect() restores nothing more.

for light in group.lights:
    await light.stop_effect()

Moods use the app's own timings and rules:

  • The change fades in over 0.3 seconds.
  • apply_mood() powers lights on only when every targeted light is off. animate_mood() turns on every light it targets.
  • The mood is rescaled so its brightest colour matches the light's brightness. So are the colours an animation steps through; bulbs in one DeviceGroup share a loop rescaled to the brightest of them.
  • Calling apply_mood() on a light that is already running a mood effect restarts that effect with the new theme.
  • apply_mood() does not stop an effect that is not a mood, such as firmware FLAME or the software Rainbow, just as apply_theme() does not.

What a mood does depends on the light:

  • Bulbs show one of the theme's colours. Animated, they run a Colour Loop through the theme's colours, and bulbs in one DeviceGroup share one loop.
  • Strips show the mood across their zones. Animated, they run firmware MOVE after painting the still image.
  • Matrix lights show the mood's image. Animated, a MORPH mood runs firmware MORPH and a MOVE mood runs EffectScroll, which moves the image one column every 1.25 seconds.
  • Spot, Path and the Mirror use firmware MORPH for every mood. The Mirror is painted as a single matrix light over its 4x13 buffer, not ring by ring.
  • Every Candle, the Tube and the Mirror paint stripe moods as bands along the long axis, with the first colour at the bottom. On every Candle and the Tube, a MOVE stripe mood scrolls the bands down the light; blended and grid moods scroll sideways. The Mirror runs MORPH instead.
  • A Tile chain is painted and scrolled as one canvas in chain order, whatever shape the tiles are arranged in. A Tile whose accelerometer reports a rotation (left, right or upside down) is remapped; FaceUp and FaceDown are not.

Custom Themes

Create Branded Theme

from lifx import HSBK, Theme, discover, DeviceGroup

# Create corporate branding theme
corporate_theme = Theme([
    HSBK(hue=220, saturation=0.8, brightness=0.9, kelvin=4000),  # Professional blue
    HSBK(hue=0, saturation=0.7, brightness=0.8, kelvin=4000),     # Corporate red
    HSBK(hue=200, saturation=0.5, brightness=0.7, kelvin=4000),   # Light blue
])

devices = []
async for device in discover():
    devices.append(device)
group = DeviceGroup(devices)

await group.apply_theme(corporate_theme)

Sunset Gradient

from lifx import HSBK, Theme, discover, DeviceGroup

# Create sunset-inspired gradient
sunset_theme = Theme([
    HSBK(hue=45, saturation=1.0, brightness=1.0, kelvin=3000),   # Orange
    HSBK(hue=15, saturation=0.9, brightness=0.9, kelvin=2700),   # Deep orange
    HSBK(hue=0, saturation=0.8, brightness=0.8, kelvin=2500),    # Red
    HSBK(hue=320, saturation=0.7, brightness=0.7, kelvin=2400),  # Deep red
])

devices = []
async for device in discover():
    devices.append(device)
group = DeviceGroup(devices)

await group.apply_theme(sunset_theme, duration=3.0)

Error Handling

Robust Theme Application

from lifx import discover, DeviceGroup, ThemeLibrary, LifxTimeoutError, LifxDeviceNotFoundError

async def safe_apply_theme(theme_name: str):
    """Apply theme with comprehensive error handling."""
    try:
        # Validate theme exists
        theme = ThemeLibrary.get(theme_name)
    except KeyError as e:
        print(f"Theme error: {e}")
        return False

    try:
        devices = []
        async for device in discover():
            devices.append(device)
        group = DeviceGroup(devices)

        if not group.devices:
            print("No lights found")
            return False

        await group.apply_theme(theme, power_on=True, duration=1.5)
        print(f"Successfully applied '{theme_name}' theme")
        return True

    except LifxTimeoutError:
        print("Timeout: Devices did not respond in time")
        return False
    except LifxDeviceNotFoundError:
        print("Device error: Could not reach device")
        return False
    except Exception as e:
        print(f"Unexpected error: {e}")
        return False

Performance Tips

Batch Operations

When applying themes to many devices, use DeviceGroup.apply_theme() for concurrent execution:

from lifx import discover, DeviceGroup, ThemeLibrary

devices = []
async for device in discover():
    devices.append(device)
group = DeviceGroup(devices)

theme = ThemeLibrary.get("evening")
# All devices updated concurrently
await group.apply_theme(theme)

Avoid Rapid Transitions

from lifx import discover, DeviceGroup, ThemeLibrary
import asyncio

devices = []
async for device in discover():
    devices.append(device)
group = DeviceGroup(devices)

themes = ["evening", "relaxing", "peaceful"]

for theme_name in themes:
    theme = ThemeLibrary.get(theme_name)
    await group.apply_theme(theme, duration=2.0)
    # Wait for transition to complete
    await asyncio.sleep(2.5)

See Also