339 lines
8.1 KiB
Python
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()
|
|
|
|
-#
|