WS2812B / NeoPixel LED Strips

How to control addressable WS2812B NeoPixel LED strips with ESP32

WS2812B LEDs (often called NeoPixels, Adafruit's brand name) are addressable RGB LEDs. Unlike a basic RGB LED where you control one color for the whole LED, each WS2812B pixel contains its own tiny controller chip. You can set any color on any individual LED in a strip using just a single data pin from the ESP32. This makes them perfect for status indicators, light strips, and decorative lighting in IoT projects.

This guide uses the ESP32-WROOM-32 DevKit. Pin labels and GPIO numbers may differ on your board -- always check your board's pinout diagram.

Simpler options: For a single status indicator, a plain LED is cheaper and easier. For one LED with colour mixing (no strip), see RGB LEDs.

🔗Key Specs

ParameterValue
LED typeWS2812B (integrated controller + RGB LED)
Color depth24-bit ($256 \times 3$ channels)
Data protocolSingle-wire, 800 kHz
Supply voltage$5\,\text{V}$ DC
Current per LEDUp to $60\,\text{mA}$ at full white
Data logic level$5\,\text{V}$ (works with $3.3\,\text{V}$ in most cases)

🔗Power Budget

Each WS2812B LED draws up to $60\,\text{mA}$ at full brightness white ($20\,\text{mA}$ per color channel). For a strip of $n$ LEDs:

$$I_{max} = n \times 60\,\text{mA}$$

For example, a 30-LED strip can draw up to:

$$30 \times 60\,\text{mA} = 1800\,\text{mA} = 1.8\,\text{A}$$

Warning: Do not power more than 2--3 NeoPixels from the ESP32's 3.3V or 5V pin. The onboard voltage regulator cannot supply enough current. For strips of any significant length, use an external 5V power supply rated for your total current draw.

🔗What You'll Need

ComponentQtyNotesBuy
ESP32 dev board1AliExpress | Amazon.de .co.uk .com
WS2812B NeoPixel LED strip1AliExpress | Amazon.de .co.uk .com
330 ohm resistor1Protects first LED data inputAliExpress | Amazon.de .co.uk .com
1000 uF electrolytic capacitor1Across power supply terminalsAliExpress | Amazon.de .co.uk .com
5V power supply1Rated for your strip's current drawAmazon.de .co.uk .com
Breadboard1AliExpress | Amazon.de .co.uk .com
Jumper wires4AliExpress | Amazon.de .co.uk .com

Links marked Amazon/AliExpress are affiliate links. We may earn a small commission at no extra cost to you.

🔗Wiring

WS2812B PinConnectionNotes
5V (VCC)External 5V power supply (+)Do not use ESP32 3.3V for more than 2--3 LEDs
GNDExternal power supply GND and ESP32 GNDShared ground is essential
DIN (Data In)GPIO 16 through $330\,\Omega$ resistorProtects the first LED's data input

Additionally, place a $1000\,\mu\text{F}$ electrolytic capacitor across the 5V and GND terminals of the power supply, close to the strip. This absorbs voltage spikes when the LEDs switch on and protects the first LED from damage.

Tip: The data signal direction matters. WS2812B strips have arrows printed on them showing the data flow. Connect your ESP32 to the DIN (Data In) end, not DOUT.

🔗Logic Level Note

WS2812B LEDs expect a $5\,\text{V}$ data signal, but in practice they almost always work with the ESP32's $3.3\,\text{V}$ output. If you experience flickering or unreliable color output (especially with long data wires), add a logic level shifter between the ESP32 GPIO and the strip's DIN pin.

🔗Required Libraries

Install the Adafruit NeoPixel library through the Arduino Library Manager:

  1. Go to Sketch > Include Library > Manage Libraries...
  2. Search for Adafruit NeoPixel and install it

🔗Code Example: Basic Colors

This sketch sets individual pixel colors on a strip of 8 NeoPixels.

#include <Adafruit_NeoPixel.h>

#define LED_PIN    16   // GPIO connected to DIN
#define NUM_LEDS   8    // Number of LEDs in the strip

Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
    strip.begin();
    strip.setBrightness(50);  // 0-255, keep low for testing
    strip.show();             // Initialize all pixels to off
}

void loop() {
    // Set first 3 pixels to red, green, blue
    strip.setPixelColor(0, strip.Color(255, 0, 0));    // Red
    strip.setPixelColor(1, strip.Color(0, 255, 0));    // Green
    strip.setPixelColor(2, strip.Color(0, 0, 255));    // Blue

    // Set next pixels to mixed colors
    strip.setPixelColor(3, strip.Color(255, 255, 0));  // Yellow
    strip.setPixelColor(4, strip.Color(255, 0, 255));  // Magenta
    strip.setPixelColor(5, strip.Color(0, 255, 255));  // Cyan
    strip.setPixelColor(6, strip.Color(255, 128, 0));  // Orange
    strip.setPixelColor(7, strip.Color(255, 255, 255));// White

    strip.show();  // Send data to the strip
    delay(2000);

    // Turn all off
    strip.clear();
    strip.show();
    delay(1000);
}

🔗Code Example: Chase Effect

A single lit pixel travels along the strip.

#include <Adafruit_NeoPixel.h>

#define LED_PIN    16
#define NUM_LEDS   8

Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
    strip.begin();
    strip.setBrightness(50);
    strip.show();
}

void chase(uint32_t color, int wait) {
    for (int i = 0; i < NUM_LEDS; i++) {
        strip.clear();
        strip.setPixelColor(i, color);
        strip.show();
        delay(wait);
    }
}

void loop() {
    chase(strip.Color(255, 0, 0), 100);    // Red chase
    chase(strip.Color(0, 255, 0), 100);    // Green chase
    chase(strip.Color(0, 0, 255), 100);    // Blue chase
}

🔗Code Example: Rainbow Effect

This fills the entire strip with a smoothly shifting rainbow.

#include <Adafruit_NeoPixel.h>

#define LED_PIN    16
#define NUM_LEDS   8

Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
    strip.begin();
    strip.setBrightness(50);
    strip.show();
}

void rainbow(int wait) {
    for (long firstPixelHue = 0; firstPixelHue < 65536; firstPixelHue += 256) {
        for (int i = 0; i < NUM_LEDS; i++) {
            int pixelHue = firstPixelHue + (i * 65536L / NUM_LEDS);
            strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
        }
        strip.show();
        delay(wait);
    }
}

void loop() {
    rainbow(10);
}

🔗How It Works

Each WS2812B LED contains a small controller chip that listens on its data input pin. When the ESP32 sends a stream of color data, the first LED in the chain takes the first 24 bits (8 bits each for green, red, and blue) and passes the rest of the data stream to the next LED. Each subsequent LED takes its 24 bits and forwards the remainder. This daisy-chain protocol means you only need one data pin regardless of how many LEDs you have.

The strip.show() call is what actually transmits all the pixel data at once. Until you call show(), any setPixelColor() calls only modify an internal buffer. The timing of the data signal is very precise (measured in nanoseconds), which is why the library disables interrupts briefly during transmission.

🔗Troubleshooting

ProblemPossible CauseSolution
No LEDs light upWrong data pin or no shared groundVerify GPIO in code, ensure ESP32 GND connects to strip GND
First LED shows wrong color, rest are fineMissing series resistorAdd a $330\,\Omega$ resistor on the data line
Random flickering or wrong colors$3.3\,\text{V}$ logic level issueAdd a logic level shifter (3.3V to 5V)
First LED is damaged/deadVoltage spike on power-upAdd a $1000\,\mu\text{F}$ capacitor across power
Colors look washed outBrightness set too lowIncrease setBrightness() value (0--255)
Some LEDs in the middle are wrongDamaged LED breaking the data chainReplace the faulty LED or cut and rejoin the strip
ESP32 resets when LEDs turn onPower supply cannot handle the currentUse a beefier 5V supply; do not power from ESP32

🔗Next Steps

  • Build a notification light that changes color based on sensor data
  • Create an ambient lighting system controlled over WiFi
  • Experiment with longer strips (just make sure your power supply is sufficient)
  • Combine NeoPixels with a relay module to build a smart lamp with both room lighting and accent LEDs