You can control multiple LED strips. WS2812 - 1 is also controlled by Tasmota's light controls. It is still possible to control this light strip with Berry, but whenever you use Tasmota light controls they will temporarily overrid Berry animations.
To avoid any conflict between native WS2812 and Berry control, you can use Scheme 14 which disables native WS2812.
You first need to define the low-level Leds object that describes the hardware strip of connected leds.
You can then define higher level objects like sub-strips (if there are actually several strips chained together like rings) or LED matrix.
Leds(pixels:int, gpio:int [,model:int ,rmt:int]) -> instance<Leds> Creates a Leds instance for a linear leds strip pixels: number of leds gpio: physical gpio number model: (optional) LED model, default: Leds.WS2812_GRB, alternative Leds.SK6812_GRBW rmt: (optional) RMTchannel to use, or auto-select (see below)
Once a Leds object, you can use sub-objects:
<strip>.create_matrix(width:int, height:int [, offset:int]) -> instance<Leds_matrix> Creates a Leds_matrix instance from a Leds instance width: number of leds horizontally height: number of leds vertically offset: number of leds to skip until start of matrix You can use set_alternate(true) to enabled alternate lines (i.e. zigzag mode).
<strip>.create_segment(offset:int, pixels:int) -> instance<Leds_segment> Creates a virtual segment from a physical Leds strip, from Led number offset with pixels leds.
Methods are the equivalent low-level from NeoPixelBus. All colors are in 0xRRGGBB format (24 bits) or 0xWWRRGGBB format (32 bits).
clear() -> nil Clear all led (set to black)
clear_to(col:color [, bri:int]) -> nil Set all leds to the specified color. bri (0..100) is optional and default to 100%
show() -> nil Pushes the internal buffer to leds. May be ignored if a show command is already in progress. Use can_show() to see if show() is possible
can_show() -> bool Indicates if show() is possible, i.e. no transfer is ongoing
is_dirty() -> bool Indicates if a led was changed since last show()
dirty() -> nil Forces a refresh during next show()
pixel_size() -> int Returns the number of bytes per pixel
pixel_count() -> int Returns the number of leds in the strip/matrix
clear_to(col:color [, bri:int]) -> nil Clears all leds to the specified color. bri is optional and default to 100%
set_pixel_color(idx:int, col:color [, bri:int]) -> nil Set led number idx to the specified color. bri (0..100) is optional and default to 100%
set_matrix_pixel_color(x:int, y:int, col:color [, bri:int]) -> nil (only Leds_matrix) Set led number of coordinates x/y to the specified color. bri is optional and default to 100%
set_alternate(bool) -> nil (only Leds_matrix) Sets the matrix as alternate cabling (i.e. zigzag mode) instead of regular mode. It is common for large led matrix to have every other line in reverse order.
get_alternate() -> bool (only Leds_matrix) Read the value set with set_alternate(bool).
get_pixel_color(idx:int) -> color:int Returns the color (including brightness and gamma correction) of led number idx
gamma:bool Applies gamma correction if true (default)
pixels_buffer() -> bytes() Returns the internal buffer used by NeoPixelBus. The byte() object points to the original buffer, no new buffer is allocated; which means that raw data can be changed directly. Don't forget to call dirty() and show() afterwards
set_bytes(row:int, buffer:bytes, offset:int, len:int) -> nil (matrix only) Copy a bytes() buffer directly in the internal matrix buffer, for row row, skipping offset pixels and copying len bytes.
The class Leds_animator sets the necessary methods to facilitate animations. You just need create a sub-class or Leds_animator, provide a Leds or Leds_matrix instance and implement the animate method. You can also register animators (see below).
The instance is automatically registered as driver. Call start() to start the animation, and stop() to stop it.
Leds_animator(strip:instance) -> instance<Leds_animator> Constructors only needs an instance of Leds or Leds_matrix
start() -> nil Register the animator as Tasmota driver (with tasmota.add_driver) and start the animation
stop() -> nil Stop the animation and removes the driver from Tasmota drivers list
clear() -> nil Call stop() and clear all leds (set to black)
remove() -> nil Removes the instance from Tasmota's list of drivers, and stops the animation
set_bri(bri:int) -> nil Sets the brightness of the animation (0..100)
add_anim(anim:instance) -> nil Registers an animator to be called just before the call to animate (see below)
get_bri() -> int Returns the brightness of the animation (0..100)
animate() -> nil Place-holder for the actual animation. You need to override this method
importanimateclassRainbow_stripes:Leds_animatorvarcur_offset# current offset in the palettestaticpalette=[0xFF0000,#- red -#0xFFA500,#- orange -#0xFFFF00,#- yellow -#0x008800,#- green -#0x0000FF,#- blue -#0x4B0082,#- indigo -#0xEE82EE,#- violet -#]# duration in secondsdefinit(strip,duration)super(self).init(strip)self.cur_offset=0# add an animator to change `self.cur_offset` to each value of the paletteself.add_anim(animate.rotate(def(v)self.cur_offset=vend,0,size(self.palette),int(duration*1000)))enddefanimate()vari=0whilei<self.pixel_count# doing a loop rather than a `for` prevents from allocating a new objectvarcol=self.palette[(self.cur_offset+i)%size(self.palette)]self.strip.set_pixel_color(i,col,self.bri)# simulate the method call without GETMETi+=1endself.strip.show()endend
And here is another example that "breathes" the LED strip with a hardcoded colour:
classBreathe:Leds_animatorvarbrightnessvarcolour# duration in secondsdefinit(strip,duration)super(self).init(strip)self.brightness=0self.colour=0xFFFFFFself.add_anim(animate.back_forth(def(v)self.brightness=vend,0,100,int(duration*1000)))enddefanimate()vari=0whilei<self.pixel_count# doing a loop rather than a `for` prevents from allocating a new objectself.strip.set_pixel_color(i,self.colour,self.brightness)i+=1endself.strip.show()endend
This library uses NeoPixelBus library, and RMT hardware support in ESP32. The number of RMT channels, hence the number of simultaneous strips, depends on the CPU type. Tasmota native support for WS2812 uses RMT channel 0; it is not usable in such case.
Currently RMT channel 0 is used by default if no GPIO WS2812-1 is configured, RMT channel 1 otherwise.