Troubleshooting Guide¶
Common issues and solutions when working with lifx.
Table of Contents¶
Discovery Issues¶
No Devices Found¶
Symptom: discover() returns an empty group
Common Causes:
-
Devices not on same network
-
Firewall blocking UDP port 56700
-
Broadcast address incorrect
Try different broadcast addresses:
from lifx import discover, DeviceGroup
# Default (255.255.255.255)
devices = []
async for device in discover():
devices.append(device)
group = DeviceGroup(devices)
# Network-specific (e.g., 192.168.1.255)
devices = []
async for device in discover(broadcast_address="192.168.1.255"):
devices.append(device)
group = DeviceGroup(devices)
Solution:
import asyncio
from lifx.network.discovery import discover_devices
async def diagnose_discovery():
print("Attempting discovery...")
# Try with extended timeout
devices = []
async for device in discover_devices(
timeout=10.0,
broadcast_address="255.255.255.255"
):
devices.append(device)
if not devices:
print("No devices found. Check:")
print("1. Devices are powered on")
print("2. Devices are on the same network")
print("3. Firewall allows UDP port 56700")
print("4. Try a network-specific broadcast address")
else:
print(f"Found {len(devices)} devices:")
for device in devices:
print(f" - {device.serial} at {device.ip}")
asyncio.run(diagnose_discovery())
Partial Device Discovery¶
Symptom: Only some devices discovered
Causes:
- Devices on different subnets
- Network congestion
- Devices slow to respond
Solution:
A single discover_devices() call already re-broadcasts GetService on an
escalating schedule within the discovery window, so devices that miss the
first broadcast get several more chances to respond. There is no need to call
discovery multiple times.
If some devices are still missed on a slow or congested network, increase the
timeout to widen the discovery window:
Connection Problems¶
Connection Refused¶
Symptom: LifxConnectionError: Connection refused
Causes:
- Incorrect IP address
- Device powered off
- Network unreachable
Solution:
from lifx import Device, LifxConnectionError
import asyncio
async def test_connection(ip: str):
try:
async with await Device.connect(ip) as light:
label = await light.get_label()
print(f"Connected to: {label}")
return True
except LifxConnectionError as e:
print(f"Connection failed: {e}")
print("Check:")
print("1. Device IP is correct")
print("2. Device is powered on")
print("3. Device is reachable (try ping)")
return False
# Test connectivity
asyncio.run(test_connection("192.168.1.100"))
Connection Drops¶
Symptom: Intermittent LifxConnectionError or LifxNetworkError
Causes:
- WiFi signal weak
- Network congestion
- Device overloaded
Solution:
The library itself retransmits within each request's timeout, so transient packet loss is handled for you. An application-level wrapper like the one below is for retrying whole operations that failed — not for per-packet reliability.
import asyncio
from lifx import Device, LifxError
async def resilient_operation(ip: str, max_retries: int = 3):
"""Retry operations with exponential backoff"""
async with await Device.connect(ip) as light:
for attempt in range(max_retries):
try:
await light.set_power(True)
print("Success!")
return
except LifxError as e:
wait_time = 2 ** attempt # 1s, 2s, 4s
print(f"Attempt {attempt + 1} failed: {e}")
if attempt < max_retries - 1:
print(f"Retrying in {wait_time}s...")
await asyncio.sleep(wait_time)
print("All retries exhausted")
Timeout Errors¶
Request Timeouts¶
Symptom: LifxTimeoutError: Request timed out after X seconds
Causes:
- Device slow to respond
- Network latency high
- Device busy processing other requests
Solution:
from lifx import Device
# Increase timeout for slow devices
async with await Device.connect(ip, timeout=5.0) as light:
# get_color() returns (color, power, label)
color, power, label = await light.get_color()
Discovery Timeout Too Short¶
Symptom: Some devices not found
Solution:
from lifx import discover
# Increase the discovery timeout (the default is 15.0 seconds)
devices = []
async for device in discover(timeout=30.0):
devices.append(device)
print(f"Found {len(devices)} devices")
Performance Issues¶
Slow Operations¶
Symptom: Operations take longer than expected
Diagnosis:
import asyncio
import time
from lifx import Device
async def measure_latency():
async with await Device.connect("192.168.1.100") as light:
# Measure single request
start = time.time()
await light.get_label()
elapsed = time.time() - start
print(f"Single request: {elapsed*1000:.2f}ms")
# Measure sequential requests
start = time.time()
for _ in range(10):
await light.get_label()
elapsed = time.time() - start
print(f"10 sequential: {elapsed*1000:.2f}ms ({elapsed*100:.2f}ms avg)")
# Measure concurrent requests
start = time.time()
await asyncio.gather(*[light.get_label() for _ in range(10)])
elapsed = time.time() - start
print(f"10 concurrent: {elapsed*1000:.2f}ms")
Common Causes:
- Sequential instead of concurrent operations
Slow approach (sequential):
Fast approach (concurrent):
- Not reusing connections
Inefficient (creates new connection each time):
for i in range(10):
async with await Device.connect(ip) as light:
await light.set_color(HSBK(hue=(360 / 10) * i, saturation=1.0, brightness=1.0, kelvin=3500))
Efficient (reuses connection):
async with await Device.connect(ip) as light:
for i in range(10):
await light.set_color(HSBK(hue=(360 / 10) * i, saturation=1.0, brightness=1.0, kelvin=3500))
- Need fresh data?
Use get_*() methods to always fetch from the device:
# Always fetch fresh data
# get_color() returns all three values in one call
color, power, label = await light.get_color()
# Or fetch other device info
version = await light.get_version()
Gen4 Power-Save Wake Tail¶
Symptom: The first command after a device has been idle for roughly a minute or more is slower than usual — up to ~250 ms instead of the single-digit milliseconds a busy device answers in. Subsequent commands respond at full speed.
Causes:
- Gen4 devices use WiFi power-save while idle, so the radio takes a moment to wake for the first packet
- Affects gen4 devices only — gen2 and gen3 devices show no wake tail
This is a latency effect, not a reliability problem: on healthy networks, an idle device loses zero packets. Every command still succeeds; the first one after idle just takes a little longer.
Identifying gen4 devices:
Gen4 devices report a host firmware major version of 4 or later:
firmware = await device.get_host_firmware()
if firmware.version_major >= 4:
print("Gen4 device: expect a sub-250 ms wake tail after idle")
Inside async with, the cached device.host_firmware property is already
populated, so you can check device.host_firmware.version_major directly. Do
not try to identify gen4 devices by product ID — the products registry has no
generation field.
Solution:
Most applications can ignore the wake tail entirely. If your application is latency-sensitive and cannot tolerate a slower first command, an optional periodic poll keeps the device's radio awake:
import asyncio
from lifx import Light
async def keep_awake(light: Light) -> None:
"""Optional: poll periodically so a gen4 device's radio stays awake."""
while True:
# Any request works; get_color() returns colour, power and label
# in a single request/response pair.
await light.get_color()
await asyncio.sleep(15) # 10-15 s keeps the wake tail away
Run it alongside your application with asyncio.create_task() or
asyncio.TaskGroup — no extra coordination is needed, because the library
serialises requests per connection. The poll is read-only, so it is safe to
run continuously, and one request every 15 seconds stays far below the
~20 msg/sec a device can handle.
lifx-async deliberately ships no keepalive daemon
Measured on real hardware, idle devices lose zero packets on healthy networks — the wake tail is a small, bounded latency cost, not a reliability problem. Whether to spend a packet every 10–15 seconds to avoid it is the application's choice, so the library does not make it for you.
Streaming frames to a device? See the Animation Guide for how sustained streaming interacts with gen4 power-save.
Docker / Container Networking¶
Symptom: Discovery doesn't work in Docker container
Cause: Container network isolation
Solution:
Or use manual device specification:
# Don't rely on discovery
from lifx import Colors, Device
async with await Device.connect("192.168.1.100") as light:
await light.set_color(Colors.BLUE)
Debugging Tips¶
Enable Debug Logging¶
import logging
# Enable DEBUG logging for lifx
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Or for specific modules
logging.getLogger('lifx.network').setLevel(logging.DEBUG)
logging.getLogger('lifx.devices').setLevel(logging.DEBUG)
Check Product Registry¶
from lifx.products import get_product, get_registry
# Check how many products the registry knows
registry = get_registry()
print(f"Registry contains {len(registry)} products")
# Check specific product
product = get_product(27) # LIFX A19
if product:
print(f"Name: {product.name}")
print(f"Capabilities: {product.capabilities}")
Verify Device Reachability¶
# Ping device
ping 192.168.1.100
# Check UDP port (requires nmap)
sudo nmap -sU -p 56700 192.168.1.100
# Test with netcat
echo -n "test" | nc -u 192.168.1.100 56700
Getting Help¶
If you're still experiencing issues:
- Check GitHub Issues: github.com/Djelibeybi/lifx-async/issues
- Enable debug logging: Capture logs with
logging.DEBUG - Provide details:
- Python version
- lifx version
- Device model and firmware version
- Network configuration
- Minimal reproduction code
- Full error traceback
Common Error Messages¶
| Error | Meaning | Solution |
|---|---|---|
LifxTimeoutError |
Device didn't respond | Increase timeout, check network |
LifxConnectionError |
Can't connect to device | Check IP, firewall, device power |
LifxDeviceNotFoundError |
Device not discovered | Check network, increase timeout |
LifxProtocolError |
Invalid response | Update firmware, check device type |
LifxUnsupportedCommandError |
Device doesn't support command | Check device capabilities |
AttributeError: 'Light' has no attribute 'set_color_zones' |
Wrong device class | Use MultiZoneLight |
Next Steps¶
- Effects Troubleshooting — Issues specific to the effects framework
- Advanced Usage — Optimisation patterns
- API Reference — Complete API documentation
- FAQ — Frequently asked questions