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
| Parameter | Value |
|---|---|
| LED type | WS2812B (integrated controller + RGB LED) |
| Color depth | 24-bit ($256 \times 3$ channels) |
| Data protocol | Single-wire, 800 kHz |
| Supply voltage | $5\,\text{V}$ DC |
| Current per LED | Up 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
| Component | Qty | Notes | Buy |
|---|---|---|---|
| ESP32 dev board | 1 | AliExpress | Amazon.de .co.uk .com | |
| WS2812B NeoPixel LED strip | 1 | AliExpress | Amazon.de .co.uk .com | |
| 330 ohm resistor | 1 | Protects first LED data input | AliExpress | Amazon.de .co.uk .com |
| 1000 uF electrolytic capacitor | 1 | Across power supply terminals | AliExpress | Amazon.de .co.uk .com |
| 5V power supply | 1 | Rated for your strip's current draw | Amazon.de .co.uk .com |
| Breadboard | 1 | AliExpress | Amazon.de .co.uk .com | |
| Jumper wires | 4 | AliExpress | 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 Pin | Connection | Notes |
|---|---|---|
| 5V (VCC) | External 5V power supply (+) | Do not use ESP32 3.3V for more than 2--3 LEDs |
| GND | External power supply GND and ESP32 GND | Shared ground is essential |
| DIN (Data In) | GPIO 16 through $330\,\Omega$ resistor | Protects 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:
- Go to Sketch > Include Library > Manage Libraries...
- 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
| Problem | Possible Cause | Solution |
|---|---|---|
| No LEDs light up | Wrong data pin or no shared ground | Verify GPIO in code, ensure ESP32 GND connects to strip GND |
| First LED shows wrong color, rest are fine | Missing series resistor | Add a $330\,\Omega$ resistor on the data line |
| Random flickering or wrong colors | $3.3\,\text{V}$ logic level issue | Add a logic level shifter (3.3V to 5V) |
| First LED is damaged/dead | Voltage spike on power-up | Add a $1000\,\mu\text{F}$ capacitor across power |
| Colors look washed out | Brightness set too low | Increase setBrightness() value (0--255) |
| Some LEDs in the middle are wrong | Damaged LED breaking the data chain | Replace the faulty LED or cut and rejoin the strip |
| ESP32 resets when LEDs turn on | Power supply cannot handle the current | Use 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