# WS2812 Module
| Since  | Origin / Contributor  | Maintainer  | Source  |
| :----- | :-------------------- | :---------- | :------ |
| 2015-02-05 | [Till Klocke](https://github.com/dereulenspiegel), [Thomas Soëte](https://github.com/Alkorin), [Christoph Thelen](https://github.com/docbacardi) | [Arnim Läuger](https://github.com/devsaurus) | [ws2812.c](../../components/modules/ws2812.c)|

ws2812 is a library to handle ws2812-like led strips.
It works at least on WS2812, WS2812b, APA104, SK6812 (RGB or RGBW).

!!! note

    The API on ESP32 differs from the API on ESP8266. For backwards compatibility please refer to [`lua_compat/ws2812_compat.lua`](../../lua_compat/ws2812_compat.lua`).

## ws2812.write()
Send data to up to 8 led strip using its native format which is generally Green,Red,Blue for RGB strips and Green,Red,Blue,White for RGBW strips.

#### Syntax
`ws2812.write(table, ...)`

#### Parameters
Variable number of tables, each describing a single strip. Required elements are:

- `pin` IO index, see [GPIO Overview](gpio.md#gpio-overview)
- `data` payload to be sent to one or more WS2812 like leds through GPIO2

Optional elements are:

- `reset` duration of the reset signal in multiples of 100ns. A duration of 0 generates no reset. The minimum possible value is 0. The maximum is 65534. The default value is 512 which generates a reset of 51.2us.
- `t0h` duration of the high period for a 0 code in multiples of 100ns. The minimum possible value is 1. The maximum is 32767. The default value is 4 which results in a high period of 400ns for each 0 code.
- `t0l` duration of the low period for a 0 code in multiples of 100ns. The minimum possible value is 1. The maximum is 32767. The default value is 7 which results in a low period of 700ns for each 0 code.
- `t1h` duration of the high period for a 1 code in multiples of 100ns. The minimum possible value is 1. The maximum is 32767. The default value is 8 which results in a high period of 800ns for each 1 code.
- `t1l` duration of the low period for a 1 code in multiples of 100ns. The minimum possible value is 1. The maximum is 32767. The default value is 6 which results in a low period of 600ns for each 1 code.

Payload type could be:

- `string` representing bytes to send
- `ws2812.buffer` see [Buffer module](#buffer-module)

#### Returns
`nil`

#### Example
```lua
ws2812.write({pin = 4, data = string.char(255, 0, 0, 255, 0, 0)}) -- turn the two first RGB leds to green
```

```lua
ws2812.write({pin = 4, string.char(0, 0, 0, 255, 0, 0, 0, 255)}) -- turn the two first RGBW leds to white
```

```lua
ws2812.write({pin =  4, data = string.char(255, 0, 0, 255, 0, 0)},
             {pin = 14, data = string.char(0, 255, 0, 0, 255, 0)}) -- turn the two first RGB leds to green on the first strip and red on the second strip
```

```lua
ws2812.write({pin = 8, reset = 800, t0h = 3, t0l = 9, t1h = 6, t1l = 6, data = string.char(1, 0, 0)}) -- turn the SK6812 GRB led on the ESP32-C3-DevKitM-1 to green
```

# Buffer module
For more advanced animations, it is useful to keep a "framebuffer" of the strip,
interact with it and flush it to the strip.

For this purpose, the ws2812 library offers a read/write buffer. This buffer has a `__tostring` method so that it can be printed. This is useful for debugging.

#### Example
Led chaser with a RGBW strip
```lua
local i, buffer = 0, ws2812.newBuffer(300, 4); buffer:fill(0, 0, 0, 0); tmr.create():alarm(50, 1, function()
  i = i + 1
  buffer:fade(2)
  buffer:set(i % buffer:size() + 1, 0, 0, 0, 255)
  ws2812.write({pin = 4, data = buffer})
end)
```

## ws2812.newBuffer()
Allocate a new memory buffer to store led values.

#### Syntax
`ws2812.newBuffer(numberOfLeds, bytesPerLed)`

#### Parameters
 - `numberOfLeds` length of the led strip
 - `bytesPerLed` 3 for RGB strips and 4 for RGBW strips

#### Returns
`ws2812.buffer`

## ws2812.buffer:get()
Return the value at the given position

#### Syntax
`buffer:get(index)`

#### Parameters
 - `index` position in the buffer (1 for first led)

#### Returns
`(color)`

#### Example
```lua
buffer = ws2812.newBuffer(32, 4)
print(buffer:get(1))
0	0	0	0
```

## ws2812.buffer:set()
Set the value at the given position

#### Syntax
`buffer:set(index, color)`

#### Parameters
 - `index` position in the buffer (1 for the first led)
 - `color` payload of the color

Payload could be:
- `number, number, ...` you should pass as many arguments as `bytesPerLed`
- `table` should contains `bytesPerLed` numbers
- `string` should contains `bytesPerLed` bytes

#### Returns
`nil`

#### Example
```lua
buffer = ws2812.newBuffer(32, 3)
buffer:set(1, 255, 0, 0) -- set the first led green for a RGB strip
```

```lua
buffer = ws2812.newBuffer(32, 4)
buffer:set(1, {0, 0, 0, 255}) -- set the first led white for a RGBW strip
```

```lua
buffer = ws2812.newBuffer(32, 3)
buffer:set(1, string.char(255, 0, 0)) -- set the first led green for a RGB strip
```

## ws2812.buffer:size()
Return the size of the buffer in number of leds

#### Syntax
`buffer:size()`

#### Parameters
none

#### Returns
`int`

## ws2812.buffer:fill()
Fill the buffer with the given color.
The number of given bytes must match the number of bytesPerLed of the buffer

#### Syntax
`buffer:fill(color)`

#### Parameters
 - `color` bytes of the color, you should pass as many arguments as `bytesPerLed`

#### Returns
`nil`

#### Example
```lua
buffer:fill(0, 0, 0) -- fill the buffer with black for a RGB strip
```

## ws2812.buffer:dump()
Returns the contents of the buffer (the pixel values) as a string. This can then be saved to a file or sent over a network.

#### Syntax
`buffer:dump()`

#### Returns
A string containing the pixel values. 

#### Example
```lua
local s = buffer:dump() 
```

## ws2812.buffer:replace()
Inserts a string (or a buffer) into another buffer with an offset.
The buffer must have the same number of colors per led or an error will be thrown.

#### Syntax
`buffer:replace(source[, offset])`

#### Parameters
 - `source` the pixel values to be set into the buffer. This is either a string or a buffer.
 - `offset` the offset where the source is to be placed in the buffer. Default is 1. Negative values can be used.

#### Returns
`nil`

#### Example
```lua
buffer:replace(anotherbuffer:dump()) -- copy one buffer into another via a string
buffer:replace(anotherbuffer) -- copy one buffer into another
newbuffer = buffer.sub(1)     -- make a copy of a buffer into a new buffer
```

## ws2812.buffer:mix()
This is a general method that loads data into a buffer that is a linear combination of data from other buffers. It can be used to copy a buffer or,
more usefully, do a cross fade. The pixel values are computed as integers and then range limited to [0, 255]. This means that negative
factors work as expected, and that the order of combining buffers does not matter.

#### Syntax
`buffer:mix(factor1, buffer1, ...)`

#### Parameters
 - `factor1` This is the factor that the contents of `buffer1` are multiplied by. This factor is scaled by a factor of 256. Thus `factor1` value of 256 is a factor of 1.0.
 - `buffer1` This is the source buffer. It must be of the same shape as the destination buffer.

There can be any number of factor/buffer pairs.

#### Returns
`nil`

#### Example
```lua
-- loads buffer with a crossfade between buffer1 and buffer2
buffer:mix(256 - crossmix, buffer1, crossmix, buffer2)

-- multiplies all values in buffer by 0.75
-- This can be used in place of buffer:fade
buffer:mix(192, buffer)
```

## ws2812.buffer:power()
Computes the total energy requirement for the buffer. This is merely the total sum of all the pixel values (which assumes that each color in each
pixel consumes the same amount of power). A real WS2812 (or WS2811) has three constant current drivers of 20mA -- one for each of R, G and B. The
pulse width modulation will cause the *average* current to scale linearly with pixel value. 

#### Syntax
`buffer:power()`

#### Returns
An integer which is the sum of all the pixel values.

#### Example
```lua
-- Dim the buffer to no more than the PSU can provide
local psu_current_ma = 1000
local led_current_ma = 20
local led_sum = psu_current_ma * 255 / led_current_ma

local p = buffer:power()
if p > led_sum then
  buffer:mix(256 * led_sum / p, buffer) -- power is now limited
end
```

## ws2812.buffer:fade()
Fade in or out. Defaults to out. Multiply or divide each byte of each led with/by the given value. Useful for a fading effect. 

#### Syntax
`buffer:fade(value [, direction])`

#### Parameters
 - `value` value by which to divide or multiply each byte
 - `direction` ws2812.FADE\_IN or ws2812.FADE\_OUT. Defaults to ws2812.FADE\_OUT

#### Returns
`nil`

#### Example
```lua
buffer:fade(2)
buffer:fade(2, ws2812.FADE_IN)
```
## ws2812.buffer:shift()
Shift the content of (a piece of) the buffer in positive or negative direction. This allows simple animation effects. A slice of the buffer can be specified by using the 
standard start and end offset Lua notation. Negative values count backwards from the end of the buffer.

#### Syntax
`buffer:shift(value [, mode[, i[, j]]])`

#### Parameters
 - `value` number of pixels by which to rotate the buffer. Positive values rotate forwards, negative values backwards. 
 - `mode` is the shift mode to use. Can be one of `ws2812.SHIFT_LOGICAL` or `ws2812.SHIFT_CIRCULAR`. In case of SHIFT\_LOGICAL, the freed pixels are set to 0 (off). In case of SHIFT\_CIRCULAR, the buffer is treated like a ring buffer, inserting the pixels falling out on one end again on the other end. Defaults to SHIFT\_LOGICAL. 
 - `i` is the first offset in the buffer to be affected. Negative values are permitted and count backwards from the end. Default is 1.
 - `j` is the last offset in the buffer to be affected. Negative values are permitted and count backwards from the end. Default is -1.

#### Returns
`nil`

#### Example
```lua
buffer:shift(3)
```

## ws2812.buffer:sub()
This implements the extraction function like `string.sub`. The indexes are in leds and all the same rules apply.

#### Syntax
`buffer1:sub(i[, j])`

#### Parameters
 - `i` This is the start of the extracted data. Negative values can be used.
 - `j` this is the end of the extracted data. Negative values can be used. The default is -1.

#### Returns
A buffer containing the extracted piece.

#### Example
```
b = buffer:sub(1,10)
```

## ws2812.buffer:__concat()
This implements the `..` operator to concatenate two buffers. They must have the same number of colors per led.

#### Syntax
`buffer1 .. buffer2`

#### Parameters
 - `buffer1` this is the start of the resulting buffer
 - `buffer2` this is the end of the resulting buffer

#### Returns
The concatenated buffer.

#### Example
```
ws2812.write({pin = 4, data = buffer1 .. buffer2})
```
