Skip to content

Configuration File

Configure the emulator using a YAML file instead of command-line arguments

The LIFX Emulator supports YAML configuration files for persistent, reproducible setups. This is especially useful for complex configurations, team sharing, and CI/CD pipelines.

Overview

Configuration files allow you to:

  • Define complex device setups once and reuse them
  • Share configurations across team members
  • Version control your emulator settings
  • Simplify CI/CD pipeline configuration
  • Create named devices with specific product IDs

Quick Start

Create a file named lifx-emulator.yaml in your current directory:

# lifx-emulator.yaml
api: true
verbose: true
color: 2
multizone: 1

Then simply run:

lifx-emulator

The emulator automatically detects and loads the configuration file.

Config File Resolution

The emulator looks for configuration in this order (first match wins):

  1. --config flag - Explicit path to a config file
  2. LIFX_EMULATOR_CONFIG environment variable - Path from environment
  3. Auto-detection - lifx-emulator.yaml or lifx-emulator.yml in the current directory

Examples

# Explicit config file
lifx-emulator --config /path/to/my-config.yaml

# Using environment variable
export LIFX_EMULATOR_CONFIG=/path/to/config.yaml
lifx-emulator

# Auto-detection (looks for lifx-emulator.yaml in current directory)
lifx-emulator

CLI Override Behavior

CLI parameters always override config file values. This allows you to use a base configuration and override specific settings:

# Config file has port: 56700, but CLI overrides it
lifx-emulator --config base.yaml --port 56701

Priority order: CLI arguments > Config file > Defaults

Configuration Options

Server Options

# IPv4 address to bind to (default: 127.0.0.1)
bind: 127.0.0.1

# UDP port for LIFX protocol (default: 56700)
port: 56700

# Enable verbose packet logging (default: false)
verbose: false

bind accepts three kinds of address:

Value Behaviour
127.0.0.1 (default) Loopback only. Binds directly; unchanged from earlier releases.
0.0.0.0 All interfaces. Binds directly and answers every peer.
A LAN address, e.g. 192.168.1.50 Selects the interface that owns the address. The emulator binds 0.0.0.0 so discovery broadcasts are received, and accepts only peers on that interface's subnets. Other peers are counted as packets_filtered.

A LAN address that is not assigned to any local interface is rejected at start-up. Unicast from peers outside the selected interface's subnets is filtered; use 0.0.0.0 if you need to answer routed traffic from other networks.

Storage & Persistence (Deprecated)

Deprecated

persistent and persistent_scenarios are deprecated and will be removed in a future release. Use device definitions with state fields and the scenarios section instead. To migrate existing persistent storage, see Migrating from Persistent Storage.

# DEPRECATED: Use device definitions with state fields instead
# persistent: false

# DEPRECATED: Use the scenarios section instead
# persistent_scenarios: false

HTTP API Server

# Enable HTTP API server (default: false)
api: true

# API server bind address (default: 127.0.0.1)
api_host: 127.0.0.1

# API server port (default: 8080)
api_port: 8080

# Enable activity logging - last 100 packets (default: true)
api_activity: true

Device Creation by Product ID

Create devices using specific product IDs from the LIFX registry:

# List of product IDs to create
products:
  - 27   # LIFX A19
  - 38   # LIFX Beam
  - 55   # LIFX Tile

Finding Product IDs

Run lifx-emulator list-products to see all available products and their IDs.

No devices are created by default. Use products, color, or other device type fields to specify which devices to create.

Device Creation by Type

Create devices by category:

# Number of color lights - LIFX A19 (default: 0)
color: 1

# Number of color temperature lights - LIFX Mini White to Warm (default: 0)
color_temperature: 0

# Number of infrared lights - LIFX A19 Night Vision (default: 0)
infrared: 0

# Number of HEV/Clean lights - LIFX Clean (default: 0)
hev: 0

# Number of multizone devices - strips/beams (default: 0)
multizone: 0

# Number of tile devices - LIFX Tile (default: 0)
tile: 0

# Number of LIFX Switch devices - relay-based (default: 0)
switch: 0

Multizone Options

# Number of zones per multizone device
# Default: uses product defaults (16 for Z, 80 for Beam)
multizone_zones: 24

# Enable extended multizone support (default: true)
# true: Creates LIFX Beam with firmware 3.70
# false: Creates LIFX Z with firmware 2.60
multizone_extended: true

Tile/Matrix Options

# Number of tiles on each LIFX Tile chain (1 to 5)
# Default: uses product defaults (5 for LIFX Tile)
tile_count: 5

Deprecated: tile_width and tile_height

Every matrix product has a fixed tile size (the LIFX Tile is always 8x8), so the top-level and per-device tile_width/tile_height keys are accepted but ignored, and log a deprecation warning. They will be removed in the next major release. Pick a product with the tile size you need instead, such as product_id: 201 (LIFX Ceiling 13x26", one 16x8 tile).

Serial Options

# Serial prefix - exactly 6 hex characters (default: d073d5)
serial_prefix: d073d5

# Starting serial suffix (default: 1)
# Serials are formatted as: <prefix><suffix as 6-digit hex>
serial_start: 1

Per-Device Definitions

For fine-grained control, define individual devices with the devices list:

devices:
  # Simple device with just product ID
  - product_id: 27

  # Device with full initial state
  - product_id: 27
    serial: d073d5000001
    label: "Living Room"
    power_level: 65535
    color:
      hue: 21845
      saturation: 65535
      brightness: 65535
      kelvin: 3500
    location: "Downstairs"
    group: "Lights"

  # Device using compact HSBK notation
  - product_id: 27
    label: "Kitchen"
    color: [0, 0, 32768, 4000]

  # Multizone device with per-zone colors
  - product_id: 38
    zone_count: 16
    label: "TV Backlight"
    zone_colors:
      - [0, 65535, 65535, 3500]
      - [21845, 65535, 65535, 3500]
      - [43690, 65535, 65535, 3500]

  # Infrared light with IR brightness
  - product_id: 29
    label: "Security Camera"
    infrared_brightness: 32768

  # HEV light with cycle configuration
  - product_id: 90
    label: "Bathroom"
    hev_cycle_duration: 7200
    hev_indication: true

  # Tile device with custom tile count
  - product_id: 55
    tile_count: 3
    label: "Art Display"

Device Definition Fields

Field Required Description
product_id Yes LIFX product ID from registry
serial No 12-character hex serial (e.g. d073d5000001). Auto-generated if not set.
label No Device label (max 32 characters)
power_level No Initial power level (0 = off, 65535 = on)
color No Initial HSBK color (dict or [h, s, b, k] list)
location No Location label (default Test Location). Devices sharing a label share a location identifier.
location_id No Explicit location identifier, 32 hex characters. Overrides the label-derived value.
group No Group label (default Test Group). Devices sharing a label share a group identifier.
group_id No Explicit group identifier, 32 hex characters. Overrides the label-derived value.
zone_count No Number of zones (multizone devices only)
zone_colors No List of per-zone HSBK colors (multizone devices only)
infrared_brightness No Initial IR brightness 0–65535 (infrared devices only)
hev_cycle_duration No HEV cycle duration in seconds (HEV devices only)
hev_indication No HEV indication enabled (HEV devices only)
tile_count No Number of tiles (1 to 5 for the LIFX Tile; other matrix products have exactly 1)
tile_width No Deprecated and ignored: tile size is fixed per product
tile_height No Deprecated and ignored: tile size is fixed per product

Locations and Groups

Location and group identifiers are derived from their labels: a name-based UUID (version 5) of the label under a fixed emulator namespace. Two devices configured with location: "Kitchen" therefore report the same location identifier, within one emulator, across restarts, and across separate emulator instances on the same LAN. Devices without explicit labels all share the default Test Location and Test Group, so a default fleet appears as one location and one group to a client library.

Set location_id or group_id when you need deliberate separation or deliberate sharing that the labels alone do not express:

devices:
  # Shares its location and group with every other "Kitchen"/"Downlights" device
  - product_id: 27
    location: "Kitchen"
    group: "Downlights"

  # Same labels, but a private group identifier
  - product_id: 27
    location: "Kitchen"
    group: "Downlights"
    group_id: 0123456789abcdef0123456789abcdef

A SetLocation or SetGroup packet sent to one device changes only that device and uses the identifier carried in the packet. export-config writes a location_id or group_id only when it differs from the label-derived value.

HSBK Color Format

Colors can be specified as a dict or a compact list:

# Verbose dict format
color:
  hue: 21845
  saturation: 65535
  brightness: 65535
  kelvin: 3500

# Compact list format [hue, saturation, brightness, kelvin]
color: [21845, 65535, 65535, 3500]

All values are uint16 (0–65535). Kelvin must be between 1500 and 9000.

The compact list format is especially useful for zone_colors:

zone_colors:
  - [0, 65535, 65535, 3500]       # Red
  - [21845, 65535, 65535, 3500]   # Green
  - [43690, 65535, 65535, 3500]   # Blue

Combining Device Types

You can use both devices list and device type counts (color, multizone, etc.) together. All specified devices will be created.

Example Configurations

Development Setup

# development.yaml - Full observability for development
bind: 127.0.0.1
port: 56700
verbose: true

api: true
api_port: 8080
api_activity: true

color: 2
multizone: 1
tile: 1

Testing Lab

# testing-lab.yaml - Stateful devices with initial state in config
bind: 127.0.0.1
port: 56700
api: true

devices:
  - product_id: 27
    serial: d073d5000001
    label: "Test Bulb A"
    power_level: 65535
    color: [21845, 65535, 65535, 3500]
    location: "Lab"
    group: "Test Lights"
  - product_id: 27
    serial: d073d5000002
    label: "Test Bulb B"
    location: "Lab"
    group: "Test Lights"
  - product_id: 38
    serial: d073d5000003
    zone_count: 80
    label: "Test Beam"
  - product_id: 55
    serial: d073d5000004
    tile_count: 5
    label: "Test Tiles"
  - product_id: 90
    serial: d073d5000005
    label: "Test HEV"
    hev_cycle_duration: 7200
    hev_indication: true

CI/CD Pipeline

# ci-config.yaml - Isolated configuration for CI
bind: 127.0.0.1
port: 56701  # Non-standard port to avoid conflicts

verbose: false
api: false

# Use unique serial prefix for test isolation
serial_prefix: "cafe00"

color: 1
multizone: 1

Production-like Environment

# production-like.yaml - Simulate a real home setup
bind: 0.0.0.0
port: 56700

api: true
api_host: 0.0.0.0

devices:
  # Living room
  - product_id: 27
    label: "Living Room Lamp"
    power_level: 65535
    color: [0, 0, 65535, 3500]
    location: "Living Room"
    group: "Main Lights"
  - product_id: 38
    zone_count: 40
    label: "TV Backlight"
    location: "Living Room"
    group: "Entertainment"

  # Bedroom
  - product_id: 29
    label: "Bedroom Light"
    infrared_brightness: 16384
    location: "Bedroom"
    group: "Bedroom Lights"

  # Kitchen
  - product_id: 32
    zone_count: 16
    label: "Kitchen Strip"
    location: "Kitchen"
    group: "Kitchen Lights"

  # Office
  - product_id: 55
    tile_count: 5
    label: "Office Tiles"
    location: "Office"
    group: "Office"

Multizone Testing

# multizone-test.yaml - Various multizone configurations
devices:
  # Standard LIFX Z (non-extended)
  - product_id: 32
    zone_count: 16
    label: "Z Strip 16"

  # LIFX Beam (extended)
  - product_id: 38
    zone_count: 80
    label: "Beam 80"

  # Large zone count
  - product_id: 38
    zone_count: 160
    label: "Beam 160"

Scenarios

Configure test scenarios directly in the config file. Scenarios simulate protocol edge cases such as packet loss, delays, and malformed responses. They can be set at 5 scope levels with automatic precedence resolution (device > type > location > group > global).

scenarios:
  # Global settings apply to all devices
  global:
    send_unhandled: true

  # Per-device scenarios (by serial)
  devices:
    d073d5000001:
      drop_packets:
        101: 0.5          # Drop 50% of GetColor responses
      response_delays:
        116: 0.2          # 200ms delay on GetPower responses

  # Per-type scenarios (color, multizone, matrix, hev, infrared)
  types:
    multizone:
      response_delays:
        506: 0.1          # 100ms delay on StateMultiZone

  # Per-location scenarios
  locations:
    Downstairs:
      drop_packets:
        101: 0.1          # 10% packet loss for downstairs devices

  # Per-group scenarios
  groups:
    Entertainment:
      malformed_packets:
        - 506             # Corrupt StateMultiZone for group

Scenario Fields

Field Type Description
drop_packets {packet_type: rate} Drop rate 0.0–1.0 per packet type
response_delays {packet_type: seconds} Delay before responding
malformed_packets [packet_type, ...] Send truncated/corrupted responses
invalid_field_values [packet_type, ...] Send responses with all 0xFF bytes
firmware_version [major, minor] Override the version reported in StateHostFirmware
partial_responses [packet_type, ...] Send incomplete multizone/tile data
send_unhandled bool Send StateUnhandled for unknown packets

Replaces --persistent-scenarios

Config file scenarios replace the deprecated --persistent-scenarios flag. Use lifx-emulator export-config to migrate existing persistent scenarios.

Migrating from Persistent Storage

If you have been using --persistent or --persistent-scenarios, you can migrate your saved state to a config file using the export-config command:

# Export saved device state and scenarios to a config file
lifx-emulator export-config --output my-config.yaml

# Export without scenarios
lifx-emulator export-config --no-scenarios --output devices-only.yaml

# Export from a custom storage directory
lifx-emulator export-config --storage-dir /path/to/storage --output config.yaml

# Print to stdout for inspection
lifx-emulator export-config

The exported config file includes all device state (serial, label, power, color, location, group, zone colors, infrared, HEV settings) and scenario configurations. You can then use this file instead of --persistent:

# Before (deprecated)
lifx-emulator --persistent

# After (recommended)
lifx-emulator --config my-config.yaml

Validation

The configuration file is validated on load. Invalid configurations will produce clear error messages:

$ lifx-emulator --config invalid.yaml
Error loading config file invalid.yaml: serial_prefix must be exactly 6 hex characters

Common Validation Rules

  • serial_prefix must be exactly 6 hexadecimal characters
  • product_id in device definitions must be a valid LIFX product ID
  • Unknown fields are rejected (typo protection)
  • Type mismatches produce clear errors

Environment Variable

Set LIFX_EMULATOR_CONFIG to automatically load a config file:

# In your shell profile (~/.bashrc, ~/.zshrc, etc.)
export LIFX_EMULATOR_CONFIG="$HOME/.config/lifx-emulator/default.yaml"

# Now just run without arguments
lifx-emulator

This is useful for:

  • Personal default configurations
  • Team-wide standard setups
  • Container environments

Best Practices

  1. Version control your configs - Store configuration files in your project repository
  2. Use meaningful device labels - Makes debugging and testing easier
  3. Separate configs by purpose - Development, testing, CI/CD, etc.
  4. Use environment variable for defaults - Set LIFX_EMULATOR_CONFIG for your preferred setup
  5. Override with CLI for one-off changes - Don't modify config files for temporary adjustments
  6. Use the devices list for named devices - Define individual devices with labels and specific configurations

Troubleshooting

Config File Not Loading

  1. Check the file exists and is readable
  2. Verify YAML syntax: python -c "import yaml; yaml.safe_load(open('config.yaml'))"
  3. Check for typos in field names (unknown fields are rejected)
  4. Ensure the file is in the current directory for auto-detection

Unexpected Device Count

Device type counts (color, multizone, etc.) are added to the devices list, not replaced by it. If you only want the devices in your devices list, don't set any type counts:

devices:
  - product_id: 27
    label: "My Only Light"

Serial Conflicts

If you're running multiple emulator instances, use different serial prefixes:

# Instance 1
serial_prefix: "aaa000"

# Instance 2
serial_prefix: "bbb000"

Next Steps