Skip to content

ChimeraFX Light Platform

The ChimeraFX Light Platform (cfx_light) is a custom ESPHome light component specifically designed to be the ultimate companion for ChimeraFX.

Hardware & Driver Architecture

cfx_light is an asynchronous DMA driver built directly on native ESP-IDF peripherals. Here is what that means in practice:

  • Framework-agnostic RMT backend. Whether you compile with ESP-IDF or Arduino, cfx_light drives the ESP32's RMT (Remote Control) peripheral directly via IDF drivers — fire-and-forget DMA transmissions regardless of your framework choice.
  • 1-wire NRZ strips (WS2812X, SK6812, WS2811) are driven via RMT at a hardware-locked 800 kHz. Timing is generated by a custom engine to guarantee 1:1 color accuracy and zero-flicker output.
  • 2-wire SPI strips (APA102, SK9822) are driven via the SPI Master peripheral at configurable speeds (typically 10–20 MHz+), bypassing the NRZ physical bottleneck entirely. The bottleneck shifts to CPU math — see Performance & Troubleshooting for details.
  • Chipset-aware defaults. cfx_light selects the correct byte order, RGBW protocol width, and RMT symbol allocation automatically based on your declared chipset.

If your strip uses standard 800 kbps NRZ timing but is not on the supported list, WS2812X is a reliable drop-in. For unlisted SPI strips, try APA102.

Node limits for V1.41: A ChimeraFX node must be either RMT-only or SPI-only. Mixed RMT + SPI cfx_light entries are rejected at compile time because sustained SPI transfers can disturb RMT timing on tested ESP32 Classic hardware. ESP32 Classic supports up to 4 RMT outputs or 2 SPI outputs per node; ESP32-S3 supports up to 2 RMT outputs or 2 SPI outputs; ESP32-C3 supports either 1 experimental RMT output or 1 experimental SPI output. Each cfx_light can define up to 4 segments.

Tested LED Limits

The limits below are based on physical testing for ChimeraFX V1.41 using the Energy effect at default values, chosen because it is one of the heavier calculation loads in the library. Treat the recommended range as the target for smooth real-world installations, the tested range as validated on the current rig, and the stress range as useful engineering data rather than a deployment target. When validating your own rig, use LedFPS as the visible strip-refresh metric; RenderFPS only measures effect calculation speed.

Platform Transport Recommended smooth limit Tested stable limit Stress result
ESP32 Classic RMT / 1-wire NRZ 360 LEDs per GPIO for ~60 LedFPS 600 LEDs per GPIO for 30+ LedFPS 1100 LEDs per GPIO on 4 outputs runs, but visible refresh drops to roughly 16-18 LedFPS
ESP32 Classic SPI / APA102-SK9822 Up to 2000 LEDs per SPI output 2x2000 LEDs, smooth on the test rig Pending larger stress test
ESP32-C3 RMT / 1-wire NRZ Experimental: 360 LEDs on 1 output at ~60 LedFPS 600 LEDs on 1 output for 30+ LedFPS Pending larger stress test
ESP32-C3 SPI / APA102-SK9822 Up to 2000 LEDs on 1 SPI output 2000 virtual LEDs at ~60 LedFPS Pending larger stress test
ESP32-S3 RMT / 1-wire NRZ 2 RMT outputs max. Constrained by 192-symbol limit. 2x600 SK6812/RGBW at roughly ~40 LedFPS Pending larger stress test
ESP32-S3 SPI / APA102-SK9822 Up to 2000 LEDs per SPI output Pending long-strip physical retest Pending larger stress test

For 60 LED/m strips, the tested ESP32 Classic RMT guidance translates to about 24 meters total at ~60 LedFPS with 4x360 LEDs, or about 40 meters total at 30+ LedFPS with 4x600 LEDs.

ESP32-C3 RMT is intentionally marked experimental. After C3-specific RMT tuning plus Energy optimization, one RMT output can run the reference Energy effect cleanly at the limits above. Two 600-LED RMT outputs still overload the C3 RMT path and are not part of the V1.41 recommended configuration.

ESP32-S3 RMT Limitation: V1.41 is heavily constrained by the S3’s smaller RMT symbol pool (just 192 symbols, managed in 48-symbol blocks, compared to the Classic's 512 symbols). Only the first RMT output utilizes the GDMA lane, providing the best timing margin. While the hardware can theoretically support more, additional outputs fall back to non-DMA transmission, which leads to flickering or artifacts at high LED counts. Testing showed 2 RMT outputs are release-grade. 3 or 4 RMT outputs are not realistically possible on ESP32-S3 for production deployments. A high-performance parallel LED driver is currently in development to address this hardware constraint in a future release.

For the timing details behind these numbers, see Performance & Troubleshooting.

Why use cfx_light?

  1. Auto-injection (all_effects): The biggest feature! By default, cfx_light will automatically parse and inject all ChimeraFX effects into your device at compile time. No more !include macros, and no more bloated YAML files with hundreds of lines of effect blocks. You can disable this feature by setting all_effects: false.
  2. Chipset-Aware Intelligence: Native understanding of the strip's timing requirements.
  3. Optimized RMT Symbols Allocation: ESPHome's standard RMT driver occasionally struggles with symbol buffering on different chips (like S3 vs Classic). cfx_light tries automatically setting the optimal RMT memory boundaries for your exact silicon, eliminating the "flickering" or "data corruption" issues associated with large LED strips. Can be manually overridden with rmt_symbols.
  4. Automatic RGBW Handling: If you select SK6812, it automatically configures the 4-byte protocol and GRBW formatting without requiring manual overrides (although you can still override them if you have a weird LED strip variant).

CFX Light Configuration

# Example config for 1-wire NRZ strips (WS2812X, SK6812, WS2811):
light:
  - platform: cfx_light
    name: "LED Strip RMT"
    id: led_strip_rmt
    pin: GPIO16
    num_leds: 120
    chipset: WS2812X

# RMT strip with one extra physical sacrificial pixel near the controller:
light:
  - platform: cfx_light
    name: "LED Strip With Sacrificial Pixel"
    id: led_strip_signal
    pin: GPIO16
    num_leds: 60              # Visible LEDs only; physical strip has 61 LEDs
    chipset: WS2812X
    sacrificial_pixel: true   # First physical LED stays off and boosts signal

# Example config for 2-wire SPI strips (APA102, SK9822):
light:
  - platform: cfx_light
    name: "LED Strip SPI"
    id: led_strip_spi
    data_pin: GPIO23       # Data pin required for SPI strips
    clock_pin: GPIO18      # Clock pin required for SPI strips
    spi_speed: 10MHz       # SPI speed for SPI strips
    num_leds: 120          
    chipset: SK9822

Required Parameters

For 1-wire NRZ chipsets:

  • name (string): The name of the light in Home Assistant.
  • id (ID): The ID of the light component.
  • pin (Pin): The GPIO pin the data line of your LED strip is connected to.
  • chipset (string): The type of LED strip you are using.
  • num_leds (int): The number of visible, controllable LEDs in your strip. If sacrificial_pixel is enabled, do not include the sacrificial LED in this count.

For 2-wire SPI chipsets:

  • name (string): The name of the light in Home Assistant.
  • id (ID): The ID of the light component.
  • data_pin (Pin): The GPIO pin the data line of your LED strip is connected to.
  • clock_pin (Pin): The GPIO pin the clock line of your LED strip is connected to.
  • chipset (string): The type of LED strip you are using.
  • num_leds (int): The total number of LEDs in your strip.

Supported Chipsets

cfx_light supports both 1-wire (NRZ) and 2-wire (SPI) chipsets. It utilizes native hardware peripherals (RMT and SPI Master) to generate precise timings:

  • 1-wire NRZ: WS2812, WS2812B, WS2813, WS2815, SK6812 (RGBW), WS2811.
  • 2-wire SPI: APA102, SK9822 (beta driver).

Chipset Identification and Configuration

To use a specific chipset, use the chipset variable in your YAML:

Parameter Chipset Option Description
chipset WS2812X Standard 3-pin RGB timing (Default)
SK6812 4-byte RGBW timing (GRBW order)
WS2811 Optimized timing for WS2811 data rates
APA102 2-wire SPI timing (beta driver)
SK9822 2-wire SPI timing (beta driver)

Optional Parameters

  • all_effects (boolean, default: true): When set to true, the component will instantly register all effects. Set to false to manually register just the effects and custom presets you want to use.
  • rgb_order (string): The byte order of the colors. If omitted, cfx_light sets the standard default based on your chipset (e.g., WS2812X defaults to GRB). Options: RGB, RBG, GRB, GBR, BGR, BRG.
  • is_rgbw (boolean): Explicitly declare the strip as 4-byte RGBW. If your chipset is SK6812, this is automatically true.
  • is_wrgb (boolean, default: false): Sets the white byte position to the front of the data packet rather than the end. Required for some rare SK6812 variant clones.
  • rmt_symbols (int, default: 0): The number of RMT symbols to allocate. If left at 0, cfx_light will dynamically allocate the maximum safe bounds based on your specific ESP32 processor variant.
  • sacrificial_pixel (boolean, default: false): RMT-only option for long data-line runs. When enabled, cfx_light transmits one extra black pixel before logical LED 0. Place this extra physical LED close to the controller; it stays off, boosts the signal, and is not counted in num_leds or segment indexes.
  • spi_speed (Frequency, Optional): The SPI clock speed for APA102 and SK9822 strips. If omitted, cfx_light uses a sensible default.
  • default_transition_length (Time, default: 0s): The standard ESPHome transition duration for solid-color mode and for eligible ChimeraFX effect power OFF -> ON -> OFF transitions. Architectural effects and the signature effects Energy and Chaos Theory intentionally ignore this setting so their authored intros/outros stay untouched.
  • set_intro (int, Optional): Force a global Intro Animation for eligible effects. Architectural effects, Energy, and Chaos Theory keep their authored intros.
  • set_outro (int, Optional): Force a global Outro Animation for eligible effects. Architectural effects, Energy, and Chaos Theory keep their authored outros.
  • set_inout_dur (Time, Optional): Sets the duration for both global intros and outros.
  • set_brightness (percentage, Optional): Applies a brightness default every time the light turns on, using the same 0-100% style as ESPHome light brightness values.
  • set_color (list[int], Optional): Applies a color default every time the light turns on as [r, g, b] or [r, g, b, w] using 0-100 channel percentages (w requires a white-channel strip). This also affects single-tone effects that derive their color from the current light state. It does not force palette-driven multicolor effects to a single color.
  • controls (boolean, default: true): Automatically generate the ChimeraFX control entities for this light.
  • ctrl_exclude (list[int], Optional): Exclude specific auto-generated control groups by ID. See Controls for the control ID list.
  • segments (list, Optional): Define logical sub-zones of the strip as independent light entities, up to 4 per cfx_light. See the next chapter Segments for more details.

Segments (Multi-Zone Control)

ChimeraFX supports dividing a single physical LED strip into up to 4 independent logical segments. Each segment is exposed to Home Assistant as a separate light entity, allowing you to run different effects on different parts of the same strip simultaneously.

Segment Configuration

Segments are defined under the segments key in your cfx_light configuration.

light:
  - platform: cfx_light
    name: "Main TV Strip"
    id: tv_strip
    pin: GPIO16
    num_leds: 120
    chipset: WS2812X

    segments:
      - id: "tv_left"
        name: "TV Left Side"
        start: 0
        stop: 40
      - id: "tv_top"
        name: "TV Top"
        start: 40
        stop: 80
        mirror: true
      - id: "tv_right"
        name: "TV Right Side"
        start: 80
        stop: 120

Segment Parameters

  • id (ID, Required): A unique ESPHome id for the segment light entity.
  • name (string, Optional): The name of the light entity in Home Assistant. If omitted, the id is used.
  • start (int, Required): The starting pixel index (inclusive).
  • stop (int, Required): The stopping pixel index (exclusive).
  • mirror (boolean, default: false): If true, calculations are reversed for this segment (useful for symmetrical setups).
  • set_intro (int, Optional): Override the global intro mode for this segment on eligible effects. Architectural effects, Energy, and Chaos Theory keep their authored intros.
  • set_outro (int, Optional): Override the global outro mode for this segment on eligible effects. Architectural effects, Energy, and Chaos Theory keep their authored outros.
  • set_inout_dur (Time, Optional): Override the global intro/outro duration for this specific segment.
  • set_brightness (percentage, Optional): Applies a brightness default every time the segment turns on, using the same 0-100% style as ESPHome light brightness values.
  • set_color (list[int], Optional): Defines the default color applied when the segment turns on. Accepts [r, g, b] or [r, g, b, w] values (where w requires a white-channel strip) using 0-100 channel percentages. This setting affects solid-color mode and single-tone effects. Values can be validated via the light logs.

Master vs. Segment Behavior

When segments are defined:

  1. The "Master" light entity (e.g., "Main TV Strip") acts as a global power and brightness control. It does not have its own effects. Turning off the Master turns off all segments.

  2. Each segment light entity (e.g., "TV Left Side") has the full suite of ChimeraFX effects injected into it (unless all_effects: false is set on the main/master light).

  3. Each light segment operates on its own dedicated runner instance. This ensures that every single parameter is completely independent, allowing users to configure each segment exactly as they want.


Overriding and Customizing Effects

While all_effects: true loads all available effects automatically, you may still want to set hardcoded defaults (such as making the Aurora effect default to the Forest palette on boot). How you do this depends on whether you want to replace the original effect or create a new variation:

  • To override an effect: Manually define an addressable_cfx effect with the exact same name. Your manual override will seamlessly replace the auto-injected version.
  • To create multiple versions: If you want to keep the default effect but add custom variations, simply define the effect and give it a different name (e.g., name: "Aurora Fast"). This adds your customized preset as a completely new, separate effect.

light:
  - platform: cfx_light
    name: "Living Room Light"
    id: led_strip
    pin: GPIO16
    num_leds: 300
    chipset: WS2812X

    # We want ALL effects, but we want to customize 'Aurora'
    effects:
      - addressable_cfx:
          name: "Aurora"   # Override the default Aurora effect
          effect_id: 38
          set_palette: 2   # Force 'Forest' 
          set_speed: 50    # Make it faster (dfault is 24)

      - addressable_cfx:
          name: "Aurora Fast"
          effect_id: 38
          set_palette: 2   # Force 'Forest' 
          set_speed: 200   # Make it even faster
More on effect presets in the Effect Presets page. Effect IDs can be found in the Effects Library page.