lib/lib_basic/TasmotaLED/TASMOTALED_DOCUMENTATION.md
TasmotaLED is a lightweight, high-performance library for controlling addressable LED strips on ESP32 microcontrollers. It serves as a streamlined replacement for the NeoPixelBus library, focusing on efficient pixel pushing with minimal memory overhead while supporting multiple hardware acceleration methods (RMT, SPI, I2S).
Key Features:
Version: 1.0
Author: Stephan Hadinger
License: GNU General Public License v3.0
Copyright: 2024
TasmotaLED is designed with the following principles:
┌─────────────────────────────────────────────────────────────┐
│ Application Layer │
│ (Tasmota Light Driver) │
└────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ TasmotaLED Class │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ _buf_work │ │ _buf_show │ │ Pixel Format │ │
│ │ (editable) │─▶│ (internal) │ │ Conversion │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ TasmotaLEDPusher (Abstract) │
└────────────────────┬────────────────────────────────────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────┐ ┌──────────┐
│ RMT Pusher │ │ SPI │ │ I2S │
│ (Primary) │ │ Pusher │ │ Pusher │
└──────┬───────┘ └────┬─────┘ └────┬─────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────┐
│ ESP32 Hardware Peripherals │
│ (RMT / SPI / I2S Controllers) │
└─────────────────────────────────────────┘
TasmotaLED uses a dual-buffer system:
Work Buffer (_buf_work):
pixel_count × pixel_size bytesShow Buffer (_buf_show):
Show() call with format conversionpixel_count × pixel_size bytesMemory Allocation Example:
┌─────────────────────────────────────────────────────────────┐
│ TasmotaLED │
├─────────────────────────────────────────────────────────────┤
│ - _type: uint16_t │
│ - _pixel_order: uint8_t │
│ - _w_before: bool │
│ - _pixel_reverse: bool │
│ - _timing: uint8_t │
│ - _started: bool │
│ - _dirty: bool │
│ - _raw_format: bool │
│ - _pixel_count: uint16_t │
│ - _pixel_size: uint8_t │
│ - _buf_work: uint8_t* │
│ - _buf_show: uint8_t* │
│ - _pixel_matrix: const uint8_t(*)[3] │
│ - _pusher: TasmotaLEDPusher* │
├─────────────────────────────────────────────────────────────┤
│ + TasmotaLED(type, num_leds) │
│ + ~TasmotaLED() │
│ + Begin(): bool │
│ + Show(): void │
│ + SetPixelColor(index, wrgb): void │
│ + GetPixelColor(index): uint32_t │
│ + ClearTo(rgbw, first, last): void │
│ + SetPixelCount(num_leds): void │
│ + SetPixelSubType(type): void │
│ + SetPusher(pusher): void │
│ + CanShow(): bool │
│ + Pixels(): uint8_t* │
│ + PixelCount(): uint16_t │
│ + PixelSize(): uint8_t │
│ + GetType(): uint8_t │
│ + IsDirty(): bool │
│ + Dirty(): void │
│ + SetPixelReverse(bool): void │
│ + SetRawFormat(raw): void │
└─────────────────────────────────────────────────────────────┘
│
│ uses
▼
┌─────────────────────────────────────────────────────────────┐
│ TasmotaLEDPusher (Abstract) │
├─────────────────────────────────────────────────────────────┤
│ # _initialized: bool │
│ # _err: esp_err_t │
│ # _pixel_count: uint16_t │
│ # _pixel_size: uint16_t │
│ # _led_timing: const TasmotaLED_Timing* │
├─────────────────────────────────────────────────────────────┤
│ + Begin(pixel_count, pixel_size, timing): bool │
│ + Push(buf): bool = 0 │
│ + CanShow(): bool = 0 │
│ + SetPixelCount(pixel_count): bool = 0 │
│ + Initialized(): bool │
│ + Error(): esp_err_t │
│ + static ResolveHardware(hw): uint32_t │
│ + static Create(hw, gpio): TasmotaLEDPusher* │
└─────────────────────────────────────────────────────────────┘
△
│
┌─────────────────┼─────────────────┐
│ │ │
┌─────────┴──────────┐ ┌────┴─────────┐ ┌─────┴──────────┐
│ TasmotaLEDPusherRMT│ │TasmotaLED │ │ TasmotaLED │
│ │ │PusherSPI │ │PusherI2S │
├────────────────────┤ ├──────────────┤ ├────────────────┤
│ - _pin: int8_t │ │- _pin: int8_t│ │(Future) │
│ - _channel: handle │ │- _spi_strip │ │ │
│ - _led_encoder │ │- _with_dma │ │ │
│ - _tx_config │ │ │ │ │
├────────────────────┤ ├──────────────┤ ├────────────────┤
│ + Push(): bool │ │+ Push(): bool│ │ │
│ + CanShow(): bool │ │+ CanShow() │ │ │
└────────────────────┘ └──────────────┘ └────────────────┘
The LED type is encoded in a 16-bit value with the following bit layout:
Bits 15-8: Timing Code (WS2812, SK6812, etc.)
Bit 7: W Channel Position (0=after RGB, 1=before RGB)
Bits 6-4: Pixel Order (GRB, RGB, RBG, BRG, BGR, GBR)
Bits 3-0: Bytes per Pixel (3=RGB, 4=RGBW)
┌────────┬───┬───────┬──────────┐
│15 8 │ 7 │ 6 4 │ 3 0 │
├────────┼───┼───────┼──────────┤
│ Timing │ W │ Order │ Size │
└────────┴───┴───────┴──────────┘
| Value | Enum | Description | Bytes per Pixel |
|---|---|---|---|
0x0 | TasmotaLed_1_Def | Default (same as RGB) | 3 |
0x1 | TasmotaLed_3_RGB | RGB format | 3 |
0x2 | TasmotaLed_4_WRGB | RGBW format | 4 |
| Value | Enum | Description | Channel Order |
|---|---|---|---|
0b000 | TasmotaLed_Def | Default (GRB) | G, R, B |
0b001 | TasmotaLed_GRB | Green-Red-Blue | G, R, B |
0b010 | TasmotaLed_RGB | Red-Green-Blue | R, G, B |
0b011 | TasmotaLed_RBG | Red-Blue-Green | R, B, G |
0b100 | TasmotaLed_BRG | Blue-Red-Green | B, R, G |
0b101 | TasmotaLed_BGR | Blue-Green-Red | B, G, R |
0b110 | TasmotaLed_GBR | Green-Blue-Red | G, B, R |
| Value | Enum | Description | Format |
|---|---|---|---|
0 | TasmotaLed_xxxW | W after color | RGB + W |
1 | TasmotaLed_Wxxx | W before color | W + RGB |
| Value | Enum | Description | T0H | T0L | T1H | T1L | Reset |
|---|---|---|---|---|---|---|---|
0 | TasmotaLed_WS2812 | WS2812/WS2812B | 400ns | 850ns | 800ns | 450ns | 80µs |
1 | TasmotaLed_SK6812 | SK6812 | 300ns | 900ns | 600ns | 600ns | 80µs |
enum TasmotaLEDTypes : uint16_t {
// WS2812 with GRB ordering (most common)
ws2812_grb = TasmotaLed_3_RGB | TasmotaLed_GRB | TasmotaLed_WS2812,
// Value: 0x0011 (decimal 17)
// SK6812 with GRBW ordering and W after RGB
sk6812_grbw = TasmotaLed_4_WRGB | TasmotaLed_GRB | TasmotaLed_xxxW | TasmotaLed_SK6812,
// Value: 0x0112 (decimal 274)
// SK6812 with GRB ordering (no white channel)
sk6812_grb = TasmotaLed_3_RGB | TasmotaLed_GRB | TasmotaLed_SK6812,
// Value: 0x0111 (decimal 273)
};
// WS2812 RGB strip with GRB ordering
uint16_t type1 = TasmotaLed_3_RGB | TasmotaLed_GRB | TasmotaLed_WS2812;
// Binary: 0000 0000 0001 0001 = 0x0011
// SK6812 RGBW strip with RGB ordering and W first
uint16_t type2 = TasmotaLed_4_WRGB | TasmotaLed_RGB | TasmotaLed_Wxxx | TasmotaLed_SK6812;
// Binary: 0000 0001 1010 0010 = 0x01A2
// WS2812 RGB strip with BGR ordering
uint16_t type3 = TasmotaLed_3_RGB | TasmotaLed_BGR | TasmotaLed_WS2812;
// Binary: 0000 0000 0101 0001 = 0x0051
| Hardware | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 | ESP32-C2 | ESP32-C6 |
|---|---|---|---|---|---|---|
| RMT | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| SPI | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| I2S | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
Hardware acceleration is selected using the TasmotaLEDHardware enum:
enum TasmotaLEDHardware : uint32_t {
TasmotaLed_HW_Default = 0x000000, // Auto-select best available
TasmotaLed_RMT = (1 << 0) << 16, // 0x010000 - RMT peripheral
TasmotaLed_SPI = (1 << 1) << 16, // 0x020000 - SPI peripheral
TasmotaLed_I2S = (1 << 2) << 16, // 0x040000 - I2S peripheral
TasmotaLed_HW_None = 0xFF << 16, // 0xFF0000 - No hardware support
};
When TasmotaLed_HW_Default is specified, the library selects hardware in this order:
Hardware support can be enabled/disabled at compile time:
// In your build configuration or before including TasmotaLED
#define TASMOTALED_HARDWARE_RMT 1 // Enable RMT (default: 1)
#define TASMOTALED_HARDWARE_I2S 0 // Enable I2S (default: 0)
#define TASMOTALED_HARDWARE_SPI 0 // Enable SPI (default: 0)
Note: If no hardware is explicitly enabled, SPI is automatically enabled as fallback.
Advantages:
Technical Details:
Timing Precision:
WS2812: T0H=400ns (16 ticks), T0L=850ns (34 ticks)
T1H=800ns (32 ticks), T1L=450ns (18 ticks)
Reset=80µs (3200 ticks)
SK6812: T0H=300ns (12 ticks), T0L=900ns (36 ticks)
T1H=600ns (24 ticks), T1L=600ns (24 ticks)
Reset=80µs (3200 ticks)
Advantages:
Technical Details:
0 = 100, 1 = 110Bit Encoding:
LED bit 0: SPI bits 100 (high for 400ns, low for 800ns at 2.5MHz)
LED bit 1: SPI bits 110 (high for 800ns, low for 400ns at 2.5MHz)
Status: Planned but not yet implemented
Advantages:
TasmotaLED(uint16_t type, uint16_t num_leds)
Creates a new TasmotaLED instance.
Parameters:
type: LED type encoding (see LED Type Encoding section)num_leds: Number of LEDs in the stripExample:
// Create a 60-LED WS2812 strip with GRB ordering
TasmotaLED strip(ws2812_grb, 60);
// Create a 100-LED SK6812 RGBW strip
TasmotaLED strip(sk6812_grbw, 100);
~TasmotaLED()
Cleans up resources, frees buffers, and deletes the pusher instance.
void SetPusher(TasmotaLEDPusher *pusher)
Sets the hardware pusher implementation. Must be called before Begin().
Parameters:
pusher: Pointer to a TasmotaLEDPusher instance (RMT, SPI, or I2S)Example:
TasmotaLED strip(ws2812_grb, 60);
TasmotaLEDPusher *pusher = TasmotaLEDPusher::Create(TasmotaLed_RMT, 5);
strip.SetPusher(pusher);
bool Begin(void)
Initializes the hardware pusher and prepares the strip for operation.
Returns: true if initialization successful, false otherwise
Example:
if (strip.Begin()) {
// Strip is ready to use
} else {
// Initialization failed
}
void SetPixelColor(int32_t index, uint32_t wrgb)
Sets the color of a single pixel.
Parameters:
index: Pixel index (0-based, negative values count from end)wrgb: Color value in 0xWWRRGGBB format (or 0xRRGGBB for RGB strips)Example:
strip.SetPixelColor(0, 0xFF0000); // Red
strip.SetPixelColor(1, 0x00FF00); // Green
strip.SetPixelColor(2, 0x0000FF); // Blue
strip.SetPixelColor(-1, 0xFFFFFF); // Last pixel white
strip.SetPixelColor(10, 0x80FF8000); // RGBW: W=0x80, R=0xFF, G=0x80, B=0x00
uint32_t GetPixelColor(int32_t index)
Retrieves the color of a single pixel.
Parameters:
index: Pixel index (0-based, negative values count from end)Returns: Color value in 0xWWRRGGBB or 0xRRGGBB format
Example:
uint32_t color = strip.GetPixelColor(5);
uint8_t red = (color >> 16) & 0xFF;
uint8_t green = (color >> 8) & 0xFF;
uint8_t blue = color & 0xFF;
void ClearTo(uint32_t rgbw, int32_t first = 0, int32_t last = -1)
Sets a range of pixels to the same color.
Parameters:
rgbw: Color value in 0xWWRRGGBB or 0xRRGGBB formatfirst: First pixel index (default: 0)last: Last pixel index (default: -1 = last pixel)Example:
strip.ClearTo(0x000000); // Clear entire strip to black
strip.ClearTo(0xFF0000, 0, 9); // Set first 10 pixels to red
strip.ClearTo(0x00FF00, 10, 19); // Set pixels 10-19 to green
strip.ClearTo(0x0000FF, -10, -1); // Set last 10 pixels to blue
void Show(void)
Pushes the pixel buffer to the LED strip. Converts from WRGB/RGB format to the strip's native format and transmits via hardware.
Example:
strip.SetPixelColor(0, 0xFF0000);
strip.SetPixelColor(1, 0x00FF00);
strip.Show(); // Update the strip
bool CanShow(void) const
Checks if the strip is ready to accept a new Show() command.
Returns: true if ready, false if previous transmission still in progress
Example:
if (strip.CanShow()) {
strip.Show();
}
void SetPixelCount(uint16_t num_leds)
Changes the number of LEDs in the strip. Reallocates buffers if necessary.
Parameters:
num_leds: New number of LEDsExample:
strip.SetPixelCount(100); // Resize to 100 LEDs
void SetPixelSubType(uint8_t type)
Changes only the pixel ordering and size (lower 8 bits of type), keeping timing unchanged.
Parameters:
type: New subtype (bits 0-7 of type encoding)Example:
// Change from GRB to RGB ordering
strip.SetPixelSubType(TasmotaLed_3_RGB | TasmotaLed_RGB);
void SetRawFormat(bool raw_format)
Enables/disables raw format mode. When enabled, buffer is copied directly without format conversion.
Parameters:
raw_format: true for raw mode, false for automatic conversionExample:
strip.SetRawFormat(true); // Disable format conversion
uint16_t PixelCount(void) const
Returns the number of LEDs in the strip.
uint8_t PixelSize(void) const
Returns the number of bytes per pixel (3 for RGB, 4 for RGBW).
uint8_t GetType(void) const
Returns the LED type encoding.
uint8_t * Pixels(void) const
Returns a pointer to the work buffer for direct manipulation.
Example:
uint8_t *buf = strip.Pixels();
// Direct buffer access (advanced usage)
buf[0] = 0xFF; // Set first byte
bool IsDirty(void) const
Returns the dirty flag (for NeoPixelBus compatibility, but not used internally).
void Dirty(void)
Sets the dirty flag to true.
static TasmotaLEDPusher * Create(uint32_t hw, int8_t gpio)
Creates a pusher instance for the specified hardware type.
Parameters:
hw: Hardware type (TasmotaLed_RMT, TasmotaLed_SPI, TasmotaLed_I2S, or TasmotaLed_HW_Default)gpio: GPIO pin number for LED data outputReturns: Pointer to pusher instance, or nullptr if creation failed
Example:
TasmotaLEDPusher *pusher = TasmotaLEDPusher::Create(TasmotaLed_RMT, 5);
if (pusher) {
strip.SetPusher(pusher);
}
static uint32_t ResolveHardware(uint32_t hw)
Resolves hardware type based on SOC capabilities.
Parameters:
hw: Requested hardware typeReturns: Resolved hardware type (removes unsupported flags)
virtual bool Begin(uint16_t pixel_count, uint16_t pixel_size,
const TasmotaLED_Timing * led_timing)
Initializes the hardware pusher.
Parameters:
pixel_count: Number of LEDspixel_size: Bytes per pixel (3 or 4)led_timing: Pointer to timing structureReturns: true if successful
virtual bool Push(uint8_t *buf) = 0
Pushes pixel data to the LED strip (pure virtual).
Parameters:
buf: Pointer to pixel buffer in strip formatReturns: true if successful
virtual bool CanShow(void) = 0
Checks if hardware is ready for next transmission (pure virtual).
Returns: true if ready
virtual bool SetPixelCount(uint16_t pixel_count) = 0
Updates pixel count (pure virtual).
Parameters:
pixel_count: New number of pixelsReturns: true if successful
bool Initialized(void) const
Returns initialization status.
esp_err_t Error(void) const
Returns last error code.
#include "TasmotaLED.h"
#include "TasmotaLEDPusher.h"
// For WS2812 RGB strip with 60 LEDs
TasmotaLED strip(ws2812_grb, 60);
// For SK6812 RGBW strip with 100 LEDs
TasmotaLED strip(sk6812_grbw, 100);
// Custom configuration
uint16_t custom_type = TasmotaLed_3_RGB | TasmotaLed_RGB | TasmotaLed_WS2812;
TasmotaLED strip(custom_type, 144);
// Auto-select best hardware for GPIO 5
TasmotaLEDPusher *pusher = TasmotaLEDPusher::Create(TasmotaLed_HW_Default, 5);
if (pusher) {
strip.SetPusher(pusher);
} else {
// Handle error
}
// Or explicitly request RMT
TasmotaLEDPusher *pusher = TasmotaLEDPusher::Create(TasmotaLed_RMT, 5);
if (!strip.Begin()) {
// Handle initialization error
Serial.println("Failed to initialize LED strip");
}
// Set colors
strip.ClearTo(0x000000); // Clear to black
strip.SetPixelColor(0, 0xFF0000); // First pixel red
strip.SetPixelColor(1, 0x00FF00); // Second pixel green
strip.Show(); // Update strip
// Create custom type: RGB, BGR ordering, WS2812 timing
uint16_t custom_type = TasmotaLed_3_RGB | // 3 bytes per pixel
TasmotaLed_BGR | // BGR ordering
TasmotaLed_WS2812; // WS2812 timing
TasmotaLED strip(custom_type, 60);
// SK6812 RGBW with W channel before RGB
uint16_t rgbw_type = TasmotaLed_4_WRGB | // 4 bytes per pixel
TasmotaLed_RGB | // RGB ordering
TasmotaLed_Wxxx | // W first
TasmotaLed_SK6812; // SK6812 timing
TasmotaLED strip(rgbw_type, 100);
// Strip 1 on GPIO 5
TasmotaLED strip1(ws2812_grb, 60);
TasmotaLEDPusher *pusher1 = TasmotaLEDPusher::Create(TasmotaLed_RMT, 5);
strip1.SetPusher(pusher1);
strip1.Begin();
// Strip 2 on GPIO 18
TasmotaLED strip2(sk6812_grbw, 100);
TasmotaLEDPusher *pusher2 = TasmotaLEDPusher::Create(TasmotaLed_RMT, 18);
strip2.SetPusher(pusher2);
strip2.Begin();
strip.SetRawFormat(true); // Disable automatic format conversion
// Now buffer must be in strip's native format (e.g., GRB for WS2812)
uint8_t *buf = strip.Pixels();
buf[0] = 0xFF; // Green
buf[1] = 0x00; // Red
buf[2] = 0x00; // Blue
strip.Show();
In your platformio.ini or build flags:
build_flags =
-DTASMOTALED_HARDWARE_RMT=1
-DTASMOTALED_HARDWARE_SPI=1
-DTASMOTALED_HARDWARE_I2S=0
Or in your code before including TasmotaLED:
#define TASMOTALED_HARDWARE_RMT 1
#define TASMOTALED_HARDWARE_SPI 0
#define TASMOTALED_HARDWARE_I2S 0
#include "TasmotaLED.h"
| Component | Size | Description |
|---|---|---|
| TasmotaLED object | ~60 bytes | Class instance |
| Work buffer | pixels × size | Editable buffer (RGB or RGBW) |
| Show buffer | pixels × size | Internal transmission buffer |
| Pusher object | ~40-80 bytes | Hardware implementation |
| Total | ~100 + (2 × pixels × size) |
| Configuration | Memory Usage |
|---|---|
| 60 RGB pixels | ~460 bytes |
| 144 RGB pixels | ~964 bytes |
| 300 RGB pixels | ~1,900 bytes |
| 512 RGB pixels | ~3,172 bytes |
| 60 RGBW pixels | ~580 bytes |
| 144 RGBW pixels | ~1,252 bytes |
SPI requires 3× buffer for encoding:
| Configuration | Additional Memory |
|---|---|
| 60 RGB pixels | +540 bytes |
| 144 RGB pixels | +1,296 bytes |
| 300 RGB pixels | +2,700 bytes |
| Operation | Time | Notes |
|---|---|---|
ClearTo(0x000000) | ~15 µs | Optimized memset |
ClearTo(0xFF0000) | ~124 µs | Per-pixel write |
SetPixelColor() | ~0.2 µs | Single pixel |
| Format conversion | ~124 µs | RGB→GRB conversion |
Show() (RMT) | ~16.2 ms | Actual transmission |
Show() (SPI) | ~16.6 ms | Transmission + encoding |
Transmission time depends on pixel count and timing:
WS2812 (30 µs per pixel):
SK6812 (30 µs per pixel):
Maximum Refresh Rate:
Minimize Show() Calls
// Bad: Multiple Show() calls
for (int i = 0; i < 60; i++) {
strip.SetPixelColor(i, color);
strip.Show(); // 60 transmissions!
}
// Good: Single Show() call
for (int i = 0; i < 60; i++) {
strip.SetPixelColor(i, color);
}
strip.Show(); // 1 transmission
Use ClearTo() for Bulk Operations
// Faster than loop with SetPixelColor()
strip.ClearTo(0xFF0000, 0, 29); // First 30 pixels red
Check CanShow() Before Show()
if (strip.CanShow()) {
strip.Show();
}
Direct Buffer Access for Complex Patterns
uint8_t *buf = strip.Pixels();
// Direct manipulation (advanced)
for (int i = 0; i < strip.PixelCount() * strip.PixelSize(); i++) {
buf[i] = pattern[i];
}
strip.Show();
#include "TasmotaLED.h"
#include "TasmotaLEDPusher.h"
// Create strip instance
TasmotaLED strip(ws2812_grb, 60);
void setup() {
// Create pusher with auto hardware selection
TasmotaLEDPusher *pusher = TasmotaLEDPusher::Create(TasmotaLed_HW_Default, 5);
if (pusher) {
strip.SetPusher(pusher);
if (strip.Begin()) {
// Strip ready
strip.ClearTo(0x000000); // Clear to black
strip.Show();
}
}
}
// Set individual pixels
strip.SetPixelColor(0, 0xFF0000); // Red
strip.SetPixelColor(1, 0x00FF00); // Green
strip.SetPixelColor(2, 0x0000FF); // Blue
// Set range of pixels
strip.ClearTo(0xFF0000, 0, 9); // First 10 pixels red
// Update strip
strip.Show();
TasmotaLED strip(sk6812_grbw, 60);
// Pure white using W channel
strip.ClearTo(0xFF000000); // W=0xFF, RGB=0
// Warm white (W + Red)
strip.ClearTo(0x80FF0000); // W=0x80, R=0xFF, G=0, B=0
// RGB color (no W)
strip.ClearTo(0x00FF00FF); // W=0, R=0xFF, G=0, B=0xFF (Magenta)
strip.Show();
void loop() {
// Check if strip is ready before updating
if (strip.CanShow()) {
// Update pixels
for (int i = 0; i < strip.PixelCount(); i++) {
strip.SetPixelColor(i, colors[i]);
}
strip.Show();
}
// Other code continues without blocking
}
TasmotaLED is designed to integrate seamlessly with Tasmota's light driver system. Here's how it fits into the Tasmota architecture:
Driver Initialization (FUNC_INIT)
void TasmotaLEDInit(void) {
// Create strip based on Settings
uint16_t led_type = Settings->light_type;
uint16_t led_count = Settings->light_pixels;
int8_t gpio = Pin(GPIO_LED);
strip = new TasmotaLED(led_type, led_count);
// Create pusher with hardware auto-selection
TasmotaLEDPusher *pusher = TasmotaLEDPusher::Create(
TasmotaLed_HW_Default, gpio);
if (pusher) {
strip->SetPusher(pusher);
if (strip->Begin()) {
AddLog(LOG_LEVEL_INFO, "LED: Initialized %d pixels on GPIO %d",
led_count, gpio);
}
}
}
Pixel Updates (FUNC_SET_CHANNELS)
void TasmotaLEDUpdate(void) {
// Get color data from Tasmota light engine
for (int i = 0; i < strip->PixelCount(); i++) {
uint32_t color = GetPixelColorFromLightEngine(i);
strip->SetPixelColor(i, color);
}
// Push to hardware
if (strip->CanShow()) {
strip->Show();
}
}
Configuration Changes
void TasmotaLEDReconfigure(void) {
// Handle pixel count changes
if (new_pixel_count != strip->PixelCount()) {
strip->SetPixelCount(new_pixel_count);
}
// Handle type changes
if (new_led_type != strip->GetType()) {
strip->SetPixelSubType(new_led_type & 0xFF);
}
}
When integrated with Tasmota, these commands control the LED strip:
| Command | Description | Example |
|---|---|---|
Pixels | Set number of LEDs | Pixels 60 |
Scheme | Set color scheme | Scheme 2 |
Speed | Set animation speed | Speed 10 |
Width | Set effect width | Width 1 |
Color | Set RGB color | Color #FF0000 |
White | Set white channel | White 50 |
Dimmer | Set brightness | Dimmer 75 |
Fade | Enable fade | Fade 1 |
Tasmota stores LED configuration in Settings structure:
struct SETTINGS {
// ...
uint16_t light_pixels; // Number of LEDs
uint8_t light_type; // LED type encoding
uint8_t light_scheme; // Animation scheme
uint8_t light_speed; // Animation speed
uint8_t light_width; // Effect width
// ...
};
Tasmota automatically selects the best hardware based on:
uint32_t TasmotaSelectHardware(void) {
uint32_t hw = TasmotaLed_HW_Default;
// Force SPI on ESP32-C2 (no RMT)
#ifdef CONFIG_IDF_TARGET_ESP32C2
hw = TasmotaLed_SPI;
#endif
// User override via SetOption
if (Settings->flag5.led_use_spi) {
hw = TasmotaLed_SPI;
}
return hw;
}
Symptoms: No LEDs light up after calling Show()
Possible Causes:
Solutions:
// Check initialization
if (!strip.Begin()) {
Serial.println("Failed to initialize");
// Check pusher creation
if (pusher == nullptr) {
Serial.println("Pusher creation failed");
}
}
// Verify GPIO
Serial.printf("Using GPIO %d\n", gpio_pin);
// Test with simple pattern
strip.ClearTo(0xFF0000); // All red
strip.Show();
Symptoms: Colors appear incorrect (e.g., red shows as green)
Possible Causes:
Solutions:
// Try different orderings
strip.SetPixelSubType(TasmotaLed_3_RGB | TasmotaLed_RGB); // RGB
strip.SetPixelSubType(TasmotaLed_3_RGB | TasmotaLed_GRB); // GRB
strip.SetPixelSubType(TasmotaLed_3_RGB | TasmotaLed_BGR); // BGR
// Test each ordering
strip.ClearTo(0xFF0000); // Should be red
strip.Show();
Symptoms: Random flickering, incorrect colors, or partial updates
Possible Causes:
Solutions:
// Try different timing
uint16_t type_ws2812 = TasmotaLed_3_RGB | TasmotaLed_GRB | TasmotaLed_WS2812;
uint16_t type_sk6812 = TasmotaLed_3_RGB | TasmotaLed_GRB | TasmotaLed_SK6812;
// Check power supply (5V, sufficient amperage)
// Add capacitor (1000µF) across power supply
// Keep data cable short (<1m) or use level shifter
Symptoms: Begin() returns false, crashes, or resets
Possible Causes:
Solutions:
// Check available heap
Serial.printf("Free heap: %d bytes\n", ESP.getFreeHeap());
// Calculate required memory
uint32_t required = strip.PixelCount() * strip.PixelSize() * 2;
Serial.printf("Required: %d bytes\n", required);
// Reduce pixel count if necessary
if (required > ESP.getFreeHeap() / 2) {
strip.SetPixelCount(smaller_count);
}
Symptoms: Slow updates, low frame rate
Possible Causes:
Show() callsSolutions:
// Batch updates
for (int i = 0; i < strip.PixelCount(); i++) {
strip.SetPixelColor(i, colors[i]);
}
strip.Show(); // Single show call
// Use ClearTo() for bulk operations
strip.ClearTo(0xFF0000, 0, 29); // Faster than loop
// Check hardware
Serial.printf("Using hardware: 0x%08X\n", hw_type);
// Verify CanShow() before Show()
if (strip.CanShow()) {
strip.Show();
}
Enable debug logging to diagnose issues:
// In Tasmota, set log level
SerialLog 4 // Debug level
// Look for these messages:
// LED: RMT gpio 5
// LED: SPI gpio 5
// LED: Error create RMT bus failed 5 err=XXX
TASMOTALED_HARDWARE_SPI is enabledVerify timing with oscilloscope or logic analyzer:
WS2812 Expected:
SK6812 Expected:
The library uses a lookup table for pixel ordering:
static const uint8_t TASMOTALED_CHANNEL_ORDERS[8][3] = {
{1, 0, 2}, // Def=GRB (0)
{1, 0, 2}, // GRB (1)
{0, 1, 2}, // RGB (2)
{0, 2, 1}, // RBG (3)
{2, 1, 0}, // BRG (4)
{1, 2, 0}, // BGR (5)
{2, 0, 1}, // GBR (6)
{1, 0, 2} // GRB (7) - fallback
};
Interpretation:
Example: GRB ordering {1, 0, 2} means:
typedef struct TasmotaLED_Timing {
uint16_t T0H; // Bit 0 high time (nanoseconds)
uint16_t T0L; // Bit 0 low time (nanoseconds)
uint16_t T1H; // Bit 1 high time (nanoseconds)
uint16_t T1L; // Bit 1 low time (nanoseconds)
uint32_t Reset; // Reset time (nanoseconds)
} TasmotaLED_Timing;
| Feature | TasmotaLED | NeoPixelBus |
|---|---|---|
| Memory | Lower (2 buffers) | Higher (3+ buffers) |
| Code Size | ~15 KB | ~40 KB |
| Hardware | RMT, SPI, I2S | RMT, I2S, UART, BitBang |
| ESP8266 | ❌ No | ✅ Yes |
| ESP32 | ✅ Yes | ✅ Yes |
| Buffer Swap | No (copy on Show) | Yes (double buffering) |
| Dirty Flag | Ignored | Used |
| API | Similar | Full-featured |
| Performance | Optimized | Feature-rich |
TasmotaLED - Lightweight implementation for addressable LEDs
Copyright (C) 2024 Stephan Hadinger
This library is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
| Version | Date | Changes |
|---|---|---|
| 1.0 | 2024 | Initial release with RMT and SPI support |
End of Documentation