Tasmota/lib/libesp32/Berry/default/embedded/leds.be
2021-12-01 22:44:58 +01:00

339 lines
8.1 KiB
Python

# class Leds
#
# for adressable leds like NoePixel
# Native commands
# 00 : ctor (leds:int, gpio:int) -> void
# 01 : begin void -> void
# 02 : show void -> void
# 03 : CanShow void -> bool
# 04 : IsDirty void -> bool
# 05 : Dirty void -> void
# 06 : Pixels void -> bytes() (mapped to the buffer)
# 07 : PixelSize void -> int
# 08 : PixelCount void -> int
# 09 : ClearTo (color:??) -> void
# 10 : SetPixelColor (idx:int, color:??) -> void
# 11 : GetPixelColor (idx:int) -> color:??
# 20 : RotateLeft (rot:int [, first:int, last:int]) -> void
# 21 : RotateRight (rot:int [, first:int, last:int]) -> void
# 22 : ShiftLeft (rot:int [, first:int, last:int]) -> void
# 23 : ShiftRight (rot:int [, first:int, last:int]) -> void
class Leds : Leds_ntv
var gamma # if true, apply gamma (true is default)
var leds # number of leds
# leds:int = number of leds of the strip
# gpio:int (optional) = GPIO for NeoPixel. If not specified, takes the WS2812 gpio
# type:int (optional) = Type of LED, defaults to WS2812 RGB
# rmt:int (optional) = RMT hardware channel to use, leave default unless you have a good reason
def init(leds, gpio, type, rmt) # rmt is optional
self.gamma = true # gamma is enabled by default, it should be disabled explicitly if needed
self.leds = int(leds)
if gpio == nil && gpio.pin(gpio.WS2812) >= 0
gpio = gpio.pin(gpio.WS2812)
end
# if no GPIO, abort
if gpio == nil
raise "valuer_error", "no GPIO specified for neopixelbus"
end
# initialize the structure
self.ctor(self.leds, gpio, type, rmt)
if self._p == nil raise "internal_error", "couldn't not initialize noepixelbus" end
# call begin
self.begin()
end
def clear()
self.clear_to(0x000000)
self.show()
end
def ctor(leds, gpio, rmt)
if rmt == nil
self.call_native(0, leds, gpio)
else
self.call_native(0, leds, gpio, rmt)
end
end
def begin()
self.call_native(1)
end
def show()
self.call_native(2)
end
def can_show()
return self.call_native(3)
end
def is_dirty()
return self.call_native(4)
end
def dirty()
self.call_native(5)
end
def pixels_buffer()
return self.call_native(6)
end
def pixel_size()
return self.call_native(7)
end
def pixel_count()
return self.call_native(8)
end
def clear_to(col, bri)
self.call_native(9, self.to_gamma(col, bri))
end
def set_pixel_color(idx, col, bri)
self.call_native(10, idx, self.to_gamma(col, bri))
end
def get_pixel_color(idx)
return self.call_native(11, idx)
end
# def rotate_left(rot, first, last)
# self.call_native(20, rot, first, last)
# end
# def rotate_right(rot, first, last)
# self.call_native(21, rot, first, last)
# end
# def shift_left(rot, first, last)
# self.call_native(22, rot, first, last)
# end
# def shift_right(rot, first, last)
# self.call_native(22, rot, first, last)
# end
# apply gamma and bri
def to_gamma(rgbw, bri)
bri = (bri != nil) ? bri : 100
var r = tasmota.scale_uint(bri, 0, 100, 0, (rgbw & 0xFF0000) >> 16)
var g = tasmota.scale_uint(bri, 0, 100, 0, (rgbw & 0x00FF00) >> 8)
var b = tasmota.scale_uint(bri, 0, 100, 0, (rgbw & 0x0000FF))
if self.gamma
return light.gamma8(r) << 16 |
light.gamma8(g) << 8 |
light.gamma8(b)
else
return r << 16 |
g << 8 |
b
end
end
# `segment`
# create a new `strip` object that maps a part of the current strip
def create_segment(offset, leds)
if int(offset) + int(leds) > self.leds || offset < 0 || leds < 0
raise "value_error", "out of range"
end
# inner class
class Leds_segment
var strip
var offset, leds
def init(strip, offset, leds)
self.strip = strip
self.offset = int(offset)
self.leds = int(leds)
end
def clear()
self.clear_to(0x000000)
self.show()
end
def begin()
# do nothing, already being handled by physical strip
end
def show(force)
# don't trigger on segment, you will need to trigger on full strip instead
if bool(force) || (self.offset == 0 && self.leds == self.strip.leds)
self.strip.show()
end
end
def can_show()
return self.strip.can_show()
end
def is_dirty()
return self.strip.is_dirty()
end
def dirty()
self.strip.dirty()
end
def pixels_buffer()
return nil
end
def pixel_size()
return self.strip.pixel_size()
end
def pixel_count()
return self.leds
end
def clear_to(col, bri)
var i = 0
while i < self.leds
self.strip.set_pixel_color(i + self.offset, col, bri)
i += 1
end
end
def set_pixel_color(idx, col, bri)
self.strip.set_pixel_color(idx + self.offset, col, bri)
end
def get_pixel_color(idx)
return self.strip.get_pixel_color(idx + self.offseta)
end
end
return Leds_segment(self, offset, leds)
end
def create_matrix(w, h, offset)
offset = int(offset)
w = int(w)
h = int(h)
if offset == nil offset = 0 end
if w * h + offset > self.leds || h < 0 || w < 0 || offset < 0
raise "value_error", "out of range"
end
# inner class
class Leds_matrix
var strip
var offset
var h, w
var alternate # are rows in alternate mode (even/odd are reversed)
def init(strip, w, h, offset)
self.strip = strip
self.offset = offset
self.h = h
self.w = w
self.alternate = false
end
def clear()
self.clear_to(0x000000)
self.show()
end
def begin()
# do nothing, already being handled by physical strip
end
def show(force)
# don't trigger on segment, you will need to trigger on full strip instead
if bool(force) || (self.offset == 0 && self.w * self.h == self.strip.leds)
self.strip.show()
end
end
def can_show()
return self.strip.can_show()
end
def is_dirty()
return self.strip.is_dirty()
end
def dirty()
self.strip.dirty()
end
def pixels_buffer()
return nil
end
def pixel_size()
return self.strip.pixel_size()
end
def pixel_count()
return self.w * self.h
end
def clear_to(col, bri)
var i = 0
while i < self.w * self.h
self.strip.set_pixel_color(i + self.offset, col, bri)
i += 1
end
end
def set_pixel_color(idx, col, bri)
self.strip.set_pixel_color(idx + self.offset, col, bri)
end
def get_pixel_color(idx)
return self.strip.get_pixel_color(idx + self.offseta)
end
# Leds_matrix specific
def set_alternate(alt)
self.alternate = alt
end
def get_alternate()
return self.alternate
end
def set_matrix_pixel_color(x, y, col, bri)
if self.alternate && x % 2
# reversed line
self.strip.set_pixel_color(x * self.w + self.h - y - 1 + self.offset, col, bri)
else
self.strip.set_pixel_color(x * self.w + y + self.offset, col, bri)
end
end
end
return Leds_matrix(self, w, h, offset)
end
static def matrix(w, h, gpio, rmt)
var strip = Leds(w * h, gpio, rmt)
var matrix = strip.create_matrix(w, h, 0)
return matrix
end
end
#-
var s = Leds(25, gpio.pin(gpio.WS2812, 1))
s.clear_to(0x300000)
s.show()
i = 0
def anim()
s.clear_to(0x300000)
s.set_pixel_color(i, 0x004000)
s.show()
i = (i + 1) % 25
tasmota.set_timer(200, anim)
end
anim()
-#
#-
var s = Leds_matrix(5, 5, gpio.pin(gpio.WS2812, 1))
s.set_alternate(true)
s.clear_to(0x300000)
s.show()
x = 0
y = 0
def anim()
s.clear_to(0x300000)
s.set_matrix_pixel_color(x, y, 0x004000)
s.show()
y = (y + 1) % 5
if y == 0
x = (x + 1) % 5
end
tasmota.set_timer(200, anim)
end
anim()
-#