FastLED Helper

Use FastLED library for ESP32/Arduino LED strip control. Covers setup, color management (CRGB/CHSV), animations, palettes, power management, and chipset-specific configurations. Triggers on phrases like "FastLED", "LED strip", "WS2812", "NeoPixel", "APA102", "LED animation", "RGB LED", "addressable LED".

Audits

Pending

Install

openclaw skills install fastled-helper

FastLED Skill

FastLED is a high-performance library for controlling addressable RGB LED strips (WS2812/NeoPixel, APA102/DotStar, LPD8806, etc.) on ESP32, Arduino, and other platforms.

Core Setup

Include and LED Array

#include "FastLED.h"

#define NUM_LEDS 60
#define DATA_PIN 6
#define CLOCK_PIN 7  // For SPI chipsets only

CRGB leds[NUM_LEDS];  // RGB color array, one per LED

Initialize LED Strip (setup())

3-wire chipsets (WS2812, NeoPixel, etc.):

void setup() {
    FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
    // or: FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, NUM_LEDS);
}

4-wire SPI chipsets (APA102, LPD8806, etc.):

void setup() {
    // Using hardware SPI pins
    FastLED.addLeds<APA102>(leds, NUM_LEDS);
    
    // Or with custom pins
    FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN>(leds, NUM_LEDS);
    
    // With custom data rate
    FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, RGB, DATA_RATE_MHZ(12)>(leds, NUM_LEDS);
}

Show LEDs

void loop() {
    leds[0] = CRGB::Red;   // Set first LED to red
    FastLED.show();         // Push data to strip
    delay(30);              // Wait before next frame
}

Color Management

CRGB - RGB Color Space

Creating colors:

// Individual channels
leds[i].r = 255; leds[i].g = 128; leds[i].b = 0;

// Constructor
leds[i] = CRGB(255, 128, 0);

// Hex code
leds[i] = 0xFF8000;

// Named web colors
leds[i] = CRGB::HotPink;
leds[i] = CRGB::DarkOrange;

// setRGB method
leds[i].setRGB(255, 128, 0);

Common predefined colors:

CRGB::Black, CRGB::White, CRGB::Red, CRGB::Green, CRGB::Blue,
CRGB::Yellow, CRGB::Cyan, CRGB::Magenta, CRGB::Orange, CRGB::Purple

CRGB methods:

leds[i].fadeToBlackBy(64);      // Fade by 64/256 (25%)
leds[i].fadeLightBy(64);        // Darken by 64/256
leds[i].nscale8_video(200);     // Scale to 78% brightness (video scaling)
leds[i].nscale8(200);           // Scale to 78% brightness (linear)
leds[i].maximizeBrightness();   // Maximize brightness (keep hue)
leds[i].invert();               // Invert color

CHSV - HSV Color Space

FastLED uses 0-255 range for all HSV values (not 0-360/0-100):

// Hue (0-255), Saturation (0-255), Value/Brightness (0-255)
leds[i] = CHSV(160, 255, 255);  // Full brightness blue

// Using named hue constants
leds[i] = CHSV(HUE_RED, 255, 255);
leds[i] = CHSV(HUE_GREEN, 200, 255);
leds[i] = CHSV(HUE_AQUA + 10, 255, 200);

// setHSV method
leds[i].setHSV(160, 255, 255);

Hue cardinal points:

HUE_RED (0), HUE_ORANGE (32), HUE_YELLOW (64), HUE_GREEN (96),
HUE_AQUA (128), HUE_BLUE (160), HUE_PURPLE (192), HUE_PINK (224)

Color conversion:

CHSV hsvColor(160, 255, 255);
CRGB rgbColor = hsvColor;  // Automatic conversion

LED Control Functions

Fill Functions

// Fill all LEDs with solid color
fill_solid(leds, NUM_LEDS, CRGB::Red);

// Fill range with solid color
fill_solid(&(leds[10]), 20, CRGB::Blue);

// Fill with gradient (start color to end color)
fill_gradient_RGB(leds, NUM_LEDS, CRGB::Red, CRGB::Blue);

// Fill with HSV gradient
fill_gradient(leds, NUM_LEDS, CHSV(0, 255, 255), CHSV(160, 255, 255));

// Fill with HSV gradient (3-color)
fill_gradient(leds, 0, CHSV(0,255,255), NUM_LEDS/2, CHSV(100,255,255), 
              NUM_LEDS-1, CHSV(200,255,255), SHORTEST_HUES);

// Fill rainbow
fill_rainbow(leds, NUM_LEDS, 0, 5);  // Start hue 0, delta 5 per LED

Copy/Move Functions

// Copy single LED
leds[i] = leds[j];

// Copy range
memmove(&leds[dest], &leds[src], 10 * sizeof(CRGB));
memmove8(&leds[dest], &leds[src], 10 * sizeof(CRGB));  // Faster on AVR

// Shift LEDs (move all one position)
memmove(&leds[1], &leds[0], (NUM_LEDS-1) * sizeof(CRGB));
leds[0] = CRGB::Black;  // Clear first

// Fade all to black
fadeToBlackBy(leds, NUM_LEDS, 64);  // Fade by 64/256

// Dim all
nscale8(leds, NUM_LEDS, 200);  // Scale to 78%

Brightness and Power

// Set global brightness (0-255)
FastLED.setBrightness(128);  // 50% brightness

// Get current power usage (in milliwatts)
uint16_t milliwatts = calculate_unscaled_power_mW(leds, NUM_LEDS);

// Limit power usage
FastLED.setMaxPowerInVoltsAndMilliamps(5, 1500);  // 5V, 1.5A max

Color Palettes

Built-in Palettes

// Use built-in palette
CRGBPalette16 myPal = RainbowColors_p;
CRGBPalette16 myPal = RainbowStripeColors_p;
CRGBPalette16 myPal = OceanColors_p;
CRGBPalette16 myPal = CloudColors_p;
CRGBPalette16 myPal = LavaColors_p;
CRGBPalette16 myPal = ForestColors_p;
CRGBPalette16 myPal = PartyColors_p;
CRGBPalette16 myPal = HeatColors_p;

Custom Gradient Palettes

// Define gradient palette (stored in PROGMEM)
DEFINE_GRADIENT_PALETTE( heatmap_gp ) {
    0,     0,  0,  0,   // black
  128,   255,  0,  0,   // red
  224,   255,255,  0,   // bright yellow
  255,   255,255,255 }; // full white

// Activate
CRGBPalette16 myPal = heatmap_gp;

// Use
uint8_t index = 128;  // 0-255
leds[i] = ColorFromPalette(myPal, index);
leds[i] = ColorFromPalette(myPal, index, 128);  // With brightness 128
leds[i] = ColorFromPalette(myPal, index, 255, NOBLEND);  // No blending

Palette Blending

CRGBPalette16 currentPalette;
CRGBPalette16 targetPalette;
uint8_t paletteBlendAmount = 0;

// Blend between palettes
nblendPaletteTowardPalette(currentPalette, targetPalette, 24);

Animation Helpers

Linear Blending

// Blend between two colors
CRGB colorA = CRGB::Red;
CRGB colorB = CRGB::Blue;
leds[i] = blend(colorA, colorB, 128);  // 50% blend

// Blend with black (fade)
leds[i] = blend(leds[i], CRGB::Black, 64);

Beat Functions (Time-based Animation)

// Returns 0-255 based on BPM
uint8_t beat = beatsin8(60);  // 60 BPM sine wave

// With low/high range
uint8_t beat = beatsin8(60, 20, 200);  // Range 20-200

// With phase offset
uint8_t beat = beatsin8(60, 20, 200, 0, 64);  // Phase offset 64

// Other beat functions
uint16_t beat16 = beatsin16(60);        // 16-bit precision
uint8_t beat88 = beatsin88(60 << 8);     // 8.8 fixed point

Wave Functions

// Triwave (triangle wave)
uint8_t val = triwave8(128);  // 0-255 range

// Quadwave (smoother)
uint8_t val = quadwave8(128);

// Cubic wave (even smoother)
uint8_t val = cubicwave8(128);

// Sine wave
uint8_t val = sin8(128);      // 0-255 range (half wave)
uint8_t val = cos8(128);      // 0-255 range (half wave)

Random Functions

// Random 8-bit value
uint8_t r = random8();
uint8_t r = random8(100);     // 0-99

// Random 16-bit value
uint16_t r = random16();

// Random CRGB color
CRGB c = CRGB(random8(), random8(), random8());

Multi-Strip and Parallel Output

Multiple LED Arrays

#define NUM_LEDS_STRIP_A 60
#define NUM_LEDS_STRIP_B 30

#define DATA_PIN_A 6
#define DATA_PIN_B 7

CRGB ledsA[NUM_LEDS_STRIP_A];
CRGB ledsB[NUM_LEDS_STRIP_B];

void setup() {
    FastLED.addLeds<NEOPIXEL, DATA_PIN_A>(ledsA, NUM_LEDS_STRIP_A);
    FastLED.addLeds<NEOPIXEL, DATA_PIN_B>(ledsB, NUM_LEDS_STRIP_B);
}

void loop() {
    fill_solid(ledsA, NUM_LEDS_STRIP_A, CRGB::Red);
    fill_solid(ledsB, NUM_LEDS_STRIP_B, CRGB::Blue);
    FastLED.show();
}

Parallel Output (Teensy/ESP32)

// ESP32: Up to 8 parallel strips
#define NUM_STRIPS 8
#define NUM_LEDS_PER_STRIP 60

CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP];

void setup() {
    FastLED.addLeds<WS2812, 2, GRB>(leds, 0, NUM_LEDS_PER_STRIP);
    FastLED.addLeds<WS2812, 3, GRB>(leds, 1 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
    FastLED.addLeds<WS2812, 4, GRB>(leds, 2 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
    // ... up to 8 strips
}

Supported Chipsets

3-Wire (Data only)

ChipsetAliasData RateNotes
WS2811800kbps
WS2812NEOPIXEL800kbpsLED+controller in one package
WS2812BNEOPIXEL800kbpsMost common
WS2813800kbpsBackup data line
SK6812800kbpsRGBW support
TM1809800kbps1 IC per 3 LEDs
TM1804800kbps1 IC per 1 LED
TM1803400kbpsRadioShack version
UCS1903400kbpsVery slow
UCS1904800kbps
UCS2903800kbps

4-Wire SPI (Data + Clock)

ChipsetAliasData RateNotes
APA102DOTSTAR~24MbpsRecommended
SK9822~24MbpsAPA102 clone
LPD88061-20Mbps7-bit per channel
WS28011MbpsOlder, glitch-prone
P9813TCL1-15MbpsTotal Control Lighting
SM16716Poor protocol

Color Order Specifiers

RGB, RBG, GRB, GBR, BRG, BGR  // Common for 3-wire
RBG, BGR, etc.                  // For RGBW (add W at end)

ESP32-Specific Notes

GPIO Pins

  • Any GPIO can be used for data output
  • Recommended: GPIO 2, 4, 12-19, 21-23, 25-27, 32-33
  • Avoid: GPIO 6-11 (used for flash), GPIO 34-39 (input only)

RMT Peripheral (Hardware Assist)

// FastLED on ESP32 uses RMT peripheral for precise timing
// No interrupt disabling needed (unlike AVR)

// Increase RMT channels if needed (default is usually sufficient)
#define FASTLED_RMT_MAX_CHANNELS 8

Power Considerations

  • ESP32 3.3V GPIO can drive 5V LED strips directly (usually works)
  • For long strips, use level shifter (3.3V → 5V)
  • Power LED strip separately from ESP32 (don't power 5V strip from ESP32)

Common Patterns

Rainbow Cycle

uint8_t hue = 0;

void loop() {
    fill_rainbow(leds, NUM_LEDS, hue, 255 / NUM_LEDS);
    FastLED.show();
    hue++;
    delay(20);
}

Color Wipe

void colorWipe(CRGB color, int wait) {
    for(int i=0; i<NUM_LEDS; i++) {
        leds[i] = color;
        FastLED.show();
        delay(wait);
    }
}

Running Dot

void loop() {
    fadeToBlackBy(leds, NUM_LEDS, 64);
    int pos = beatsin16(60, 0, NUM_LEDS-1);
    leds[pos] = CHSV(hue, 255, 255);
    FastLED.show();
}

Fire Effect

void fireEffect() {
    CRGBPalette16 heatPalette = HeatColors_p;
    for(int i=0; i<NUM_LEDS; i++) {
        uint8_t noise = inoise8(i * 50, millis() / 10);
        uint8_t index = scale8(noise, 240);
        leds[i] = ColorFromPalette(heatPalette, index);
    }
    FastLED.show();
}

Tips and Gotchas

  • show() is blocking on most platforms (sends all data before returning)
  • WS2812 requires precise timing - interrupts disabled during send on AVR, but not ESP32
  • Power supply: Budget 60mA per LED at full white. 300 LEDs = 18A max
  • Capacitor: Add 1000μF across power supply near strip start
  • Resistor: Add 330-470Ω in series on data line near strip start
  • Level shifter: Use for 5V strips with 3.3V MCU if data glitches
  • Memory: Each CRGB is 3 bytes. 1000 LEDs = 3KB RAM
  • ** Temporal dithering**: Improves low-brightness smoothness, enabled by default
  • Color correction: FastLED.setCorrection(TypicalLEDStrip) or UncorrectedColor
  • Temperature: FastLED.setTemperature(ClearBlueSky) or Tungsten40W

Resources