# 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`


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://klipper.3dwork.io/klipper/mejoras/neopixel.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
