> For the complete documentation index, see [llms.txt](https://klipper.3dwork.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://klipper.3dwork.io/klipper/mejoras/neopixel.md).

# Neopixel

Klipper tiene soporte nativo para tiras LED inteligentes WS2812/SK6812 (Neopixel) y APA102/SK9822 (Dotstar), más integración con WLED y LUMEN a través de Moonraker. Con esto puedes iluminar el cerramiento, mostrar el progreso de impresión en tiempo real con colores, animar el toolhead o simplemente saber de un vistazo en qué estado está la máquina.

{% hint style="info" %}
Esta guía cubre las tres opciones de conexión de menos a más avanzada. Si ya tienes los LEDs funcionando y solo buscas efectos, salta a [LED Effects](#led-effects-efectos-avanzados) o a la sección de [hardware externo](#opcion-2-hardware-externo-o-segunda-mcu).
{% endhint %}

## Dónde conseguir tiras LED Neopixel

{% tabs %}
{% tab title="WS2812B 5V (más común)" %}
{% embed url="<https://s.click.aliexpress.com/e/182731559?productUrl=https://www.aliexpress.com/item/2036819167.html>" %}
{% endtab %}

{% tab title="SK6812 RGBW 5V" %}
{% embed url="<https://s.click.aliexpress.com/e/182731559?productUrl=https://www.aliexpress.com/item/32742461421.html>" %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Si utilizas los links de compra, el precio del producto será el mismo que si accedes de manera habitual, pero a 3DWork le quedará una pequeña comisión. Algo que nos ayudará a soportar el proyecto y continuar generando contenido.
{% endhint %}

## Antes de conectar — instalación física

{% hint style="danger" %}
**Puntos críticos antes de conectar cualquier tira LED:**

* Añade una **resistencia de 300-500 Ω** entre el pin de señal de la MCU y el pin de datos de la tira. Protege la MCU de picos en el bus de datos. Sin ella puedes quemar el pin.
* Las tiras tienen **dirección** — la alimentación y la señal van en el sentido de la flecha marcada en la PCB.

  <figure><img src="/files/8tmY5SPtW6o3ON1wFir4" alt="Dirección de la tira LED"><figcaption></figcaption></figure>
* **Alimenta externamente** con una fuente 5V dedicada si tienes más de 15-20 LEDs. La mayoría de electrónicas (SKR, Octopus, Manta) solo aguantan eso antes de necesitar corriente extra. Superar el límite provoca reinicios aleatorios de la MCU.
* **GND común obligatorio** — conecta el GND de la tira y el GND de la MCU al mismo punto. Sin esto la señal de datos no llega bien y los LEDs hacen cosas raras.
* Para calcular el consumo exacto: [WLED Power Calculator](https://wled-calculator.github.io/)
  {% endhint %}

### Tipos de LED y su `color_order`

Este parámetro es el origen de la mayoría de problemas con colores incorrectos. Cada tipo de LED envía los bytes de color en un orden distinto:

| LED                | Protocolo                | `color_order` | Notas                                |
| ------------------ | ------------------------ | ------------- | ------------------------------------ |
| WS2812B            | 1 cable (datos)          | `GRB`         | El más común en impresoras 3D        |
| WS2812B con blanco | 1 cable (datos)          | `GRBW`        | 4 canales                            |
| SK6812 RGBW        | 1 cable (datos)          | `GRBW`        | Muy usado en tiras de cerramiento    |
| SK6812 RGB         | 1 cable (datos)          | `GRB`         | Sin canal blanco                     |
| APA102 / SK9822    | 2 cables (datos + reloj) | `BGR`         | Más robusto, mejor para tiras largas |
| Dotstar (Adafruit) | 2 cables (datos + reloj) | `BGR`         | Mismo chip que APA102                |
| WS2811             | 1 cable (datos)          | `RGB`         | Cuidado: orden diferente al WS2812   |

Si pides rojo y salen verdes, o azul y salen otra cosa, el problema es el `color_order`. Prueba los valores hasta que los colores sean correctos.

{% hint style="info" %}
También puedes especificar un `color_order` diferente para cada LED de la cadena si mezclas tipos distintos: `color_order: GRB, GRB, GRBW`
{% endhint %}

***

## Opción 1 — Conexión a la MCU principal

La forma más directa: conectar la tira al pin RGB de tu electrónica (Octopus, SKR, Manta…) y dejar que Klipper la gestione. Sin hardware extra, configuración en `printer.cfg` y control total desde macros y LED Effects.

{% hint style="warning" %}
Klipper **no soporta Neopixel conectados directamente a los GPIO de la Raspberry Pi** cuando se usa como Linux MCU. El kernel de Linux no tiene la precisión de temporización necesaria para el protocolo WS2812. Si quieres usar los GPIO de la Pi, ve a la sección [LUMEN](#lumen-plugin-moonraker-para-raspberry-pi) o [Segunda MCU RP2040](#segunda-mcu-rp2040-pi-pico).
{% endhint %}

### Configuración en printer.cfg

Lo más limpio es crear un archivo separado `led_effects.cfg` y referenciarlo desde `printer.cfg`:

```ini
# En printer.cfg
[include led_effects.cfg]
```

Así mantienes el cfg principal ordenado y puedes tocar la configuración de LEDs sin tocar el resto.

{% tabs %}
{% tab title="WS2812 / Neopixel" %}
El más común en impresoras 3D. Un único cable de datos, protocolo de 1 hilo.

```ini
[neopixel mi_tira_led]
pin: PA1                  # Pin de datos — ajusta a tu electrónica
chain_count: 15           # Número de LEDs en la tira
color_order: GRB          # Estándar WS2812B — cambia si los colores salen mal
initial_RED: 0.5
initial_GREEN: 0.5
initial_BLUE: 0.5
initial_WHITE: 0.0        # Solo para LEDs RGBW
```

{% endtab %}

{% tab title="SK6812 RGBW" %}
Añade un cuarto canal blanco dedicado. Ideal para iluminación de cámara o cerramiento donde buscas luz neutra.

```ini
[neopixel mi_tira_rgbw]
pin: PB0
chain_count: 20
color_order: GRBW
initial_RED: 0.0
initial_GREEN: 0.0
initial_BLUE: 0.0
initial_WHITE: 0.8        # El canal blanco da una iluminación neutra muy limpia
```

{% endtab %}

{% tab title="APA102 / Dotstar" %}
Usa dos cables (datos + reloj), lo que los hace prácticamente inmunes a interferencias. La mejor opción para tiras largas o entornos con ruido eléctrico (motores, fuentes baratas). Más caros que los WS2812 pero mucho más estables.

```ini
[dotstar mi_dotstar]
data_pin: PA3             # Pin de datos
clock_pin: PA4            # Pin de reloj — exclusivo de Dotstar/APA102
chain_count: 30
color_order: BGR
initial_RED: 0.3
initial_GREEN: 0.3
initial_BLUE: 0.3
```

{% endtab %}
{% endtabs %}

### Pines LED en electrónicas BTT habituales

| Electrónica               | Conector   | Pin Klipper |
| ------------------------- | ---------- | ----------- |
| BTT Octopus v1.x          | RGB header | `PB0`       |
| BTT Manta M4P / M5P / M8P | RGB1       | `PD0`       |
| BTT SKR 3                 | RGB        | `PE2`       |
| BTT SKR Mini E3 v3        | Neopixel   | `PC7`       |

{% hint style="warning" %}
Los manuales de BTT a veces tienen errores en los pines de los conectores RGB. Si el pin no funciona, prueba el alternativo (`PD1` en lugar de `PD0`, etc.) o consulta el esquema del repositorio de BTT en GitHub.
{% endhint %}

### virtual\_leds — segmentar una tira en zonas lógicas

`[virtual_leds]` permite dividir una tira física en segmentos independientes y controlar cada zona por separado. Muy útil en configuraciones como el Stealthburner (logo + nozzle en la misma cadena) o cualquier tira que quieras controlar por zonas.

```ini
[neopixel toolhead_leds]
pin: nhk:gpio7
chain_count: 3
color_order: GRB
initial_RED: 0.0
initial_GREEN: 0.0
initial_BLUE: 0.0

# Segmento 1: LED del logo (LED nº 1 de la cadena)
[virtual_leds logo_leds]
leds: neopixel:toolhead_leds (1)

# Segmento 2: LEDs del nozzle (LEDs 2 y 3)
[virtual_leds nozzle_leds]
leds: neopixel:toolhead_leds (2, 3)
```

Ahora puedes usar `logo_leds` y `nozzle_leds` de forma independiente en tus efectos y macros, aunque físicamente sean la misma tira.

### Comandos SET\_LED y SET\_LED\_TEMPLATE

#### SET\_LED — cambio directo de color

```gcode
# Cambiar todos los LEDs de la tira
SET_LED LED=mi_tira_led RED=0.5 GREEN=0.0 BLUE=0.0

# Cambiar un LED específico (INDEX empieza en 1)
SET_LED LED=mi_tira_led RED=1.0 GREEN=0.0 BLUE=0.0 INDEX=1

# Apagar todos
SET_LED LED=mi_tira_led RED=0 GREEN=0 BLUE=0

# Actualizar varios LEDs de golpe sin parpadeos intermedios
# TRANSMIT=0 acumula el cambio sin enviarlo; TRANSMIT=1 (el último) envía todo junto
SET_LED LED=mi_tira_led RED=1.0 INDEX=1 TRANSMIT=0
SET_LED LED=mi_tira_led GREEN=1.0 INDEX=2 TRANSMIT=0
SET_LED LED=mi_tira_led BLUE=1.0 INDEX=3 TRANSMIT=1
```

| Parámetro                       | Descripción                                                        |
| ------------------------------- | ------------------------------------------------------------------ |
| `LED`                           | Nombre del `[neopixel]`, `[dotstar]` o `[virtual_leds]`            |
| `RED`, `GREEN`, `BLUE`, `WHITE` | Intensidad del canal (0.0 a 1.0)                                   |
| `INDEX`                         | Número de LED en la cadena (1 = primero). Sin INDEX aplica a todos |
| `TRANSMIT`                      | `0` = acumula sin enviar, `1` = envía todo (por defecto 1)         |
| `SYNC`                          | `0` = no espera a que termine el movimiento anterior               |

#### SET\_LED\_TEMPLATE — plantillas dinámicas

`SET_LED_TEMPLATE` asigna un template de display a los LEDs, de modo que el color se actualiza automáticamente en tiempo real según el estado de la impresora. Ideal para barras de progreso o indicadores de temperatura.

```gcode
# Asignar una plantilla al LED
SET_LED_TEMPLATE LED=mi_tira_led TEMPLATE=nombre_template

# Quitar la plantilla y volver a control manual
SET_LED_TEMPLATE LED=mi_tira_led TEMPLATE=""
SET_LED LED=mi_tira_led RED=0 GREEN=0 BLUE=0
```

Ejemplo de plantilla — barra de progreso de impresión:

```ini
[display_template led_progress]
param_led_num: 0
param_led_total: 1
text:
  {% set ratio = printer.display_status.progress %}
  {% set led_ratio = param_led_num|float / param_led_total %}
  {% if ratio > led_ratio %}
    0.0, 0.5, 1.0, 0.0
  {% else %}
    0.0, 0.0, 0.05, 0.0
  {% endif %}
```

Para aplicarla a cada LED de la tira:

```ini
[gcode_macro LEDS_PROGRESS]
gcode:
  {% set leds_count = printer["neopixel mi_tira_led"].chain_count|int %}
  {% for i in range(1, leds_count + 1) %}
    SET_LED_TEMPLATE LED=mi_tira_led TEMPLATE=led_progress param_led_num={i} param_led_total={leds_count} INDEX={i} TRANSMIT={ 1 if i == leds_count else 0 }
  {% endfor %}
```

### Macros para el ciclo de impresión

El set mínimo que vale la pena tener configurado:

```ini
# ─── Iluminación básica ─────────────────────────────────────────────────────

[gcode_macro LEDS_OFF]
description: Apagar todos los LEDs
gcode:
    SET_LED LED=mi_tira_led RED=0 GREEN=0 BLUE=0 WHITE=0

[gcode_macro LEDS_ON]
description: Iluminación blanca para cámara
gcode:
    SET_LED LED=mi_tira_led RED=1.0 GREEN=1.0 BLUE=1.0

# ─── Estados de impresión ───────────────────────────────────────────────────

[gcode_macro LEDS_HEATING]
description: Naranja — calentando hotend/cama
gcode:
    SET_LED LED=mi_tira_led RED=1.0 GREEN=0.3 BLUE=0.0

[gcode_macro LEDS_LEVELING]
description: Azul — nivelando/mesh
gcode:
    SET_LED LED=mi_tira_led RED=0.0 GREEN=0.2 BLUE=1.0

[gcode_macro LEDS_PRINTING]
description: Verde suave — imprimiendo
gcode:
    SET_LED LED=mi_tira_led RED=0.0 GREEN=0.8 BLUE=0.2

[gcode_macro LEDS_DONE]
description: Verde brillante — impresión finalizada
gcode:
    SET_LED LED=mi_tira_led RED=0.0 GREEN=1.0 BLUE=0.0

[gcode_macro LEDS_ERROR]
description: Rojo — error o pausa por filamento
gcode:
    SET_LED LED=mi_tira_led RED=1.0 GREEN=0.0 BLUE=0.0

[gcode_macro LEDS_PAUSED]
description: Amarillo — impresión pausada
gcode:
    SET_LED LED=mi_tira_led RED=1.0 GREEN=0.8 BLUE=0.0
```

Intégralas en `PRINT_START` y `PRINT_END`:

```ini
[gcode_macro PRINT_START]
gcode:
    LEDS_HEATING
    # ... calentar cama y hotend ...
    LEDS_LEVELING
    # ... home + mesh ...
    LEDS_PRINTING
    # ... purga e inicio de impresión ...

[gcode_macro PRINT_END]
gcode:
    # ... retract, park ...
    LEDS_DONE
```

### Control desde Mainsail y Fluidd

Las tiras `[neopixel]` y `[dotstar]` gestionadas directamente por Klipper aparecen automáticamente en el panel web bajo **Dashboard → Miscellaneous**:

![](/files/jpTCl0TtR8TWP3vlFtee) ![](/files/U3fRhaM2iETMnKVXlnt9)

Desde ahí puedes cambiar los colores manualmente con sliders sin necesidad de macros.

{% hint style="info" %}
Los LEDs controlados por WLED, LUMEN o LED Effects **no aparecen** en Miscellaneous. Se controlan únicamente a través de macros G-code.
{% endhint %}

### LED Effects — efectos avanzados

[**klipper-led\_effect**](https://github.com/julianschill/klipper-led_effect) añade efectos dinámicos a los LEDs gestionados por Klipper: breathing, chasing, progress bar, temperatura en tiempo real, reacción a errores, arco iris, y muchos más. Es lo que usan la mayoría de configuraciones de Voron y similares.

#### Instalación

```bash
cd ~
git clone https://github.com/julianschill/klipper-led_effect.git
cd klipper-led_effect
./install-led_effect.sh
```

Si tu instalación está en rutas no estándar:

```bash
./install-led_effect.sh [-k <klipper path>] [-s <klipper service name>] [-c <config path>]
```

Añade esto en `moonraker.conf` para recibir actualizaciones automáticas:

```ini
[update_manager led_effect]
type: git_repo
path: ~/klipper-led_effect
origin: https://github.com/julianschill/klipper-led_effect.git
primary_branch: master
is_system_service: False
```

{% hint style="success" %}
El repositorio incluye una **app de escritorio** (Windows y Mac) para simular efectos antes de aplicarlos a la impresora. Descárgala desde [Releases → Assets](https://github.com/julianschill/klipper-led_effect/releases). Ahorra mucho tiempo de prueba y error.

<img src="/files/O1rmkJGU26e2BDyqO5q9" alt="" data-size="original">
{% endhint %}

#### Controlar los efectos

```gcode
# Activar un efecto
SET_LED_EFFECT EFFECT=nombre_efecto

# Activar con fade-in de 1 segundo
SET_LED_EFFECT EFFECT=nombre_efecto FADETIME=1.0

# Parar un efecto concreto
SET_LED_EFFECT EFFECT=nombre_efecto STOP=1

# Parar todos los efectos activos
STOP_LED_EFFECTS
```

#### Estructura de `[led_effect]`

```ini
[led_effect nombre_efecto]
leds:
    neopixel:mi_tira_led              # Toda la tira
    neopixel:mi_tira_led (1-8)        # LEDs 1 a 8
    neopixel:mi_tira_led (9-16)       # LEDs 9 a 16
    virtual_leds:logo_leds            # Segmento virtual
    dotstar:mi_dotstar (1,3,5)        # LEDs específicos
autostart: true                       # Activar al arrancar Klipper
frame_rate: 24                        # Fotogramas/segundo
heater: extruder                      # Vincular a temperatura de un heater
run_on_error: false                   # Solo se activa en estado de error crítico
layers:
    # tipo     vel  ciclos  mezcla  (R,G,B) o (R,G,B,W)
    breathing  10   1       top     (0.5, 0.5, 1.0)
```

**Parámetros de capa:**

| Parámetro      | Descripción                                                                |
| -------------- | -------------------------------------------------------------------------- |
| `autostart`    | `true` activa el efecto al iniciar Klipper                                 |
| `frame_rate`   | FPS de actualización. 24 es suficiente para casi todo                      |
| `heater`       | Vincula el efecto a la temperatura de un heater (`extruder`, `heater_bed`) |
| `analog_pin`   | Vincula el efecto al valor de un pin analógico                             |
| `stepper`      | Vincula el efecto al estado de un stepper                                  |
| `run_on_error` | Si `true`, solo activo en estado de error de Klipper                       |

Para la referencia completa de tipos de capa y parámetros: [documentación oficial del plugin](https://github.com/julianschill/klipper-led_effect/blob/master/docs/LED_Effect.md#defining-effect-layers).

#### Ejemplos de efectos

**Breathing — respiración suave, ideal para idle:**

```ini
[led_effect leds_idle]
autostart: true
frame_rate: 24
leds:
    neopixel:mi_tira_led
layers:
    breathing  10  1  top  (0.2, 0.2, 0.8)
```

**Temperatura del nozzle en tiempo real** — azul frío → rojo caliente:

```ini
[led_effect temperatura_nozzle]
leds:
    neopixel:mi_tira_led
autostart: true
frame_rate: 24
heater: extruder
layers:
    heater  50  0  add   (1.0, 0.0, 0.0), (0.0, 0.0, 1.0)
```

**Barra de progreso de impresión:**

```ini
[led_effect barra_progreso]
leds:
    neopixel:mi_tira_led
autostart: false
frame_rate: 24
layers:
    progress  -1  0  add   (0.0, 0.0, 1.0), (0.0, 0.1, 0.6)
    static     0  0  top   (0.0, 0.0, 0.05)
```

**Arco iris continuo:**

```ini
[led_effect rainbow]
leds:
    neopixel:mi_tira_led
autostart: false
frame_rate: 24
layers:
    gradient  0.3  1  add  (0.3, 0.0, 0.0),(0.0, 0.3, 0.0),(0.0, 0.0, 0.3)
```

**Error crítico — rojo parpadeante (se activa automáticamente):**

```ini
[led_effect error_critico]
leds:
    neopixel:mi_tira_led
layers:
    strobe     1  1.5  add         (1.0, 1.0, 1.0)
    breathing  2  0    difference  (0.95, 0.0, 0.0)
    static     1  0    top         (1.0, 0.0, 0.0)
autostart: false
frame_rate: 24
run_on_error: true
```

**Comet / persecución:**

```ini
[led_effect loading]
leds:
    neopixel:mi_tira_led
autostart: false
frame_rate: 24
layers:
    comet  0.3  0  add  (0.0, 0.0, 1.0)
```

***

## LEDs en el toolhead — Stealthburner y similares

Si tienes un cabezal Voron Stealthburner (o cualquier toolhead con LEDs en el hotend), puedes usar el script de post-procesado de JJR para que los LEDs cambien de color según el tipo de trazada que está imprimiendo: perímetros, relleno, soporte, etc.

{% embed url="<https://gist.github.com/alienboyxp/9a79cd50d2526c275c3ae6804b6670be>" %}

La versión actualizada del script está en [este repositorio](https://github.com/sadaoikebe/my-printer-config/blob/master/stealthburner_colors.py).

### Configuración base para Stealthburner

```ini
[neopixel sb_leds]
pin: toolhead:gpio7       # Ajusta al pin de tu toolboard
chain_count: 3
color_order: GRB
initial_RED: 0.0
initial_GREEN: 0.0
initial_BLUE: 0.0

[virtual_leds sb_logo]
leds: neopixel:sb_leds (1)

[virtual_leds sb_nozzle]
leds: neopixel:sb_leds (2, 3)
```

### Añadir el script al laminador

{% tabs %}
{% tab title="PrusaSlicer / SuperSlicer / OrcaSlicer" %}

1. Copia `stealthburner_colors.py` a tu ordenador (en una ruta **sin espacios**)
2. Asegúrate de tener **Python 3** instalado
3. En el laminador: **Print Settings → Output Options → Post-processing scripts** — añade la ruta completa al script

![](/files/hCcRKB9pw2044KBt4Nv5)

Al laminar aparece una ventana de terminal confirmando la ejecución.
{% endtab %}

{% tab title="Cura" %}
Copia el script al directorio de scripts de Cura:

* Windows: `%APPDATA%\cura\<VERSION>\scripts`
* Linux: `~/.local/share/cura/<VERSION>/scripts`
* macOS: `~/Library/Application Support/Cura/<VERSION>/scripts`

En Cura: **Extensions → Post Processing → Modify G-Code** → **Add a script → Stealthburner Colors**
{% endtab %}
{% endtabs %}

Para verificar que funcionó, abre el G-code generado con un editor y busca `SET_LED LED=sb_leds`. Deben aparecer cambios de color en los puntos de transición entre tipos de trazada.

***

## Opción 2 — Hardware externo o segunda MCU

Cuando la MCU principal no tiene pines libres, quieres controlar tiras grandes con animaciones fluidas a 60fps, o prefieres un sistema de efectos más rico sin escribir código, estas tres opciones cubren todos los casos.

### WLED vs LUMEN vs RP2040 — ¿cuándo usar cada uno?

|                                     | WLED                                   | LUMEN                                | RP2040 / Pi Pico                 |
| ----------------------------------- | -------------------------------------- | ------------------------------------ | -------------------------------- |
| **Hardware extra**                  | ESP8266/ESP32 (\~5€)                   | Ninguno (usa la Pi)                  | Pi Pico (\~5€)                   |
| **Conexión a Klipper**              | Moonraker (`[wled]`)                   | Moonraker (plugin)                   | MCU secundaria (`[mcu]`)         |
| **FPS / fluidez**                   | Alta (WiFi, alguna latencia)           | 60fps GPIO nativo                    | Igual que MCU principal          |
| **Número de efectos**               | +100 efectos y paletas                 | 12 efectos, 14 estados automáticos   | Los de klipper-led\_effect       |
| **Interfaz de configuración**       | App web propia + presets               | Archivo `lumen.cfg`                  | `printer.cfg`                    |
| **Detección automática de estados** | No — necesita macros                   | Sí — sin tocar PRINT\_START          | No — necesita macros             |
| **Mejor para**                      | Cerramientos grandes, efectos vistosos | Pi ya instalada, cero hardware extra | Pines MCU agotados, tiras largas |

{% hint style="info" %}
Las tres opciones son compatibles entre sí. Puedes tener WLED para el cerramiento, LUMEN para el toolhead, y una segunda MCU para una tira larga simultáneamente.
{% endhint %}

***

### WLED — firmware ESP8266/ESP32

[WLED](https://kno.wled.ge/) es un firmware open-source para ESP8266/ESP32 con más de 100 efectos y paletas de color. Se integra con Moonraker para controlar presets desde macros G-code.

{% hint style="success" %}
WLED es la opción recomendada si quieres efectos visuales llamativos en el cerramiento. La ESP32 cuesta menos de 5€ y aguanta tiras de cientos de LEDs sin problemas.
{% endhint %}

#### Configurar presets en WLED

Antes de integrar con Klipper, define los presets en la app de WLED:

1. Elige color y efecto desde la pantalla principal
2. Pestaña **Presets** → crear nuevo preset. El **ID** del preset es el número que usarás en Klipper
3. Crea al menos: encendido con efecto, apagado, y uno por cada estado de impresión

Asigna una **IP estática** a tu WLED desde la configuración WiFi del propio WLED. Si cambia la IP, los macros dejan de funcionar.

#### moonraker.conf

```ini
[wled cerramiento]
type: http
address: 192.168.1.99    # IP estática de tu WLED
initial_red: 0.5
initial_green: 0.4
initial_blue: 0.3
chain_count: 60

# Si tienes varios WLED, añade más secciones
[wled toolhead_wled]
type: http
address: 192.168.1.100
chain_count: 8
```

#### Macros Klipper para WLED

```ini
[gcode_macro WLED_ON]
description: Encender WLED con preset opcional
gcode:
    {% set strip = params.STRIP | default("cerramiento") | string %}
    {% set preset = params.PRESET | default(1) | int %}
    {action_call_remote_method("set_wled_state",
                               strip=strip,
                               state=True,
                               preset=preset)}

[gcode_macro WLED_OFF]
description: Apagar WLED
gcode:
    {% set strip = params.STRIP | default("cerramiento") | string %}
    {action_call_remote_method("set_wled_state",
                               strip=strip,
                               state=False)}

# Macros de estado usando presets
[gcode_macro WLED_HEATING]
gcode:
    WLED_ON STRIP=cerramiento PRESET=2

[gcode_macro WLED_PRINTING]
gcode:
    WLED_ON STRIP=cerramiento PRESET=3

[gcode_macro WLED_DONE]
gcode:
    WLED_ON STRIP=cerramiento PRESET=4
```

***

### LUMEN — plugin Moonraker para Raspberry Pi

[LUMEN](https://github.com/MakesBadDecisions/Lumen_RPI) es un plugin de Moonraker que controla LEDs directamente desde la Raspberry Pi sin necesidad de hardware externo. Detecta automáticamente 14 estados de la impresora y aplica efectos suaves a 60fps usando el GPIO de la Pi.

{% hint style="success" %}
LUMEN es la mejor opción si ya tienes la Pi y quieres detección automática de estados sin tocar `PRINT_START` ni `PRINT_END`. La instalación es un único script.
{% endhint %}

#### Instalación

```bash
cd ~
git clone https://github.com/MakesBadDecisions/Lumen_RPI.git lumen
cd lumen
chmod +x install.sh
./install.sh
```

El instalador detecta las rutas de Klipper/Moonraker automáticamente, instala la librería `rpi-ws281x`, levanta el servicio `ws281x-proxy` (necesario para acceso GPIO a 60fps) y añade la configuración base al `moonraker.conf`.

#### moonraker.conf

```ini
[lumen]
config_path: ~/printer_data/config/lumen.cfg

[update_manager lumen]
type: git_repo
path: ~/lumen
origin: https://github.com/MakesBadDecisions/Lumen_RPI.git
managed_services: moonraker
primary_branch: main
```

#### Configuración en lumen.cfg

{% tabs %}
{% tab title="GPIO (Pi directa)" %}
Para tiras WS2812B conectadas directamente a los GPIO de la Raspberry Pi. Corre a 60fps sin tocar la cola G-code.

```ini
[lumen_settings]
gpio_fps: 60               # FPS de animación
bored_timeout: 300         # Segundos idle antes de "bored"
sleep_timeout: 600         # Segundos bored antes de "sleep"

[lumen_group cerramiento]
driver: proxy              # GPIO via ws281x-proxy (recomendado para 60fps)
gpio_pin: 18               # Pin BCM válidos: 12, 13, 18, 19
index_start: 1
index_end: 60
color_order: GRB
group_brightness: 0.8
on_idle: pulse cobalt
on_heating: thermal bed ice lava 2.0
on_printing: progress steel matrix 1.5
on_cooldown: pulse ice
on_error: heartbeat red
on_bored: disco
on_sleep: off
```

{% hint style="warning" %}
Los únicos GPIO válidos para WS2812B en la Pi son **12, 13, 18 y 19** (pines PWM hardware). GPIO 18 es el más recomendado — GPIO 19 puede dar conflictos con la salida de audio si está habilitada en `/boot/config.txt`.
{% endhint %}
{% endtab %}

{% tab title="MCU (toolhead/EBB)" %}
Para LEDs conectados a la MCU principal o un toolboard. LUMEN envía `SET_LED` via cola G-code — la animación es más lenta durante la impresión pero funciona en cualquier electrónica BTT.

```ini
# Requiere definir el neopixel en printer.cfg primero:
# [neopixel toolhead_leds]
# pin: EBBCan:PD3
# chain_count: 3
# color_order: GRB

[lumen_group toolhead]
driver: klipper
neopixel: toolhead_leds    # Debe coincidir con [neopixel] en printer.cfg
index_start: 1
index_end: 3
group_brightness: 1.0
on_idle: solid green
on_heating: pulse orange
on_printing: solid white
on_error: heartbeat red
```

{% endtab %}

{% tab title="PWM (tira monocolor)" %}
Para tiras LED no addressables (luz blanca, un solo canal de brillo).

```ini
# Requiere en printer.cfg:
# [output_pin caselight]
# pin: PB7
# pwm: True
# value: 0.5

[lumen_group luz_caja]
driver: pwm
pin_name: caselight
on_idle: 0.5
on_printing: 1.0
on_sleep: 0.0
```

{% endtab %}
{% endtabs %}

#### Estados automáticos de la impresora

LUMEN detecta 14 estados directamente desde Moonraker/Klipper sin necesidad de macros en `PRINT_START`/`PRINT_END`:

| Estado            | Cuándo se activa                                |
| ----------------- | ----------------------------------------------- |
| `idle`            | Impresora fría, sin objetivos de temperatura    |
| `heating`         | Calentando hotend o cama                        |
| `printing`        | Impresión activa a temperatura                  |
| `cooldown`        | Impresión terminada, todavía caliente (>40°C)   |
| `error`           | Klipper en shutdown o error                     |
| `paused`          | Impresión pausada                               |
| `cancelled`       | Impresión cancelada                             |
| `homing`          | Ejecutando homing                               |
| `meshing`         | Haciendo bed mesh                               |
| `leveling`        | Nivelando                                       |
| `probing`         | Probando con el sensor                          |
| `filament_change` | Cambio de filamento (requiere sensor de runout) |
| `bored`           | Idle durante N minutos (configurable)           |
| `sleep`           | Bored durante N minutos (configurable)          |

#### Efectos disponibles

```ini
on_idle: solid white           # Sólido
on_idle: pulse cobalt          # Respiración/fade
on_error: heartbeat red        # Doble pulso (latido)
on_bored: disco                # Destellos arcoíris
on_bored: rainbow              # Arcoíris continuo
on_heating: fire               # Llama simulada
on_printing: comet cobalt      # Cometa con estela
on_cooldown: chase 1           # Persecución predador/presa (multi-grupo)
on_idle: kitt red              # Scanner KITT (Knight Rider)

# Gradiente térmico: thermal <fuente> <color_frío> <color_caliente> <curva>
on_heating: thermal bed ice lava 2.0

# Barra de progreso: progress <color_inicio> <color_fin> <curva>
on_printing: progress steel matrix 1.5

on_sleep: off                  # Apagado
```

#### Integración opcional con macros

LUMEN funciona sin macros — los estados se detectan automáticamente. Para control manual añade el archivo de macros de ejemplo a `printer.cfg`:

```ini
[include lumen_macros.cfg]
```

```gcode
LUMEN_RELOAD                                       # Recargar config sin reiniciar Moonraker
LUMEN_SET GROUP=cerramiento EFFECT=solid COLOR=white DURATION=10  # Override temporal
LUMEN_TEST STATE=heating                           # Probar un estado
```

#### Modo test — verificar efectos sin imprimir

```gcode
LUMEN_TEST_START                           # Entrar en modo test
LUMEN_TEST_NEXT_STATE                      # Ciclar: idle → heating → printing → ...
LUMEN_TEST_NEXT_EFFECT GROUP=cerramiento   # Ciclar efectos en un grupo
LUMEN_TEST_STOP                            # Salir y recargar config
```

#### API REST

```bash
curl http://localhost:7125/server/lumen/status | jq                            # Estado + métricas
curl -X POST "http://localhost:7125/server/lumen/set_group?group=cerramiento&effect=solid&color=white"
curl -X POST "http://localhost:7125/server/lumen/reload"                       # Hot reload config
curl -X POST "http://localhost:7125/server/lumen/test_event?event=heating"     # Forzar estado
```

***

### Segunda MCU — RP2040 / Pi Pico

Si tu electrónica no tiene pines libres o quieres controlar tiras de más de 20 LEDs sin saturar la MCU principal, un microcontrolador dedicado con firmware Klipper es la solución más limpia: los LEDs aparecen en Klipper como cualquier otro neopixel y son compatibles con LED Effects.

**La opción más recomendada: Raspberry Pi Pico (RP2040)**

Cuesta menos de 5€, tiene soporte nativo en Klipper, y puede manejar centenares de LEDs sin esfuerzo. Mucho más potente que un Arduino Nano para este uso.

#### Compilar firmware para RP2040

```bash
cd ~/klipper
make clean
make menuconfig
```

Configuración en menuconfig:

* **Micro-controller Architecture**: `Raspberry Pi RP2040`
* **Bootloader offset**: `No bootloader`
* **Communication interface**: `USB`

```bash
make
```

Con el Pico en modo BOOTSEL (mantén el botón pulsado al conectar el USB), aparece como unidad de almacenamiento. Copia el archivo `.uf2` generado.

#### Configurar en printer.cfg

```ini
[mcu pico_leds]
serial: /dev/serial/by-id/usb-Klipper_rp2040_XXXXX-if00

[neopixel tira_pico]
pin: pico_leds:gpio0      # GPIO del Pico conectado a la tira
chain_count: 60
color_order: GRB
initial_RED: 0.3
initial_GREEN: 0.3
initial_BLUE: 0.3
```

Una vez configurado puedes usar este `[neopixel]` con cualquier macro `SET_LED` o con el plugin LED Effects exactamente igual que si estuviera en la MCU principal.

{% hint style="info" %}
**Arduino Nano como alternativa**

Si tienes un Arduino Nano disponible también funciona. En `make menuconfig` selecciona `Atmega AVR` → `atmega328p`. El RP2040 es preferible por capacidad y mejor soporte, pero el Nano funciona perfectamente para tiras pequeñas.
{% endhint %}

***

## Solución de problemas

### Los colores salen incorrectos

El problema casi siempre es el `color_order`. Prueba en este orden:

1. Comprueba el modelo exacto de tu LED (WS2812B, SK6812, APA102...)
2. Consulta la tabla de tipos más arriba y ajusta `color_order`
3. Si mezclas LEDs de distinto tipo en la misma cadena, puedes especificar uno por LED: `color_order: GRB, GRB, GRBW`

### Los LEDs parpadean o hacen cosas raras

{% columns %}
{% column %}
**Causa probable: señal**

* Falta resistencia en el pin de datos (300-500 Ω)
* Cable de señal demasiado largo (más de 50 cm sin repetidor)
* GND no compartido entre MCU y tira
  {% endcolumn %}

{% column %}
**Causa probable: alimentación**

* Tira alimentada desde el 5V de la electrónica con más de 20 LEDs
* Fuente 5V insuficiente — usa la calculadora WLED para verificar amperaje
* Capacitor 1000 µF entre +5V y GND al inicio de la tira estabiliza la tensión
  {% endcolumn %}
  {% endcolumns %}

### "Neopixel update did not succeed" en el log

Este error aparece cuando el timing de la señal falla. Causas más frecuentes:

* MCU demasiado cargada — reduce `frame_rate` en LED Effects (de 24 a 10 o menos)
* Tira conectada a pin de Raspberry Pi directamente sin usar LUMEN ni segunda MCU
* Interferencias en el cable de señal — acorta el cable o añade el condensador

### Solo se enciende el primer LED

Comprobaciones:

1. Verifica que `chain_count` coincide con el número real de LEDs
2. El sentido de la tira es incorrecto — invierte la conexión o usa otro punto de entrada
3. Alimentación insuficiente — a partir del LED 15-20 sin alimentación externa la señal se degrada

### Los efectos de LED Effects no se activan

1. Confirma que el plugin está instalado: en Mainsail → Sistema → Extensiones, debe aparecer `led_effect`
2. Reinicia Klipper tras instalar el plugin
3. Verifica que los nombres de `[neopixel]` en el `[led_effect]` coinciden exactamente con los definidos en el cfg
4. Si usas `virtual_leds`, la referencia en `[led_effect]` debe ser `virtual_leds:nombre` no `neopixel:nombre`
