mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-25 11:46:31 +00:00
Refactoring of Berry animate
module for WS2812 Leds (#20236)
This commit is contained in:
parent
7b12450876
commit
c1f8ee5dbb
@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
### Breaking Changed
|
### Breaking Changed
|
||||||
|
- Refactoring of Berry `animate` module for WS2812 Leds
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -146,7 +146,10 @@ BERRY_LOCAL const bntvmodule_t* const be_module_table[] = {
|
|||||||
#ifdef USE_UNISHOX_COMPRESSION
|
#ifdef USE_UNISHOX_COMPRESSION
|
||||||
&be_native_module(unishox),
|
&be_native_module(unishox),
|
||||||
#endif // USE_UNISHOX_COMPRESSION
|
#endif // USE_UNISHOX_COMPRESSION
|
||||||
|
|
||||||
|
#ifdef USE_WS2812
|
||||||
&be_native_module(animate),
|
&be_native_module(animate),
|
||||||
|
#endif // USE_WS2812
|
||||||
|
|
||||||
#ifdef USE_LVGL
|
#ifdef USE_LVGL
|
||||||
&be_native_module(lv),
|
&be_native_module(lv),
|
||||||
@ -206,10 +209,7 @@ be_extern_native_class(AXP192);
|
|||||||
be_extern_native_class(AXP202);
|
be_extern_native_class(AXP202);
|
||||||
be_extern_native_class(OneWire);
|
be_extern_native_class(OneWire);
|
||||||
be_extern_native_class(Leds_ntv);
|
be_extern_native_class(Leds_ntv);
|
||||||
be_extern_native_class(Leds_frame);
|
|
||||||
be_extern_native_class(Leds);
|
be_extern_native_class(Leds);
|
||||||
be_extern_native_class(Leds_animator);
|
|
||||||
be_extern_native_class(Leds_pulse);
|
|
||||||
be_extern_native_class(AudioGenerator);
|
be_extern_native_class(AudioGenerator);
|
||||||
be_extern_native_class(AudioFileSource);
|
be_extern_native_class(AudioFileSource);
|
||||||
be_extern_native_class(AudioOutputI2S);
|
be_extern_native_class(AudioOutputI2S);
|
||||||
@ -278,9 +278,6 @@ BERRY_LOCAL bclass_array be_class_table = {
|
|||||||
#ifdef USE_WS2812
|
#ifdef USE_WS2812
|
||||||
&be_native_class(Leds_ntv),
|
&be_native_class(Leds_ntv),
|
||||||
&be_native_class(Leds),
|
&be_native_class(Leds),
|
||||||
&be_native_class(Leds_frame),
|
|
||||||
&be_native_class(Leds_animator),
|
|
||||||
&be_native_class(Leds_pulse),
|
|
||||||
#endif // USE_WS2812
|
#endif // USE_WS2812
|
||||||
#ifdef USE_ENERGY_SENSOR
|
#ifdef USE_ENERGY_SENSOR
|
||||||
&be_native_class(energy_struct),
|
&be_native_class(energy_struct),
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
/********************************************************************
|
|
||||||
* Berry module `animate`
|
|
||||||
*
|
|
||||||
* To use: `import animate`
|
|
||||||
*
|
|
||||||
*******************************************************************/
|
|
||||||
#include "solidify/solidified_animate_module.h"
|
|
197
lib/libesp32/berry_tasmota/src/be_animate_module.c
Normal file
197
lib/libesp32/berry_tasmota/src/be_animate_module.c
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
be_animate_module.c - implements the animate module for Leds
|
||||||
|
|
||||||
|
Copyright (C) 2023 Stephan Hadinger & Theo Arends
|
||||||
|
|
||||||
|
This program 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*******************************************************************\
|
||||||
|
* `animate` global module
|
||||||
|
\*******************************************************************/
|
||||||
|
|
||||||
|
#include "be_constobj.h"
|
||||||
|
#include "be_mapping.h"
|
||||||
|
|
||||||
|
#include "solidify/solidified_animate_0_core.h"
|
||||||
|
#include "solidify/solidified_animate_1_animate_effects.h"
|
||||||
|
#include "solidify/solidified_animate_9_module.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************\
|
||||||
|
* standard palettes
|
||||||
|
\*******************************************************************/
|
||||||
|
static const uint8_t PALETTE_RAINBOW_WHITE[] = {
|
||||||
|
0x50, 0xFF, 0x00, 0x00, // red
|
||||||
|
0x30, 0xFF, 0x00, 0x00, // red
|
||||||
|
0x50, 0xFF, 0xA5, 0x00, // orange
|
||||||
|
0x30, 0xFF, 0xA5, 0x00, // orange
|
||||||
|
0x50, 0xFF, 0xFF, 0x00, // yellow
|
||||||
|
0x30, 0xFF, 0xFF, 0x00, // yellow
|
||||||
|
0x50, 0x00, 0xFF, 0x00, // green
|
||||||
|
0x30, 0x00, 0xFF, 0x00, // green
|
||||||
|
0x50, 0x00, 0x00, 0xFF, // blue
|
||||||
|
0x30, 0x00, 0x00, 0xFF, // blue
|
||||||
|
0x50, 0xFF, 0x00, 0xFF, // indigo
|
||||||
|
0x30, 0xFF, 0x00, 0xFF, // indigo
|
||||||
|
0x50, 0xFF, 0xFF, 0xFF, // white
|
||||||
|
0x30, 0xFF, 0xFF, 0xFF, // white
|
||||||
|
0x00, 0xFF, 0x00, 0x00, // red
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t PALETTE_STANDARD_TAG[] = {
|
||||||
|
0x40, 0xFF, 0x00, 0x00, // red
|
||||||
|
0x40, 0xFF, 0xA5, 0x00, // orange
|
||||||
|
0x40, 0xFF, 0xFF, 0x00, // yellow
|
||||||
|
0x40, 0x00, 0xFF, 0x00, // green
|
||||||
|
0x40, 0x00, 0x00, 0xFF, // blue
|
||||||
|
0x40, 0xFF, 0x00, 0xFF, // indigo
|
||||||
|
0x40, 0xFF, 0xFF, 0xFF, // violet
|
||||||
|
0x00, 0xFF, 0x00, 0x00, // red
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gradient palette "ib_jul01_gp", originally from
|
||||||
|
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/xmas/tn/ib_jul01.png.index.html
|
||||||
|
static const uint8_t PALETTE_ib_jul01_gp[] = {
|
||||||
|
0x00, 0xE6, 0x06, 0x11, // rgb(230, 6, 17) 0.000%,
|
||||||
|
0x5E, 0x25, 0x60, 0x5A, // rgb( 37, 96, 90) 37.010%,
|
||||||
|
0x85, 0x90, 0xBD, 0x6A, // rgb(144,189,106) 52.000%,
|
||||||
|
0xFF, 0xBB, 0x03, 0x0D, // rgb(187, 3, 13) 100.000%
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t PALETTE_STANDARD_VAL[] = {
|
||||||
|
0x00, 0xFF, 0x00, 0x00, // red
|
||||||
|
0x24, 0xFF, 0xA5, 0x00, // orange
|
||||||
|
0x49, 0xFF, 0xFF, 0x00, // yellow
|
||||||
|
0x6E, 0x00, 0xFF, 0x00, // green
|
||||||
|
0x92, 0x00, 0x00, 0xFF, // blue
|
||||||
|
0xB7, 0xFF, 0x00, 0xFF, // indigo
|
||||||
|
0xDB, 0xFF, 0xFF, 0xFF, // violet
|
||||||
|
0xFF, 0xFF, 0x00, 0x00, // red
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t PALETTE_SATURATED_TAG[] = {
|
||||||
|
0x40, 0xFF, 0x00, 0x00, // red
|
||||||
|
0x40, 0xFF, 0xA5, 0x00, // orange
|
||||||
|
0x40, 0xFF, 0xFF, 0x00, // yellow
|
||||||
|
0x40, 0x00, 0xFF, 0x00, // green
|
||||||
|
0x40, 0x00, 0x00, 0xFF, // blue
|
||||||
|
0x40, 0xFF, 0x00, 0xFF, // indigo
|
||||||
|
0x40, 0xFF, 0xFF, 0xFF, // violet
|
||||||
|
0x00, 0xFF, 0x00, 0x00, // red
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const bclass be_class_Leds_frame;
|
||||||
|
|
||||||
|
#include "be_fixed_animate.h"
|
||||||
|
|
||||||
|
/* @const_object_info_begin
|
||||||
|
|
||||||
|
module animate (scope: global, strings: weak) {
|
||||||
|
SAWTOOTH, int(1)
|
||||||
|
TRIANGLE, int(2)
|
||||||
|
SQUARE, int(3)
|
||||||
|
COSINE, int(4)
|
||||||
|
SINE, int(5)
|
||||||
|
LASTFORM, int(5)
|
||||||
|
|
||||||
|
PALETTE_STANDARD_TAG, comptr(PALETTE_STANDARD_TAG)
|
||||||
|
PALETTE_RAINBOW_WHITE, comptr(PALETTE_RAINBOW_WHITE)
|
||||||
|
PALETTE_STANDARD_VAL, comptr(PALETTE_STANDARD_VAL)
|
||||||
|
PALETTE_SATURATED_TAG, comptr(PALETTE_SATURATED_TAG)
|
||||||
|
|
||||||
|
(), class(be_class_Animate_core)
|
||||||
|
core, class(be_class_Animate_core) // alias
|
||||||
|
animator, class(be_class_Animate_animator)
|
||||||
|
frame, class(be_class_Leds_frame)
|
||||||
|
pulse, class(be_class_Animate_pulse)
|
||||||
|
palette, class(be_class_Animate_palette)
|
||||||
|
oscillator, class(be_class_Animate_oscillator)
|
||||||
|
}
|
||||||
|
|
||||||
|
@const_object_info_end */
|
||||||
|
|
||||||
|
/* Unit test for palettes
|
||||||
|
|
||||||
|
import animate
|
||||||
|
var p, gradient
|
||||||
|
p = animate.palette.ptr_to_palette(animate.PALETTE_STANDARD_TAG)
|
||||||
|
assert(p == bytes('40FF000040FFA50040FFFF004000FF00400000FF40FF00FF40FFFFFF00FF0000'))
|
||||||
|
gradient = animate.palette.to_css_gradient(p)
|
||||||
|
assert(gradient == 'background:linear-gradient(to right,#FF0000 0.0%,#FFA500 14.3%,#FFFF00 28.6%,#00FF00 42.9%,#0000FF 57.1%,#FF00FF 71.4%,#FFFFFF 85.7%,#FF0000 100.0%);')
|
||||||
|
|
||||||
|
p = animate.palette.ptr_to_palette(animate.PALETTE_STANDARD_VAL)
|
||||||
|
assert(p == bytes('00FF000024FFA50049FFFF006E00FF00920000FFB7FF00FFDBFFFFFFFFFF0000'))
|
||||||
|
gradient = animate.palette.to_css_gradient(animate.PALETTE_STANDARD_VAL)
|
||||||
|
assert(gradient == 'background:linear-gradient(to right,#FF0000 0.0%,#FFA500 14.1%,#FFFF00 28.6%,#00FF00 43.1%,#0000FF 57.3%,#FF00FF 71.8%,#FFFFFF 85.9%,#FF0000 100.0%);')
|
||||||
|
|
||||||
|
|
||||||
|
# unit tests
|
||||||
|
import animate
|
||||||
|
var o = animate.oscillator(-1000, 1000, 3000)
|
||||||
|
o.start(1000)
|
||||||
|
assert(o.value == -1000)
|
||||||
|
assert(o.animate(1500) == -667)
|
||||||
|
assert(o.animate(2500) == 0)
|
||||||
|
assert(o.animate(3999) == 1000)
|
||||||
|
assert(o.animate(4000) == -1000)
|
||||||
|
assert(o.animate(4100) == -933)
|
||||||
|
|
||||||
|
o = animate.oscillator(-1000, 1000, 6000, animate.TRIANGLE)
|
||||||
|
o.start(1000)
|
||||||
|
assert(o.value == -1000)
|
||||||
|
assert(o.animate(1500) == -667)
|
||||||
|
assert(o.animate(2500) == 0)
|
||||||
|
assert(o.animate(3999) == 1000)
|
||||||
|
assert(o.animate(4000) == 1000)
|
||||||
|
assert(o.animate(4100) == 933)
|
||||||
|
assert(o.animate(6000) == -334)
|
||||||
|
assert(o.animate(7000) == -1000)
|
||||||
|
assert(o.animate(7100) == -933)
|
||||||
|
|
||||||
|
o = animate.oscillator(-1000, 1000, 6000, animate.SQUARE)
|
||||||
|
o.start(1000)
|
||||||
|
assert(o.value == -1000)
|
||||||
|
assert(o.animate(1500) == -1000)
|
||||||
|
assert(o.animate(2500) == -1000)
|
||||||
|
assert(o.animate(3999) == -1000)
|
||||||
|
assert(o.animate(4000) == 1000)
|
||||||
|
assert(o.animate(4100) == 1000)
|
||||||
|
assert(o.animate(6000) == 1000)
|
||||||
|
assert(o.animate(7000) == -1000)
|
||||||
|
assert(o.animate(7100) == -1000)
|
||||||
|
|
||||||
|
o = animate.oscillator(-1000, 1000, 6000, animate.SINE)
|
||||||
|
o.start(1000)
|
||||||
|
assert(o.animate(1000) == 0)
|
||||||
|
assert(o.animate(1500) == 500)
|
||||||
|
assert(o.animate(2000) == 867)
|
||||||
|
assert(o.animate(2500) == 1000)
|
||||||
|
assert(o.animate(4000) == 0)
|
||||||
|
assert(o.animate(5500) == -1000)
|
||||||
|
assert(o.animate(7000) == 0)
|
||||||
|
|
||||||
|
o = animate.oscillator(-1000, 1000, 6000, animate.COSINE)
|
||||||
|
o.start(1000)
|
||||||
|
assert(o.animate(1000) == -1000)
|
||||||
|
assert(o.animate(1500) == -867)
|
||||||
|
assert(o.animate(2000) == -500)
|
||||||
|
assert(o.animate(2500) == 0)
|
||||||
|
assert(o.animate(4000) == 1000)
|
||||||
|
assert(o.animate(5500) == 0)
|
||||||
|
assert(o.animate(7000) == -1000)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
@ -1,9 +0,0 @@
|
|||||||
/********************************************************************
|
|
||||||
* Berry class `Leds_animator`
|
|
||||||
*
|
|
||||||
*******************************************************************/
|
|
||||||
#ifdef USE_WS2812
|
|
||||||
|
|
||||||
#include "solidify/solidified_leds_0_animator.h"
|
|
||||||
|
|
||||||
#endif // USE_WS2812
|
|
@ -1,9 +0,0 @@
|
|||||||
/********************************************************************
|
|
||||||
* Berry class `Leds_pulse`
|
|
||||||
*
|
|
||||||
*******************************************************************/
|
|
||||||
#ifdef USE_WS2812
|
|
||||||
|
|
||||||
#include "solidify/solidified_leds_1_animate_effects.h"
|
|
||||||
|
|
||||||
#endif // USE_WS2812
|
|
@ -35,6 +35,7 @@ extern int l_delay(bvm *vm);
|
|||||||
extern int l_delay_microseconds(bvm *vm);
|
extern int l_delay_microseconds(bvm *vm);
|
||||||
extern int l_scaleuint(bvm *vm);
|
extern int l_scaleuint(bvm *vm);
|
||||||
extern int l_scaleint(bvm *vm);
|
extern int l_scaleint(bvm *vm);
|
||||||
|
extern int l_sineint(bvm *vm);
|
||||||
extern int l_logInfo(bvm *vm);
|
extern int l_logInfo(bvm *vm);
|
||||||
extern int l_loglevel(bvm *vm);
|
extern int l_loglevel(bvm *vm);
|
||||||
extern int l_save(bvm *vm);
|
extern int l_save(bvm *vm);
|
||||||
@ -120,6 +121,7 @@ class be_class_tasmota (scope: global, name: Tasmota) {
|
|||||||
delay_microseconds, func(l_delay_microseconds)
|
delay_microseconds, func(l_delay_microseconds)
|
||||||
scale_uint, static_func(l_scaleuint)
|
scale_uint, static_func(l_scaleuint)
|
||||||
scale_int, static_func(l_scaleint)
|
scale_int, static_func(l_scaleint)
|
||||||
|
sine_int, static_func(l_sineint)
|
||||||
log, func(l_logInfo)
|
log, func(l_logInfo)
|
||||||
loglevel, func(l_loglevel)
|
loglevel, func(l_loglevel)
|
||||||
save, func(l_save)
|
save, func(l_save)
|
||||||
|
@ -1,13 +1,8 @@
|
|||||||
# class Leds_animator
|
# class Animate_core
|
||||||
|
|
||||||
#@ solidify:Leds_animator,weak
|
|
||||||
|
|
||||||
# for solidification
|
|
||||||
class Leds_frame end
|
|
||||||
|
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
#
|
#
|
||||||
# class Leds_animator
|
# class Animate_core
|
||||||
#
|
#
|
||||||
# Simple framework to orchestrate all the animations for a led strip or led matrix
|
# Simple framework to orchestrate all the animations for a led strip or led matrix
|
||||||
#
|
#
|
||||||
@ -15,7 +10,8 @@ class Leds_frame end
|
|||||||
# This version uses `fast_loop` for up to 5ms animation time (200 Hz)
|
# This version uses `fast_loop` for up to 5ms animation time (200 Hz)
|
||||||
#
|
#
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
class Leds_animator
|
#@ solidify:Animate_core,weak
|
||||||
|
class Animate_core
|
||||||
var strip # neopixelbus object
|
var strip # neopixelbus object
|
||||||
var pixel_count # number of pixels in the strip
|
var pixel_count # number of pixels in the strip
|
||||||
var bri # brightness of the animation, 0..100, default 50
|
var bri # brightness of the animation, 0..100, default 50
|
||||||
@ -35,6 +31,7 @@ class Leds_animator
|
|||||||
var back_color # background color RRGGBB
|
var back_color # background color RRGGBB
|
||||||
|
|
||||||
def init(strip, bri)
|
def init(strip, bri)
|
||||||
|
import animate
|
||||||
self.strip = strip
|
self.strip = strip
|
||||||
if (bri == nil) bri = 50 end
|
if (bri == nil) bri = 50 end
|
||||||
self.bri = bri # percentage of brightness 0..100
|
self.bri = bri # percentage of brightness 0..100
|
||||||
@ -44,8 +41,8 @@ class Leds_animator
|
|||||||
self.painters = []
|
self.painters = []
|
||||||
#
|
#
|
||||||
self.clear() # clear all leds first
|
self.clear() # clear all leds first
|
||||||
self.frame = Leds_frame(self.pixel_count)
|
self.frame = animate.frame(self.pixel_count)
|
||||||
self.layer = Leds_frame(self.pixel_count)
|
self.layer = animate.frame(self.pixel_count)
|
||||||
#
|
#
|
||||||
self.fast_loop_cb = def() self.fast_loop() end
|
self.fast_loop_cb = def() self.fast_loop() end
|
||||||
self.back_color = 0x000000
|
self.back_color = 0x000000
|
@ -1,14 +1,12 @@
|
|||||||
# class Leds_pulse
|
# class Animate_pulse
|
||||||
|
|
||||||
#@ solidify:Leds_pulse,weak
|
|
||||||
|
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
#
|
#
|
||||||
# class Leds_pulse
|
# class Animate_pulse
|
||||||
#
|
#
|
||||||
# Display a color pulse
|
# Display a color pulse
|
||||||
#
|
#
|
||||||
# index (1)
|
# pos (1)
|
||||||
# |
|
# |
|
||||||
# v
|
# v
|
||||||
# _______
|
# _______
|
||||||
@ -17,16 +15,17 @@
|
|||||||
# | | | |
|
# | | | |
|
||||||
# |2| 3 |2|
|
# |2| 3 |2|
|
||||||
#
|
#
|
||||||
# 1: `index`, start of the pulse (in pixel)
|
# 1: `pos`, start of the pulse (in pixel)
|
||||||
# 2: `slew_size`, number of pixels to fade from back to fore color, can be `0`
|
# 2: `slew_size`, number of pixels to fade from back to fore color, can be `0`
|
||||||
# 3: `pulse_size`, number of pixels of the pulse
|
# 3: `pulse_size`, number of pixels of the pulse
|
||||||
#
|
#
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
|
|
||||||
class Leds_pulse
|
#@ solidify:Animate_pulse,weak
|
||||||
|
class Animate_pulse
|
||||||
var color
|
var color
|
||||||
var back_color
|
var back_color
|
||||||
var index
|
var pos
|
||||||
var slew_size
|
var slew_size
|
||||||
var pulse_size
|
var pulse_size
|
||||||
|
|
||||||
@ -54,8 +53,8 @@ class Leds_pulse
|
|||||||
self.back_color = c
|
self.back_color = c
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_index(index)
|
def set_pos(pos)
|
||||||
self.index = index
|
self.pos = pos
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_slew_size(slew_size)
|
def set_slew_size(slew_size)
|
||||||
@ -72,18 +71,18 @@ class Leds_pulse
|
|||||||
if (back_color != 0xFF000000)
|
if (back_color != 0xFF000000)
|
||||||
frame.fill_pixels(back_color) # fill with transparent color
|
frame.fill_pixels(back_color) # fill with transparent color
|
||||||
end
|
end
|
||||||
var index = self.index
|
var pos = self.pos
|
||||||
var slew_size = self.slew_size
|
var slew_size = self.slew_size
|
||||||
var pulse_size = self.pulse_size
|
var pulse_size = self.pulse_size
|
||||||
var color = self.color
|
var color = self.color
|
||||||
var pixel_size = frame.pixel_size
|
var pixel_size = frame.pixel_size
|
||||||
|
|
||||||
# var min_index = index - slew_size
|
# var min_index = pos - slew_size
|
||||||
# var max_index = index + pulse_size + slew_size - 1
|
# var max_index = pos + pulse_size + slew_size - 1
|
||||||
|
|
||||||
var pulse_min, pulse_max
|
var pulse_min, pulse_max
|
||||||
pulse_min = index
|
pulse_min = pos
|
||||||
pulse_max = index + pulse_size
|
pulse_max = pos + pulse_size
|
||||||
if (pulse_min < 0) pulse_min = 0 end
|
if (pulse_min < 0) pulse_min = 0 end
|
||||||
if (pulse_max >= pixel_size) pulse_max = pixel_size end
|
if (pulse_max >= pixel_size) pulse_max = pixel_size end
|
||||||
|
|
||||||
@ -94,28 +93,28 @@ class Leds_pulse
|
|||||||
end
|
end
|
||||||
|
|
||||||
if (slew_size > 0)
|
if (slew_size > 0)
|
||||||
# check first slew, from `min_index` to `index - 1`
|
# check first slew, from `min_index` to `pos - 1`
|
||||||
# Slew 1
|
# Slew 1
|
||||||
pulse_min = index - slew_size
|
pulse_min = pos - slew_size
|
||||||
pulse_max = index
|
pulse_max = pos
|
||||||
if (pulse_min < 0) pulse_min = 0 end
|
if (pulse_min < 0) pulse_min = 0 end
|
||||||
if (pulse_max >= pixel_size) pulse_max = pixel_size end
|
if (pulse_max >= pixel_size) pulse_max = pixel_size end
|
||||||
i = pulse_min
|
i = pulse_min
|
||||||
while (i < pulse_max)
|
while (i < pulse_max)
|
||||||
# blend from 255 (back) to 0 (fore)
|
# blend from 255 (back) to 0 (fore)
|
||||||
frame[i] = frame.blend(back_color, color, tasmota.scale_int(i, index - slew_size - 1, index, 255, 0))
|
frame[i] = frame.blend(back_color, color, tasmota.scale_int(i, pos - slew_size - 1, pos, 255, 0))
|
||||||
# blend
|
# blend
|
||||||
i += 1
|
i += 1
|
||||||
end
|
end
|
||||||
# Slew 2
|
# Slew 2
|
||||||
pulse_min = index + pulse_size
|
pulse_min = pos + pulse_size
|
||||||
pulse_max = index + pulse_size + slew_size
|
pulse_max = pos + pulse_size + slew_size
|
||||||
if (pulse_min < 0) pulse_min = 0 end
|
if (pulse_min < 0) pulse_min = 0 end
|
||||||
if (pulse_max >= pixel_size) pulse_max = pixel_size end
|
if (pulse_max >= pixel_size) pulse_max = pixel_size end
|
||||||
i = pulse_min
|
i = pulse_min
|
||||||
while (i < pulse_max)
|
while (i < pulse_max)
|
||||||
# blend
|
# blend
|
||||||
frame[i] = frame.blend(back_color, color, tasmota.scale_int(i, index + pulse_size - 1, index + pulse_size + slew_size, 0, 255))
|
frame[i] = frame.blend(back_color, color, tasmota.scale_int(i, pos + pulse_size - 1, pos + pulse_size + slew_size, 0, 255))
|
||||||
i += 1
|
i += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -130,10 +129,11 @@ end
|
|||||||
#
|
#
|
||||||
if false
|
if false
|
||||||
|
|
||||||
var frame = Leds_frame(10)
|
import animate
|
||||||
|
var frame = animate.frame(10)
|
||||||
assert(frame.tohex() == '00000000000000000000000000000000000000000000000000000000000000000000000000000000')
|
assert(frame.tohex() == '00000000000000000000000000000000000000000000000000000000000000000000000000000000')
|
||||||
|
|
||||||
var pulse = Leds_pulse(0x00FF00, 3, 2)
|
var pulse = Animate_pulse(0x00FF00, 3, 2)
|
||||||
pulse.set_index(5)
|
pulse.set_index(5)
|
||||||
pulse.paint(frame)
|
pulse.paint(frame)
|
||||||
assert(frame.tohex() == '0000000000000000000000000055000000AA000000FF000000FF000000FF000000AA000000550000')
|
assert(frame.tohex() == '0000000000000000000000000055000000AA000000FF000000FF000000FF000000AA000000550000')
|
508
lib/libesp32/berry_tasmota/src/embedded/animate_9_module.be
Normal file
508
lib/libesp32/berry_tasmota/src/embedded/animate_9_module.be
Normal file
@ -0,0 +1,508 @@
|
|||||||
|
#
|
||||||
|
# class Animate
|
||||||
|
#
|
||||||
|
# Animation framework
|
||||||
|
#
|
||||||
|
|
||||||
|
animate = module("animate")
|
||||||
|
|
||||||
|
# for solidification
|
||||||
|
class Leds_frame end
|
||||||
|
|
||||||
|
animate.("()") = Animate_core # make it available as `animate()`
|
||||||
|
animate.frame = Leds_frame
|
||||||
|
animate.pulse = Animate_pulse
|
||||||
|
|
||||||
|
#################################################################################
|
||||||
|
# class Animate_palette
|
||||||
|
#
|
||||||
|
# Animated color palette
|
||||||
|
#################################################################################
|
||||||
|
|
||||||
|
#################################################################################
|
||||||
|
# Palette format compatible
|
||||||
|
#
|
||||||
|
# Takes a binary array with a set of 4 bytes elements: VRGB
|
||||||
|
# V: Value in a range 0..255. The first value must be 0,
|
||||||
|
# the last needs to be 255.
|
||||||
|
# Numbers must be in strictly increasin numbers.
|
||||||
|
# The algorithm maps a 0..255 rotating value to its color
|
||||||
|
# in the palette.
|
||||||
|
# R: Red component
|
||||||
|
# G: Green component
|
||||||
|
# B: Blue component
|
||||||
|
# Note: RGB is in big Endian to make it more readable, although
|
||||||
|
# it's little-endian when in memory. Be aware!
|
||||||
|
# RGB values are stored at max brightness and without gamma correction
|
||||||
|
#################################################################################
|
||||||
|
|
||||||
|
# # Gradient palette "ib_jul01_gp", originally from
|
||||||
|
# # http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/xmas/tn/ib_jul01.png.index.html
|
||||||
|
# var PALETTE_ib_jul01_gp = bytes(
|
||||||
|
# "00" "E60611"
|
||||||
|
# "5E" "25605A"
|
||||||
|
# "85" "90BD6A"
|
||||||
|
# "FF" "BB030D"
|
||||||
|
# )
|
||||||
|
# # animate.PALETTE_ib_jul01_gp = PALETTE_ib_jul01_gp
|
||||||
|
# # rgb(230, 6, 17) 0.000%,
|
||||||
|
# # rgb( 37, 96, 90) 37.010%,
|
||||||
|
# # rgb(144,189,106) 52.000%,
|
||||||
|
# # rgb(187, 3, 13) 100.000%
|
||||||
|
|
||||||
|
# var PALETTE_STANDARD_VAL = bytes(
|
||||||
|
# "00" "FF0000" # red
|
||||||
|
# "24" "FFA500" # orange
|
||||||
|
# "49" "FFFF00" # yellow
|
||||||
|
# "6E" "008800" # green
|
||||||
|
# "92" "0000FF" # blue
|
||||||
|
# "B7" "4B0082" # indigo
|
||||||
|
# "DB" "EE82EE" # violet
|
||||||
|
# "FF" "FF0000" # red
|
||||||
|
# )
|
||||||
|
# # animate.PALETTE_STANDARD = PALETTE_STANDARD
|
||||||
|
|
||||||
|
# var PALETTE_SATURATED_TAG = bytes(
|
||||||
|
# "40" "FF0000" # red
|
||||||
|
# "40" "FFA500" # orange
|
||||||
|
# "40" "FFFF00" # yellow
|
||||||
|
# "40" "00FF00" # green
|
||||||
|
# "40" "0000FF" # blue
|
||||||
|
# "40" "FF00FF" # indigo
|
||||||
|
# "40" "EE44A5" # violet
|
||||||
|
# "00" "FF0000" # red
|
||||||
|
# )
|
||||||
|
|
||||||
|
# var PALETTE_STANDARD_TAG = bytes(
|
||||||
|
# "40" "FF0000" # red
|
||||||
|
# "40" "FFA500" # orange
|
||||||
|
# "40" "FFFF00" # yellow
|
||||||
|
# "40" "008800" # green
|
||||||
|
# "40" "0000FF" # blue
|
||||||
|
# "40" "4B0082" # indigo
|
||||||
|
# "40" "EE82EE" # violet
|
||||||
|
# "00" "FF0000" # red
|
||||||
|
# )
|
||||||
|
# # animate.PALETTE_STANDARD = PALETTE_STANDARD
|
||||||
|
|
||||||
|
|
||||||
|
#@ solidify:Animate_animator,weak
|
||||||
|
class Animate_animator
|
||||||
|
# timing information
|
||||||
|
var running # true if running
|
||||||
|
var duration_ms # duration_ms of the entire cycle in ms, cannot be `0`
|
||||||
|
var origin # origin in ms of the current cycle, as per tasmota.millis() reference
|
||||||
|
# callback information
|
||||||
|
var obj # object to call
|
||||||
|
var mth # object method to call
|
||||||
|
|
||||||
|
def init(duration_ms)
|
||||||
|
self.duration_ms = duration_ms
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_duration_ms(duration_ms)
|
||||||
|
self.duration_ms = duration_ms
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_cb(obj, mth)
|
||||||
|
self.obj = obj
|
||||||
|
self.mth = mth
|
||||||
|
end
|
||||||
|
|
||||||
|
def start(millis)
|
||||||
|
if (self.duration_ms == nil) return end
|
||||||
|
if millis == nil millis = tasmota.millis() end
|
||||||
|
self.origin = millis
|
||||||
|
self.running = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def stop()
|
||||||
|
self.origin = nil
|
||||||
|
self.running = false
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_running()
|
||||||
|
return bool(self.running)
|
||||||
|
end
|
||||||
|
|
||||||
|
# called at the end of each cycle
|
||||||
|
def beat()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
#@ solidify:Animate_palette,weak
|
||||||
|
class Animate_palette : Animate_animator
|
||||||
|
## inherited
|
||||||
|
## timing information
|
||||||
|
# var running
|
||||||
|
# var duration_ms # duration_ms of the entire cycle in ms, cannot be `0`
|
||||||
|
# var origin # origin in ms of the current cycle, as per tasmota.millis() reference
|
||||||
|
## callback information
|
||||||
|
# var obj # object to call
|
||||||
|
# var mth # object method to call
|
||||||
|
|
||||||
|
# parsing of palette
|
||||||
|
var palette # raw bytes object
|
||||||
|
var slots_arr # constructed array of timestamp slots
|
||||||
|
var slots # number of slots
|
||||||
|
# range information (when used as range color)
|
||||||
|
var range_min # minimum value expected as input
|
||||||
|
var range_max # maximum value expected as input, needs (range_min < range_max, can be negative)
|
||||||
|
# brightness
|
||||||
|
var bri # brightness to be applied to palette 0..100
|
||||||
|
# color object to do RGB color calculation
|
||||||
|
var color # instance of light_state, used for color calculation (reuse of object)
|
||||||
|
|
||||||
|
def init(palette, duration_ms)
|
||||||
|
super(self).init(duration_ms)
|
||||||
|
self.running = false
|
||||||
|
if (type(palette) == 'ptr') palette = self.ptr_to_palette(palette) end # convert comptr to palette buffer
|
||||||
|
self.palette = palette
|
||||||
|
self.bri = 100
|
||||||
|
self.slots = size(palette) / 4
|
||||||
|
if duration_ms != nil
|
||||||
|
self.set_duration(duration_ms)
|
||||||
|
end
|
||||||
|
self.color = light_state(light_state.RGB)
|
||||||
|
end
|
||||||
|
|
||||||
|
# setter to be used as cb
|
||||||
|
def set_bri(bri)
|
||||||
|
self.bri = int(bri)
|
||||||
|
end
|
||||||
|
|
||||||
|
# convert a comptr to a bytes() for palette
|
||||||
|
# parse the raw bytes to find the actual length
|
||||||
|
#
|
||||||
|
# input: comptr
|
||||||
|
# return: bytes() object of palette
|
||||||
|
static def ptr_to_palette(p)
|
||||||
|
if type(p) == 'ptr'
|
||||||
|
var b_raw = bytes(p, 2000) # arbitrary large size
|
||||||
|
var idx = 1
|
||||||
|
if b_raw[0] != 0
|
||||||
|
# palette in tick counts
|
||||||
|
while true
|
||||||
|
if b_raw[idx * 4] == 0
|
||||||
|
break
|
||||||
|
end
|
||||||
|
idx += 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# palette is in value range from 0..255
|
||||||
|
while true
|
||||||
|
if b_raw[idx * 4] == 0xFF
|
||||||
|
break
|
||||||
|
end
|
||||||
|
idx += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
var sz = (idx + 1) * 4
|
||||||
|
return bytes(p, sz)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_palette(min, max)
|
||||||
|
var arr = []
|
||||||
|
var slots = self.slots
|
||||||
|
arr.resize(slots)
|
||||||
|
|
||||||
|
# check if we have slots or values
|
||||||
|
# if first value index is non-zero, it's ticks count
|
||||||
|
if self.palette.get(0, 1) != 0
|
||||||
|
# palette in tick counts
|
||||||
|
# compute the total number of ticks
|
||||||
|
var total_ticks = 0
|
||||||
|
var idx = 0
|
||||||
|
while idx < slots - 1
|
||||||
|
total_ticks += self.palette.get(idx * 4, 1)
|
||||||
|
idx += 1
|
||||||
|
end
|
||||||
|
var cur_ticks = 0
|
||||||
|
idx = 0
|
||||||
|
while idx < slots
|
||||||
|
arr[idx] = tasmota.scale_int(cur_ticks, 0, total_ticks, min, max)
|
||||||
|
cur_ticks += self.palette.get(idx * 4, 1)
|
||||||
|
idx += 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# palette is in value range from 0..255
|
||||||
|
var idx = 0
|
||||||
|
while idx < slots
|
||||||
|
var val = self.palette.get(idx * 4, 1)
|
||||||
|
arr[idx] = tasmota.scale_int(val, 0, 255, min, max)
|
||||||
|
idx += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# print(f"ANM: {arr=}")
|
||||||
|
return arr
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_duration(duration_ms)
|
||||||
|
if (duration_ms == nil) return end
|
||||||
|
if duration_ms <= 0 raise "value_error", "duration_ms must be positive" end
|
||||||
|
self.duration_ms = duration_ms
|
||||||
|
|
||||||
|
self.slots_arr = self.parse_palette(0, duration_ms - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_range(min, max)
|
||||||
|
if (min >= max) raise "value_error", "min must be lower than mex" end
|
||||||
|
self.range_min = min
|
||||||
|
self.range_max = max
|
||||||
|
|
||||||
|
self.slots_arr = self.parse_palette(min, max)
|
||||||
|
end
|
||||||
|
|
||||||
|
# compute the css linear-gradient description
|
||||||
|
#
|
||||||
|
# Example: background: linear-gradient(to right, #000000, #e66465 11.0%, #9198e5);
|
||||||
|
static def to_css_gradient(palette)
|
||||||
|
var p = _class(palette)
|
||||||
|
var arr = p.parse_palette(0, 1000)
|
||||||
|
var ret = "background:linear-gradient(to right"
|
||||||
|
var idx = 0
|
||||||
|
while idx < size(arr)
|
||||||
|
var prm = arr[idx] # per mile
|
||||||
|
|
||||||
|
var bgrt = p.palette.get(idx * 4, 4)
|
||||||
|
var r = (bgrt >> 8) & 0xFF
|
||||||
|
var g = (bgrt >> 16) & 0xFF
|
||||||
|
var b = (bgrt >> 24) & 0xFF
|
||||||
|
ret += f",#{r:02X}{g:02X}{b:02X} {prm/10.0:.1f}%"
|
||||||
|
idx += 1
|
||||||
|
end
|
||||||
|
ret += ");"
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_value(value)
|
||||||
|
if (self.range_min == nil || self.range_max == nil) return nil end
|
||||||
|
var scale_int = tasmota.scale_int
|
||||||
|
|
||||||
|
# find slot
|
||||||
|
var slots = self.slots
|
||||||
|
var idx = slots - 2
|
||||||
|
while idx > 0
|
||||||
|
if value >= self.slots_arr[idx] break end
|
||||||
|
idx -= 1
|
||||||
|
end
|
||||||
|
var bgrt0 = self.palette.get(idx * 4, 4)
|
||||||
|
var bgrt1 = self.palette.get((idx + 1) * 4, 4)
|
||||||
|
var t0 = self.slots_arr[idx]
|
||||||
|
var t1 = self.slots_arr[idx + 1]
|
||||||
|
var r = scale_int(value, t0, t1, (bgrt0 >> 8) & 0xFF, (bgrt1 >> 8) & 0xFF)
|
||||||
|
var g = scale_int(value, t0, t1, (bgrt0 >> 16) & 0xFF, (bgrt1 >> 16) & 0xFF)
|
||||||
|
var b = scale_int(value, t0, t1, (bgrt0 >> 24) & 0xFF, (bgrt1 >> 24) & 0xFF)
|
||||||
|
var rgb = (r << 16) | (g << 8) | b
|
||||||
|
#
|
||||||
|
var obj = self.obj
|
||||||
|
var mth = self.mth
|
||||||
|
if (obj && mth)
|
||||||
|
mth(obj, rgb)
|
||||||
|
end
|
||||||
|
# if self.cb != nil
|
||||||
|
# self.cb(rgb)
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# print(f"ANM: {rgb=:%06X}")
|
||||||
|
return rgb
|
||||||
|
end
|
||||||
|
|
||||||
|
def animate(millis)
|
||||||
|
if (self.duration_ms == nil) return end
|
||||||
|
if millis == nil millis = tasmota.millis() end
|
||||||
|
var past = millis - self.origin
|
||||||
|
if past < 0
|
||||||
|
past = 0
|
||||||
|
millis = self.origin
|
||||||
|
end
|
||||||
|
var duration_ms = self.duration_ms
|
||||||
|
var scale_uint = tasmota.scale_uint
|
||||||
|
if past >= duration_ms
|
||||||
|
self.origin += (past / duration_ms) * duration_ms
|
||||||
|
past = past % duration_ms
|
||||||
|
end
|
||||||
|
# find slot
|
||||||
|
var slots = self.slots
|
||||||
|
var idx = slots - 2
|
||||||
|
while idx > 0
|
||||||
|
if past >= self.slots_arr[idx] break end
|
||||||
|
idx -= 1
|
||||||
|
end
|
||||||
|
var bgrt0 = self.palette.get(idx * 4, 4)
|
||||||
|
var bgrt1 = self.palette.get((idx + 1) * 4, 4)
|
||||||
|
var t0 = self.slots_arr[idx]
|
||||||
|
var t1 = self.slots_arr[idx + 1]
|
||||||
|
var r = scale_uint(past, t0, t1, (bgrt0 >> 8) & 0xFF, (bgrt1 >> 8) & 0xFF)
|
||||||
|
var g = scale_uint(past, t0, t1, (bgrt0 >> 16) & 0xFF, (bgrt1 >> 16) & 0xFF)
|
||||||
|
var b = scale_uint(past, t0, t1, (bgrt0 >> 24) & 0xFF, (bgrt1 >> 24) & 0xFF)
|
||||||
|
|
||||||
|
var color = self.color
|
||||||
|
color.set_rgb((bgrt0 >> 8) & 0xFF, (bgrt0 >> 16) & 0xFF, (bgrt0 >> 24) & 0xFF)
|
||||||
|
var bri0 = color.bri
|
||||||
|
color.set_rgb((bgrt1 >> 8) & 0xFF, (bgrt1 >> 16) & 0xFF, (bgrt1 >> 24) & 0xFF)
|
||||||
|
var bri1 = color.bri
|
||||||
|
var bri2 = scale_uint(past, t0, t1, bri0, bri1)
|
||||||
|
color.set_rgb(r, g, b)
|
||||||
|
color.set_bri(bri2)
|
||||||
|
|
||||||
|
r = color.r
|
||||||
|
g = color.g
|
||||||
|
b = color.b
|
||||||
|
|
||||||
|
# apply self.bri if not `100`
|
||||||
|
var bri = self.bri
|
||||||
|
if bri != 100
|
||||||
|
r = tasmota.scale_uint(r, 0, 100, 0, bri)
|
||||||
|
g = tasmota.scale_uint(g, 0, 100, 0, bri)
|
||||||
|
b = tasmota.scale_uint(b, 0, 100, 0, bri)
|
||||||
|
end
|
||||||
|
|
||||||
|
# var rgb = (r << 16) | (g << 8) | b
|
||||||
|
var rgb = (r << 16) | (g << 8) | b
|
||||||
|
|
||||||
|
var obj = self.obj
|
||||||
|
var mth = self.mth
|
||||||
|
if (obj && mth)
|
||||||
|
mth(obj, rgb)
|
||||||
|
end
|
||||||
|
|
||||||
|
return rgb
|
||||||
|
end
|
||||||
|
end
|
||||||
|
animate.palette = Animate_palette
|
||||||
|
|
||||||
|
#-
|
||||||
|
|
||||||
|
pal = Animate_palette(PALETTE_STANDARD_TAG, 7000)
|
||||||
|
pal = Animate_palette(PALETTE_STANDARD_VAL, 7000)
|
||||||
|
|
||||||
|
|
||||||
|
import animate
|
||||||
|
var pal = animate.palette(PALETTE_STANDARD_TAG, 7000)
|
||||||
|
pal.start(0)
|
||||||
|
for t: range(0,8000,200)
|
||||||
|
pal.tick(t)
|
||||||
|
end
|
||||||
|
|
||||||
|
-#
|
||||||
|
|
||||||
|
animate.SAWTOOTH = 1
|
||||||
|
animate.TRIANGLE = 2
|
||||||
|
animate.SQUARE = 3
|
||||||
|
animate.COSINE = 4
|
||||||
|
animate.SINE = 5
|
||||||
|
animate.LASTFOMR = 5 # identify last form
|
||||||
|
|
||||||
|
#@ solidify:Animate_oscillator,weak
|
||||||
|
class Animate_oscillator : Animate_animator
|
||||||
|
## inherited
|
||||||
|
## timing information
|
||||||
|
# var running
|
||||||
|
# var duration_ms # duration_ms of the entire cycle in ms, cannot be `0`
|
||||||
|
# var origin # origin in ms of the current cycle, as per tasmota.millis() reference
|
||||||
|
var phase # 0..100% - phase shift, default 0
|
||||||
|
var duty_cycle # 0..100% - duty cycle, default 50%
|
||||||
|
## callback information
|
||||||
|
# var obj # object to call
|
||||||
|
# var mth # object method to call
|
||||||
|
var a # starting value
|
||||||
|
var b # end value
|
||||||
|
var form # waveform
|
||||||
|
# current value
|
||||||
|
var value
|
||||||
|
|
||||||
|
def init(a, b, duration_ms, form)
|
||||||
|
self.phase = 0
|
||||||
|
self.duty_cycle = 50
|
||||||
|
self.a = a
|
||||||
|
self.b = b
|
||||||
|
self.duration_ms = duration_ms
|
||||||
|
self.value = a
|
||||||
|
if (form == nil) form = 1 end
|
||||||
|
self.form = form
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_phase(phase)
|
||||||
|
if (phase < 0) phase = 0 end
|
||||||
|
if (phase > 100) phase = 100 end
|
||||||
|
self.phase = phase
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_duty_cycle(duty_cycle)
|
||||||
|
if (duty_cycle < 0) duty_cycle = 0 end
|
||||||
|
if (duty_cycle > 100) duty_cycle = 100 end
|
||||||
|
self.duty_cycle = duty_cycle
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_a(a)
|
||||||
|
self.a = a
|
||||||
|
end
|
||||||
|
def set_b(b)
|
||||||
|
self.b = b
|
||||||
|
end
|
||||||
|
|
||||||
|
def animate(millis)
|
||||||
|
if (self.duration_ms == nil) return end
|
||||||
|
if millis == nil millis = tasmota.millis() end
|
||||||
|
var past = millis - self.origin
|
||||||
|
if past < 0
|
||||||
|
past = 0
|
||||||
|
millis = self.originally
|
||||||
|
end
|
||||||
|
var duration_ms = self.duration_ms
|
||||||
|
var duration_ms_mid # mid point considering duty cycle
|
||||||
|
duration_ms_mid = tasmota.scale_uint(self.duty_cycle, 0, 100, 0, duration_ms)
|
||||||
|
if past >= duration_ms
|
||||||
|
self.origin += (past / duration_ms) * duration_ms
|
||||||
|
past = past % duration_ms
|
||||||
|
# handle end of cycle
|
||||||
|
self.beat()
|
||||||
|
end
|
||||||
|
|
||||||
|
var a = self.a
|
||||||
|
var b = self.b
|
||||||
|
var value = self.value
|
||||||
|
var past_with_phase = past # adjust past with phase
|
||||||
|
if self.phase > 0
|
||||||
|
past_with_phase += tasmota.scale_uint(self.phase, 0, 100, 0, duration_ms)
|
||||||
|
if (past_with_phase > duration_ms) past_with_phase -= duration_ms end # if overflow, take modulus
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.form == 1 #-SAWTOOTH-#
|
||||||
|
value = tasmota.scale_int(past_with_phase, 0, duration_ms - 1, a, b)
|
||||||
|
elif self.form == 2 #-TRIANGLE-#
|
||||||
|
if past_with_phase < duration_ms_mid
|
||||||
|
value = tasmota.scale_int(past_with_phase, 0, duration_ms_mid - 1, a, b)
|
||||||
|
else
|
||||||
|
value = tasmota.scale_int(past_with_phase, duration_ms_mid, duration_ms - 1, b, a)
|
||||||
|
end
|
||||||
|
elif self.form == 3 #-SQUARE-#
|
||||||
|
if past_with_phase < duration_ms_mid
|
||||||
|
value = a
|
||||||
|
else
|
||||||
|
value = b
|
||||||
|
end
|
||||||
|
elif (self.form == 4) #-COSINE-# || (self.form == 5) #-SINE-#
|
||||||
|
# map timing to 0..32767
|
||||||
|
var angle = tasmota.scale_int(past_with_phase, 0, duration_ms - 1, 0, 32767)
|
||||||
|
if (self.form == 4) #-COSINE-#
|
||||||
|
angle -= 8192
|
||||||
|
end
|
||||||
|
var x = tasmota.sine_int(angle) # -4096 .. 4096
|
||||||
|
value = tasmota.scale_int(x, -4096, 4096, a, b)
|
||||||
|
end
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
var obj = self.obj
|
||||||
|
var mth = self.mth
|
||||||
|
if (obj && mth)
|
||||||
|
mth(obj, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
animate.oscillator = Animate_oscillator
|
@ -1,573 +0,0 @@
|
|||||||
#
|
|
||||||
# class Animate
|
|
||||||
#
|
|
||||||
# Animation framework
|
|
||||||
#
|
|
||||||
|
|
||||||
#@ solidify:animate,weak
|
|
||||||
animate = module("animate")
|
|
||||||
|
|
||||||
# state-machine: from val a to b
|
|
||||||
class Animate_ins_ramp
|
|
||||||
var a # starting value
|
|
||||||
var b # end value
|
|
||||||
var duration # duration in milliseconds
|
|
||||||
|
|
||||||
def init(a,b,duration)
|
|
||||||
self.a = a
|
|
||||||
self.b = b
|
|
||||||
self.duration = duration
|
|
||||||
end
|
|
||||||
end
|
|
||||||
animate.ins_ramp = Animate_ins_ramp
|
|
||||||
|
|
||||||
|
|
||||||
#################################################################################
|
|
||||||
# class Animate_palette
|
|
||||||
#
|
|
||||||
# Animated color palette
|
|
||||||
#################################################################################
|
|
||||||
|
|
||||||
#################################################################################
|
|
||||||
# Palette format compatible
|
|
||||||
#
|
|
||||||
# Takes a binary array with a set of 4 bytes elements: VRGB
|
|
||||||
# V: Value in a range 0..255. The first value must be 0,
|
|
||||||
# the last needs to be 255.
|
|
||||||
# Numbers must be in strictly increasin numbers.
|
|
||||||
# The algorithm maps a 0..255 rotating value to its color
|
|
||||||
# in the palette.
|
|
||||||
# R: Red component
|
|
||||||
# G: Green component
|
|
||||||
# B: Blue component
|
|
||||||
# Note: RGB is in big Endian to make it more readable, although
|
|
||||||
# it's little-endian when in memory. Be aware!
|
|
||||||
# RGB values are stored at max brightness and without gamma correction
|
|
||||||
#################################################################################
|
|
||||||
|
|
||||||
# Gradient palette "ib_jul01_gp", originally from
|
|
||||||
# http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/xmas/tn/ib_jul01.png.index.html
|
|
||||||
var PALETTE_ib_jul01_gp = bytes(
|
|
||||||
"00" "E60611"
|
|
||||||
"5E" "25605A"
|
|
||||||
"85" "90BD6A"
|
|
||||||
"FF" "BB030D"
|
|
||||||
)
|
|
||||||
# animate.PALETTE_ib_jul01_gp = PALETTE_ib_jul01_gp
|
|
||||||
# rgb(230, 6, 17) 0.000%,
|
|
||||||
# rgb( 37, 96, 90) 37.010%,
|
|
||||||
# rgb(144,189,106) 52.000%,
|
|
||||||
# rgb(187, 3, 13) 100.000%
|
|
||||||
|
|
||||||
var PALETTE_STANDARD_VAL = bytes(
|
|
||||||
"00" "FF0000" # red
|
|
||||||
"24" "FFA500" # orange
|
|
||||||
"49" "FFFF00" # yellow
|
|
||||||
"6E" "008800" # green
|
|
||||||
"92" "0000FF" # blue
|
|
||||||
"B7" "4B0082" # indigo
|
|
||||||
"DB" "EE82EE" # violet
|
|
||||||
"FF" "FF0000" # red
|
|
||||||
)
|
|
||||||
# animate.PALETTE_STANDARD = PALETTE_STANDARD
|
|
||||||
|
|
||||||
var PALETTE_SATURATED_TAG = bytes(
|
|
||||||
"40" "FF0000" # red
|
|
||||||
"40" "FFA500" # orange
|
|
||||||
"40" "FFFF00" # yellow
|
|
||||||
"40" "00FF00" # green
|
|
||||||
"40" "0000FF" # blue
|
|
||||||
"40" "FF00FF" # indigo
|
|
||||||
"40" "EE44A5" # violet
|
|
||||||
"00" "FF0000" # red
|
|
||||||
)
|
|
||||||
|
|
||||||
var PALETTE_STANDARD_TAG = bytes(
|
|
||||||
"40" "FF0000" # red
|
|
||||||
"40" "FFA500" # orange
|
|
||||||
"40" "FFFF00" # yellow
|
|
||||||
"40" "008800" # green
|
|
||||||
"40" "0000FF" # blue
|
|
||||||
"40" "4B0082" # indigo
|
|
||||||
"40" "EE82EE" # violet
|
|
||||||
"00" "FF0000" # red
|
|
||||||
)
|
|
||||||
# animate.PALETTE_STANDARD = PALETTE_STANDARD
|
|
||||||
|
|
||||||
|
|
||||||
class Animate_palette
|
|
||||||
# parsing of palette
|
|
||||||
var palette # raw bytes object
|
|
||||||
var slots_arr # constructed array of timestamp slots
|
|
||||||
var slots # number of slots
|
|
||||||
# timing information
|
|
||||||
var running
|
|
||||||
var duration_ms # duration_ms of the entire cycle in ms, cannot be `0`
|
|
||||||
var origin # origin in ms of the current cycle, as per tasmota.millis() reference
|
|
||||||
# range information (when used as range color)
|
|
||||||
var range_min # minimum value expected as input
|
|
||||||
var range_max # maximum value expected as input, needs (range_min < range_max, can be negative)
|
|
||||||
# callback information
|
|
||||||
var animate_obj # object to call
|
|
||||||
var animate_mth # object method to call
|
|
||||||
# brightness
|
|
||||||
var bri # brightness to be applied to palette 0..100
|
|
||||||
# color object to do RGB color calculation
|
|
||||||
var color # instance of light_state, used for color calculation (reuse of object)
|
|
||||||
|
|
||||||
def init(palette, duration_s)
|
|
||||||
self.running = false
|
|
||||||
self.palette = palette
|
|
||||||
self.bri = 100
|
|
||||||
self.slots = size(palette) / 4
|
|
||||||
if duration_s != nil
|
|
||||||
self.set_duration(int(duration_s * 1000))
|
|
||||||
end
|
|
||||||
self.color = light_state(light_state.RGB)
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_cb(obj, mth)
|
|
||||||
self.animate_obj = obj
|
|
||||||
self.animate_mth = mth
|
|
||||||
end
|
|
||||||
|
|
||||||
# setter to be used as cb
|
|
||||||
def set_bri(bri)
|
|
||||||
self.bri = int(bri)
|
|
||||||
end
|
|
||||||
|
|
||||||
def start(millis)
|
|
||||||
if (self.duration_ms == nil) return end
|
|
||||||
if millis == nil millis = tasmota.millis() end
|
|
||||||
self.origin = millis
|
|
||||||
self.running = true
|
|
||||||
end
|
|
||||||
|
|
||||||
def stop()
|
|
||||||
self.origin = nil
|
|
||||||
self.running = false
|
|
||||||
end
|
|
||||||
|
|
||||||
def is_running()
|
|
||||||
return bool(self.running)
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_palette(min, max)
|
|
||||||
var arr = []
|
|
||||||
var slots = self.slots
|
|
||||||
arr.resize(slots)
|
|
||||||
|
|
||||||
# check if we have slots or values
|
|
||||||
# if first value index is non-zero, it's ticks count
|
|
||||||
if self.palette.get(0, 1) != 0
|
|
||||||
# palette in tick counts
|
|
||||||
# compute the total number of ticks
|
|
||||||
var total_ticks = 0
|
|
||||||
var idx = 0
|
|
||||||
while idx < slots - 1
|
|
||||||
total_ticks += self.palette.get(idx * 4, 1)
|
|
||||||
idx += 1
|
|
||||||
end
|
|
||||||
var cur_ticks = 0
|
|
||||||
idx = 0
|
|
||||||
while idx < slots
|
|
||||||
arr[idx] = tasmota.scale_int(cur_ticks, 0, total_ticks, min, max)
|
|
||||||
cur_ticks += self.palette.get(idx * 4, 1)
|
|
||||||
idx += 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
# palette is in value range from 0..255
|
|
||||||
var idx = 0
|
|
||||||
while idx < slots
|
|
||||||
var val = self.palette.get(idx * 4, 1)
|
|
||||||
arr[idx] = tasmota.scale_int(val, 0, 255, min, max)
|
|
||||||
idx += 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
# print(f"ANM: {arr=}")
|
|
||||||
return arr
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_duration(duration_ms)
|
|
||||||
if (duration_ms == nil) return end
|
|
||||||
if duration_ms <= 0 raise "value_error", "duration_ms must be positive" end
|
|
||||||
self.duration_ms = duration_ms
|
|
||||||
|
|
||||||
self.slots_arr = self.parse_palette(0, duration_ms - 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_range(min, max)
|
|
||||||
if (min >= max) raise "value_error", "min must be lower than mex" end
|
|
||||||
self.range_min = min
|
|
||||||
self.range_max = max
|
|
||||||
|
|
||||||
self.slots_arr = self.parse_palette(min, max)
|
|
||||||
end
|
|
||||||
|
|
||||||
# compute the css linear-gradient description
|
|
||||||
#
|
|
||||||
# Example: background: linear-gradient(to right, #000000, #e66465 11.0%, #9198e5);
|
|
||||||
def to_css_gradient()
|
|
||||||
var arr = self.parse_palette(0, 1000)
|
|
||||||
var ret = "background:linear-gradient(to right"
|
|
||||||
var idx = 0
|
|
||||||
while idx < size(arr)
|
|
||||||
var prm = arr[idx] # per mile
|
|
||||||
|
|
||||||
var bgrt = self.palette.get(idx * 4, 4)
|
|
||||||
var r = (bgrt >> 8) & 0xFF
|
|
||||||
var g = (bgrt >> 16) & 0xFF
|
|
||||||
var b = (bgrt >> 24) & 0xFF
|
|
||||||
ret += f",#{r:02X}{g:02X}{b:02X} {prm/10.0:.1f}%"
|
|
||||||
idx += 1
|
|
||||||
end
|
|
||||||
ret += ");"
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_value(value)
|
|
||||||
if (self.range_min == nil || self.range_max == nil) return nil end
|
|
||||||
var scale_int = tasmota.scale_int
|
|
||||||
|
|
||||||
# find slot
|
|
||||||
var slots = self.slots
|
|
||||||
var idx = slots - 2
|
|
||||||
while idx > 0
|
|
||||||
if value >= self.slots_arr[idx] break end
|
|
||||||
idx -= 1
|
|
||||||
end
|
|
||||||
var bgrt0 = self.palette.get(idx * 4, 4)
|
|
||||||
var bgrt1 = self.palette.get((idx + 1) * 4, 4)
|
|
||||||
var t0 = self.slots_arr[idx]
|
|
||||||
var t1 = self.slots_arr[idx + 1]
|
|
||||||
var r = scale_int(value, t0, t1, (bgrt0 >> 8) & 0xFF, (bgrt1 >> 8) & 0xFF)
|
|
||||||
var g = scale_int(value, t0, t1, (bgrt0 >> 16) & 0xFF, (bgrt1 >> 16) & 0xFF)
|
|
||||||
var b = scale_int(value, t0, t1, (bgrt0 >> 24) & 0xFF, (bgrt1 >> 24) & 0xFF)
|
|
||||||
var rgb = (r << 16) | (g << 8) | b
|
|
||||||
#
|
|
||||||
var obj = self.animate_obj
|
|
||||||
var mth = self.animate_mth
|
|
||||||
if (obj && mth)
|
|
||||||
mth(obj, rgb)
|
|
||||||
end
|
|
||||||
# if self.cb != nil
|
|
||||||
# self.cb(rgb)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# print(f"ANM: {rgb=:%06X}")
|
|
||||||
return rgb
|
|
||||||
end
|
|
||||||
|
|
||||||
def animate(millis)
|
|
||||||
if (self.duration_ms == nil) return end
|
|
||||||
if millis == nil millis = tasmota.millis() end
|
|
||||||
var past = millis - self.origin
|
|
||||||
if past < 0
|
|
||||||
past = 0
|
|
||||||
millis = self.origin
|
|
||||||
end
|
|
||||||
var duration_ms = self.duration_ms
|
|
||||||
var scale_uint = tasmota.scale_uint
|
|
||||||
if past >= duration_ms
|
|
||||||
self.origin += (past / duration_ms) * duration_ms
|
|
||||||
past = past % duration_ms
|
|
||||||
end
|
|
||||||
# find slot
|
|
||||||
var slots = self.slots
|
|
||||||
var idx = slots - 2
|
|
||||||
while idx > 0
|
|
||||||
if past >= self.slots_arr[idx] break end
|
|
||||||
idx -= 1
|
|
||||||
end
|
|
||||||
var bgrt0 = self.palette.get(idx * 4, 4)
|
|
||||||
var bgrt1 = self.palette.get((idx + 1) * 4, 4)
|
|
||||||
var t0 = self.slots_arr[idx]
|
|
||||||
var t1 = self.slots_arr[idx + 1]
|
|
||||||
var r = scale_uint(past, t0, t1, (bgrt0 >> 8) & 0xFF, (bgrt1 >> 8) & 0xFF)
|
|
||||||
var g = scale_uint(past, t0, t1, (bgrt0 >> 16) & 0xFF, (bgrt1 >> 16) & 0xFF)
|
|
||||||
var b = scale_uint(past, t0, t1, (bgrt0 >> 24) & 0xFF, (bgrt1 >> 24) & 0xFF)
|
|
||||||
|
|
||||||
var color = self.color
|
|
||||||
color.set_rgb((bgrt0 >> 8) & 0xFF, (bgrt0 >> 16) & 0xFF, (bgrt0 >> 24) & 0xFF)
|
|
||||||
var bri0 = color.bri
|
|
||||||
color.set_rgb((bgrt1 >> 8) & 0xFF, (bgrt1 >> 16) & 0xFF, (bgrt1 >> 24) & 0xFF)
|
|
||||||
var bri1 = color.bri
|
|
||||||
var bri2 = scale_uint(past, t0, t1, bri0, bri1)
|
|
||||||
color.set_rgb(r, g, b)
|
|
||||||
color.set_bri(bri2)
|
|
||||||
|
|
||||||
r = color.r
|
|
||||||
g = color.g
|
|
||||||
b = color.b
|
|
||||||
|
|
||||||
# apply self.bri if not `100`
|
|
||||||
var bri = self.bri
|
|
||||||
if bri != 100
|
|
||||||
r = tasmota.scale_uint(r, 0, 100, 0, bri)
|
|
||||||
g = tasmota.scale_uint(g, 0, 100, 0, bri)
|
|
||||||
b = tasmota.scale_uint(b, 0, 100, 0, bri)
|
|
||||||
end
|
|
||||||
|
|
||||||
# var rgb = (r << 16) | (g << 8) | b
|
|
||||||
var rgb = (r << 16) | (g << 8) | b
|
|
||||||
|
|
||||||
var obj = self.animate_obj
|
|
||||||
var mth = self.animate_mth
|
|
||||||
if (obj && mth)
|
|
||||||
mth(obj, rgb)
|
|
||||||
end
|
|
||||||
|
|
||||||
return rgb
|
|
||||||
end
|
|
||||||
end
|
|
||||||
animate.palette = Animate_palette
|
|
||||||
|
|
||||||
#-
|
|
||||||
|
|
||||||
pal = Animate_palette(PALETTE_STANDARD_TAG, 7000)
|
|
||||||
pal = Animate_palette(PALETTE_STANDARD_VAL, 7000)
|
|
||||||
|
|
||||||
|
|
||||||
import animate
|
|
||||||
var pal = animate.palette(PALETTE_STANDARD_TAG, 7000)
|
|
||||||
pal.start(0)
|
|
||||||
for t: range(0,8000,200)
|
|
||||||
pal.tick(t)
|
|
||||||
end
|
|
||||||
|
|
||||||
-#
|
|
||||||
|
|
||||||
#################################################################################
|
|
||||||
# class Animate_segment
|
|
||||||
#
|
|
||||||
# Animate a small segment ______/+++\______
|
|
||||||
# length in 1/256 pixels
|
|
||||||
# slew in 1/256 pixels
|
|
||||||
# fore foregroung color
|
|
||||||
# back background color (or transparent)
|
|
||||||
# origin in 1/256 pixels
|
|
||||||
#
|
|
||||||
# strip
|
|
||||||
#################################################################################
|
|
||||||
# class Animate_segment
|
|
||||||
# var strip
|
|
||||||
# var length
|
|
||||||
# var slew
|
|
||||||
# var fore
|
|
||||||
# var back
|
|
||||||
# var origin
|
|
||||||
|
|
||||||
# def init(strip)
|
|
||||||
# self.strip = strip
|
|
||||||
# self.length = 256 # 1 pixel
|
|
||||||
# self.slew = 0 # 0 pixel (immediate)
|
|
||||||
# self.fore = 0x00FF0000 # red opaque
|
|
||||||
# self.back = 0xFF000000 # transparent
|
|
||||||
# self.origin = 0 # start of strip
|
|
||||||
# end
|
|
||||||
|
|
||||||
# def paint(bri)
|
|
||||||
# # move all important values in registers
|
|
||||||
# var strip = self.strip
|
|
||||||
# var pix_offset = strip.pixel_offset()
|
|
||||||
# var pix_count = strip.pixel_count()
|
|
||||||
# var pix_buffer = strip.pixels_buffer()
|
|
||||||
# var pix_size = strip.pixel_size()
|
|
||||||
|
|
||||||
# var length = self.length
|
|
||||||
# var slew = self.slew
|
|
||||||
# var fore = self.fore
|
|
||||||
# var back = self.back
|
|
||||||
# var origin = self.origin
|
|
||||||
|
|
||||||
# var pix = 0 # iterate on each pixel
|
|
||||||
# var limit_low = (origin - slew) / 256
|
|
||||||
# var limit_high = (origin + length + slew) / 256
|
|
||||||
# while pix < pix_count
|
|
||||||
# # are we off limits
|
|
||||||
# if (pix >= limit_low) && (pix <= limit_high) # outside of those boundaries, we just apply backgroung
|
|
||||||
# strip.set_pixel_color(pix, fore, bri)
|
|
||||||
# else
|
|
||||||
# strip.set_pixel_color(pix, back, bri)
|
|
||||||
# end
|
|
||||||
# pix += 1
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# animate.segment = Animate_segment
|
|
||||||
|
|
||||||
# state-machine: pause and goto
|
|
||||||
class Animate_ins_goto
|
|
||||||
var pc_rel # relative PC, -1 previous instruction, 1 next instruction, 0 means see pc_abs
|
|
||||||
var pc_abs # absolute PC, only if pc_rel == 0, address if next instruction
|
|
||||||
var duration # pause in milliseconds before goto, -1 means infinite (state-machine can be changed externally)
|
|
||||||
|
|
||||||
def init(pc_rel, pc_abs, duration)
|
|
||||||
self.pc_rel = pc_rel
|
|
||||||
self.pc_abs = pc_abs
|
|
||||||
self.duration = duration
|
|
||||||
end
|
|
||||||
end
|
|
||||||
animate.ins_goto = Animate_ins_goto
|
|
||||||
|
|
||||||
class Animate_engine
|
|
||||||
var code # array of state-machine instructions
|
|
||||||
var closure # closure to call with the new value
|
|
||||||
var animate_obj # object to call (alternative to closure)
|
|
||||||
var animate_mth # method to call on object
|
|
||||||
var pc # program-counter
|
|
||||||
var ins_time # absolute time when the current instruction started
|
|
||||||
var running # is the animation running? allows fast return
|
|
||||||
var value # current value
|
|
||||||
|
|
||||||
def init()
|
|
||||||
self.code = []
|
|
||||||
self.pc = 0 # start at instruction 0
|
|
||||||
self.ins_time = 0
|
|
||||||
self.running = false # not running by default
|
|
||||||
#
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_cb(obj, mth)
|
|
||||||
self.animate_obj = obj
|
|
||||||
self.animate_mth = mth
|
|
||||||
end
|
|
||||||
|
|
||||||
# start but needs external calls to `animate()`
|
|
||||||
# cur_time:int (opt) current timestamp in ms, defaults to `tasmota.millis()`
|
|
||||||
# val:int (opt) starting value, default to `nil`
|
|
||||||
def start(cur_time, val)
|
|
||||||
if cur_time == nil cur_time = tasmota.millis() end
|
|
||||||
if (val != nil) self.value = val end
|
|
||||||
self.ins_time = cur_time
|
|
||||||
|
|
||||||
self.running = true
|
|
||||||
end
|
|
||||||
|
|
||||||
# # runs autonomously in the Tasmota event loop
|
|
||||||
# def autorun(cur_time, val)
|
|
||||||
# self.run(cur_time, val)
|
|
||||||
# end
|
|
||||||
|
|
||||||
def stop()
|
|
||||||
self.running = false
|
|
||||||
end
|
|
||||||
|
|
||||||
def is_running()
|
|
||||||
return self.running
|
|
||||||
end
|
|
||||||
|
|
||||||
def animate(cur_time) # time in milliseconds, optional, defaults to `tasmota.millis()`
|
|
||||||
if !self.running return end
|
|
||||||
if cur_time == nil cur_time = tasmota.millis() end
|
|
||||||
# run through instructions
|
|
||||||
while true
|
|
||||||
var sub_index = cur_time - self.ins_time # time since the beginning of current instruction
|
|
||||||
#
|
|
||||||
# make sure PC is valid
|
|
||||||
if self.pc >= size(self.code)
|
|
||||||
self.running = false
|
|
||||||
break
|
|
||||||
end
|
|
||||||
#
|
|
||||||
if self.pc < 0 raise "internal_error", "Animate pc is out of range" end
|
|
||||||
var ins = self.code[self.pc]
|
|
||||||
|
|
||||||
# Instruction Ramp
|
|
||||||
if isinstance(ins, animate.ins_ramp)
|
|
||||||
var closure = self.closure # assign to a local variable to not call a method
|
|
||||||
var obj = self.animate_obj
|
|
||||||
var mth = self.animate_mth
|
|
||||||
if sub_index < ins.duration
|
|
||||||
# we're still in the ramp
|
|
||||||
self.value = tasmota.scale_uint(sub_index, 0, ins.duration, ins.a, ins.b)
|
|
||||||
# call method
|
|
||||||
if (obj && mth) mth(obj, self.value) end
|
|
||||||
# call closure
|
|
||||||
if (closure) closure(self.value) end # call closure, need try? TODO
|
|
||||||
break
|
|
||||||
else
|
|
||||||
self.value = ins.b
|
|
||||||
# call method
|
|
||||||
if (obj && mth) mth(obj, self.value) end
|
|
||||||
# call closure
|
|
||||||
if (closure) closure(self.value) end # set to last value
|
|
||||||
self.pc += 1 # next instruction
|
|
||||||
self.ins_time = cur_time - (sub_index - ins.duration)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Instruction Goto
|
|
||||||
elif isinstance(ins, animate.ins_goto)
|
|
||||||
if sub_index < ins.duration
|
|
||||||
break
|
|
||||||
else
|
|
||||||
if ins.pc_rel != 0
|
|
||||||
self.pc += ins.pc_rel
|
|
||||||
else
|
|
||||||
self.pc = ins.pc_abs
|
|
||||||
end
|
|
||||||
self.ins_time = cur_time - (sub_index - ins.duration)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Invalid
|
|
||||||
else
|
|
||||||
raise "internal_error", "unknown instruction"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return self.value
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
animate.engine = Animate_engine
|
|
||||||
|
|
||||||
class Animate_from_to : Animate_engine
|
|
||||||
|
|
||||||
def init(obj, mth, from, to, duration)
|
|
||||||
super(self).init()
|
|
||||||
self.set_cb(obj, mth)
|
|
||||||
self.code.push(animate.ins_ramp(from, to, duration))
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
animate.from_to = Animate_from_to
|
|
||||||
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# a=Animate_from_to(nil, 0, 100, 5000)
|
|
||||||
#
|
|
||||||
###
|
|
||||||
|
|
||||||
class Animate_rotate : Animate_engine
|
|
||||||
|
|
||||||
def init(obj, mth, from, to, duration)
|
|
||||||
super(self).init()
|
|
||||||
self.set_cb(obj, mth)
|
|
||||||
self.code.push(animate.ins_ramp(from, to, duration))
|
|
||||||
self.code.push(animate.ins_goto(0, 0, 0)) # goto abs pc = 0 without any pause
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
animate.rotate = Animate_rotate
|
|
||||||
|
|
||||||
#-
|
|
||||||
a=Animate_rotate(nil, 0, 100, 5000)
|
|
||||||
a.autorun()
|
|
||||||
-#
|
|
||||||
|
|
||||||
class Animate_back_forth : Animate_engine
|
|
||||||
|
|
||||||
def init(obj, mth, from, to, duration)
|
|
||||||
super(self).init()
|
|
||||||
self.set_cb(obj, mth)
|
|
||||||
self.code.push(animate.ins_ramp(from, to, duration))
|
|
||||||
self.code.push(animate.ins_ramp(to, from, duration))
|
|
||||||
self.code.push(animate.ins_goto(0, 0, 0)) # goto abs pc = 0 without any pause
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
animate.back_forth = Animate_back_forth
|
|
||||||
|
|
||||||
#-
|
|
||||||
a=Animate_back_forth(nil, 0, 100, 5000)
|
|
||||||
a.autorun()
|
|
||||||
-#
|
|
@ -1,15 +1,15 @@
|
|||||||
/* Solidification of leds_0_animator.h */
|
/* Solidification of animate_0_core.h */
|
||||||
/********************************************************************\
|
/********************************************************************\
|
||||||
* Generated code, don't edit *
|
* Generated code, don't edit *
|
||||||
\********************************************************************/
|
\********************************************************************/
|
||||||
#include "be_constobj.h"
|
#include "be_constobj.h"
|
||||||
|
|
||||||
extern const bclass be_class_Leds_animator;
|
extern const bclass be_class_Animate_core;
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: remove
|
** Solidified function: remove
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_remove, /* name */
|
be_local_closure(Animate_core_remove, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
4, /* nstack */
|
4, /* nstack */
|
||||||
1, /* argc */
|
1, /* argc */
|
||||||
@ -44,7 +44,7 @@ be_local_closure(Leds_animator_remove, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: add_background_animator
|
** Solidified function: add_background_animator
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_add_background_animator, /* name */
|
be_local_closure(Animate_core_add_background_animator, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
6, /* nstack */
|
6, /* nstack */
|
||||||
2, /* argc */
|
2, /* argc */
|
||||||
@ -79,7 +79,7 @@ be_local_closure(Leds_animator_add_background_animator, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: clear
|
** Solidified function: clear
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_clear, /* name */
|
be_local_closure(Animate_core_clear, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
3, /* nstack */
|
3, /* nstack */
|
||||||
1, /* argc */
|
1, /* argc */
|
||||||
@ -112,7 +112,7 @@ be_local_closure(Leds_animator_clear, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: add_animator
|
** Solidified function: add_animator
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_add_animator, /* name */
|
be_local_closure(Animate_core_add_animator, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
5, /* nstack */
|
5, /* nstack */
|
||||||
2, /* argc */
|
2, /* argc */
|
||||||
@ -143,7 +143,7 @@ be_local_closure(Leds_animator_add_animator, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: animate
|
** Solidified function: animate
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_animate, /* name */
|
be_local_closure(Animate_core_animate, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
1, /* nstack */
|
1, /* nstack */
|
||||||
1, /* argc */
|
1, /* argc */
|
||||||
@ -167,7 +167,7 @@ be_local_closure(Leds_animator_animate, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: get_bri
|
** Solidified function: get_bri
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_get_bri, /* name */
|
be_local_closure(Animate_core_get_bri, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
3, /* nstack */
|
3, /* nstack */
|
||||||
2, /* argc */
|
2, /* argc */
|
||||||
@ -194,7 +194,7 @@ be_local_closure(Leds_animator_get_bri, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: set_bri
|
** Solidified function: set_bri
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_set_bri, /* name */
|
be_local_closure(Animate_core_set_bri, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
2, /* nstack */
|
2, /* nstack */
|
||||||
2, /* argc */
|
2, /* argc */
|
||||||
@ -221,7 +221,7 @@ be_local_closure(Leds_animator_set_bri, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: set_back_color
|
** Solidified function: set_back_color
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_set_back_color, /* name */
|
be_local_closure(Animate_core_set_back_color, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
2, /* nstack */
|
2, /* nstack */
|
||||||
2, /* argc */
|
2, /* argc */
|
||||||
@ -248,7 +248,7 @@ be_local_closure(Leds_animator_set_back_color, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: stop
|
** Solidified function: stop
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_stop, /* name */
|
be_local_closure(Animate_core_stop, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
6, /* nstack */
|
6, /* nstack */
|
||||||
1, /* argc */
|
1, /* argc */
|
||||||
@ -299,7 +299,7 @@ be_local_closure(Leds_animator_stop, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: set_cb
|
** Solidified function: set_cb
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_set_cb, /* name */
|
be_local_closure(Animate_core_set_cb, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
3, /* nstack */
|
3, /* nstack */
|
||||||
3, /* argc */
|
3, /* argc */
|
||||||
@ -328,9 +328,9 @@ be_local_closure(Leds_animator_set_cb, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: init
|
** Solidified function: init
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_init, /* name */
|
be_local_closure(Animate_core_init, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
5, /* nstack */
|
7, /* nstack */
|
||||||
3, /* argc */
|
3, /* argc */
|
||||||
2, /* varg */
|
2, /* varg */
|
||||||
0, /* has upvals */
|
0, /* has upvals */
|
||||||
@ -363,15 +363,15 @@ be_local_closure(Leds_animator_init, /* name */
|
|||||||
}),
|
}),
|
||||||
1, /* has constants */
|
1, /* has constants */
|
||||||
( &(const bvalue[13]) { /* constants */
|
( &(const bvalue[13]) { /* constants */
|
||||||
/* K0 */ be_nested_str_weak(strip),
|
/* K0 */ be_nested_str_weak(animate),
|
||||||
/* K1 */ be_nested_str_weak(bri),
|
/* K1 */ be_nested_str_weak(strip),
|
||||||
/* K2 */ be_nested_str_weak(running),
|
/* K2 */ be_nested_str_weak(bri),
|
||||||
/* K3 */ be_nested_str_weak(pixel_count),
|
/* K3 */ be_nested_str_weak(running),
|
||||||
/* K4 */ be_nested_str_weak(animators),
|
/* K4 */ be_nested_str_weak(pixel_count),
|
||||||
/* K5 */ be_nested_str_weak(painters),
|
/* K5 */ be_nested_str_weak(animators),
|
||||||
/* K6 */ be_nested_str_weak(clear),
|
/* K6 */ be_nested_str_weak(painters),
|
||||||
/* K7 */ be_nested_str_weak(frame),
|
/* K7 */ be_nested_str_weak(clear),
|
||||||
/* K8 */ be_nested_str_weak(Leds_frame),
|
/* K8 */ be_nested_str_weak(frame),
|
||||||
/* K9 */ be_nested_str_weak(layer),
|
/* K9 */ be_nested_str_weak(layer),
|
||||||
/* K10 */ be_nested_str_weak(fast_loop_cb),
|
/* K10 */ be_nested_str_weak(fast_loop_cb),
|
||||||
/* K11 */ be_nested_str_weak(back_color),
|
/* K11 */ be_nested_str_weak(back_color),
|
||||||
@ -379,39 +379,40 @@ be_local_closure(Leds_animator_init, /* name */
|
|||||||
}),
|
}),
|
||||||
be_str_weak(init),
|
be_str_weak(init),
|
||||||
&be_const_str_solidified,
|
&be_const_str_solidified,
|
||||||
( &(const binstruction[32]) { /* code */
|
( &(const binstruction[33]) { /* code */
|
||||||
0x90020001, // 0000 SETMBR R0 K0 R1
|
0xA40E0000, // 0000 IMPORT R3 K0
|
||||||
0x4C0C0000, // 0001 LDNIL R3
|
0x90020201, // 0001 SETMBR R0 K1 R1
|
||||||
0x1C0C0403, // 0002 EQ R3 R2 R3
|
0x4C100000, // 0002 LDNIL R4
|
||||||
0x780E0000, // 0003 JMPF R3 #0005
|
0x1C100404, // 0003 EQ R4 R2 R4
|
||||||
0x540A0031, // 0004 LDINT R2 50
|
0x78120000, // 0004 JMPF R4 #0006
|
||||||
0x90020202, // 0005 SETMBR R0 K1 R2
|
0x540A0031, // 0005 LDINT R2 50
|
||||||
0x500C0000, // 0006 LDBOOL R3 0 0
|
0x90020402, // 0006 SETMBR R0 K2 R2
|
||||||
0x90020403, // 0007 SETMBR R0 K2 R3
|
0x50100000, // 0007 LDBOOL R4 0 0
|
||||||
0x8C0C0303, // 0008 GETMET R3 R1 K3
|
0x90020604, // 0008 SETMBR R0 K3 R4
|
||||||
0x7C0C0200, // 0009 CALL R3 1
|
0x8C100304, // 0009 GETMET R4 R1 K4
|
||||||
0x90020603, // 000A SETMBR R0 K3 R3
|
0x7C100200, // 000A CALL R4 1
|
||||||
0x600C0012, // 000B GETGBL R3 G18
|
0x90020804, // 000B SETMBR R0 K4 R4
|
||||||
0x7C0C0000, // 000C CALL R3 0
|
0x60100012, // 000C GETGBL R4 G18
|
||||||
0x90020803, // 000D SETMBR R0 K4 R3
|
0x7C100000, // 000D CALL R4 0
|
||||||
0x600C0012, // 000E GETGBL R3 G18
|
0x90020A04, // 000E SETMBR R0 K5 R4
|
||||||
0x7C0C0000, // 000F CALL R3 0
|
0x60100012, // 000F GETGBL R4 G18
|
||||||
0x90020A03, // 0010 SETMBR R0 K5 R3
|
0x7C100000, // 0010 CALL R4 0
|
||||||
0x8C0C0106, // 0011 GETMET R3 R0 K6
|
0x90020C04, // 0011 SETMBR R0 K6 R4
|
||||||
0x7C0C0200, // 0012 CALL R3 1
|
0x8C100107, // 0012 GETMET R4 R0 K7
|
||||||
0xB80E1000, // 0013 GETNGBL R3 K8
|
0x7C100200, // 0013 CALL R4 1
|
||||||
0x88100103, // 0014 GETMBR R4 R0 K3
|
0x8C100708, // 0014 GETMET R4 R3 K8
|
||||||
0x7C0C0200, // 0015 CALL R3 1
|
0x88180104, // 0015 GETMBR R6 R0 K4
|
||||||
0x90020E03, // 0016 SETMBR R0 K7 R3
|
0x7C100400, // 0016 CALL R4 2
|
||||||
0xB80E1000, // 0017 GETNGBL R3 K8
|
0x90021004, // 0017 SETMBR R0 K8 R4
|
||||||
0x88100103, // 0018 GETMBR R4 R0 K3
|
0x8C100708, // 0018 GETMET R4 R3 K8
|
||||||
0x7C0C0200, // 0019 CALL R3 1
|
0x88180104, // 0019 GETMBR R6 R0 K4
|
||||||
0x90021203, // 001A SETMBR R0 K9 R3
|
0x7C100400, // 001A CALL R4 2
|
||||||
0x840C0000, // 001B CLOSURE R3 P0
|
0x90021204, // 001B SETMBR R0 K9 R4
|
||||||
0x90021403, // 001C SETMBR R0 K10 R3
|
0x84100000, // 001C CLOSURE R4 P0
|
||||||
0x9002170C, // 001D SETMBR R0 K11 K12
|
0x90021404, // 001D SETMBR R0 K10 R4
|
||||||
0xA0000000, // 001E CLOSE R0
|
0x9002170C, // 001E SETMBR R0 K11 K12
|
||||||
0x80000000, // 001F RET 0
|
0xA0000000, // 001F CLOSE R0
|
||||||
|
0x80000000, // 0020 RET 0
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -421,7 +422,7 @@ be_local_closure(Leds_animator_init, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: add_painter
|
** Solidified function: add_painter
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_add_painter, /* name */
|
be_local_closure(Animate_core_add_painter, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
5, /* nstack */
|
5, /* nstack */
|
||||||
2, /* argc */
|
2, /* argc */
|
||||||
@ -452,7 +453,7 @@ be_local_closure(Leds_animator_add_painter, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: fast_loop
|
** Solidified function: fast_loop
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_fast_loop, /* name */
|
be_local_closure(Animate_core_fast_loop, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
12, /* nstack */
|
12, /* nstack */
|
||||||
1, /* argc */
|
1, /* argc */
|
||||||
@ -585,7 +586,7 @@ be_local_closure(Leds_animator_fast_loop, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: start
|
** Solidified function: start
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_animator_start, /* name */
|
be_local_closure(Animate_core_start, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
6, /* nstack */
|
6, /* nstack */
|
||||||
1, /* argc */
|
1, /* argc */
|
||||||
@ -636,49 +637,49 @@ be_local_closure(Leds_animator_start, /* name */
|
|||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified class: Leds_animator
|
** Solidified class: Animate_core
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_class(Leds_animator,
|
be_local_class(Animate_core,
|
||||||
13,
|
13,
|
||||||
NULL,
|
NULL,
|
||||||
be_nested_map(28,
|
be_nested_map(28,
|
||||||
( (struct bmapnode*) &(const bmapnode[]) {
|
( (struct bmapnode*) &(const bmapnode[]) {
|
||||||
{ be_const_key_weak(bri, 23), be_const_var(2) },
|
{ be_const_key_weak(bri, 23), be_const_var(2) },
|
||||||
{ be_const_key_weak(remove, -1), be_const_closure(Leds_animator_remove_closure) },
|
{ be_const_key_weak(remove, -1), be_const_closure(Animate_core_remove_closure) },
|
||||||
{ be_const_key_weak(start, 21), be_const_closure(Leds_animator_start_closure) },
|
{ be_const_key_weak(start, 21), be_const_closure(Animate_core_start_closure) },
|
||||||
{ be_const_key_weak(fast_loop, -1), be_const_closure(Leds_animator_fast_loop_closure) },
|
{ be_const_key_weak(fast_loop, -1), be_const_closure(Animate_core_fast_loop_closure) },
|
||||||
{ be_const_key_weak(add_animator, -1), be_const_closure(Leds_animator_add_animator_closure) },
|
{ be_const_key_weak(add_animator, -1), be_const_closure(Animate_core_add_animator_closure) },
|
||||||
{ be_const_key_weak(FAST_LOOP_MIN, 8), be_const_int(20) },
|
{ be_const_key_weak(FAST_LOOP_MIN, 8), be_const_int(20) },
|
||||||
{ be_const_key_weak(animate, -1), be_const_closure(Leds_animator_animate_closure) },
|
{ be_const_key_weak(animate, -1), be_const_closure(Animate_core_animate_closure) },
|
||||||
{ be_const_key_weak(pixel_count, -1), be_const_var(1) },
|
{ be_const_key_weak(pixel_count, -1), be_const_var(1) },
|
||||||
{ be_const_key_weak(animators, -1), be_const_var(4) },
|
{ be_const_key_weak(animators, -1), be_const_var(4) },
|
||||||
{ be_const_key_weak(back_color, 11), be_const_var(12) },
|
{ be_const_key_weak(back_color, 11), be_const_var(12) },
|
||||||
{ be_const_key_weak(fast_loop_cb, 12), be_const_var(6) },
|
{ be_const_key_weak(fast_loop_cb, 12), be_const_var(6) },
|
||||||
{ be_const_key_weak(frame, -1), be_const_var(10) },
|
{ be_const_key_weak(frame, -1), be_const_var(10) },
|
||||||
{ be_const_key_weak(animate_object, -1), be_const_var(8) },
|
{ be_const_key_weak(animate_object, -1), be_const_var(8) },
|
||||||
{ be_const_key_weak(stop, -1), be_const_closure(Leds_animator_stop_closure) },
|
{ be_const_key_weak(stop, -1), be_const_closure(Animate_core_stop_closure) },
|
||||||
{ be_const_key_weak(init, -1), be_const_closure(Leds_animator_init_closure) },
|
{ be_const_key_weak(init, -1), be_const_closure(Animate_core_init_closure) },
|
||||||
{ be_const_key_weak(set_cb, 13), be_const_closure(Leds_animator_set_cb_closure) },
|
{ be_const_key_weak(set_cb, 13), be_const_closure(Animate_core_set_cb_closure) },
|
||||||
{ be_const_key_weak(running, -1), be_const_var(3) },
|
{ be_const_key_weak(running, -1), be_const_var(3) },
|
||||||
{ be_const_key_weak(strip, 15), be_const_var(0) },
|
{ be_const_key_weak(strip, 15), be_const_var(0) },
|
||||||
{ be_const_key_weak(fast_loop_next, -1), be_const_var(7) },
|
{ be_const_key_weak(fast_loop_next, -1), be_const_var(7) },
|
||||||
{ be_const_key_weak(set_back_color, 14), be_const_closure(Leds_animator_set_back_color_closure) },
|
{ be_const_key_weak(set_back_color, 14), be_const_closure(Animate_core_set_back_color_closure) },
|
||||||
{ be_const_key_weak(add_painter, -1), be_const_closure(Leds_animator_add_painter_closure) },
|
{ be_const_key_weak(add_painter, -1), be_const_closure(Animate_core_add_painter_closure) },
|
||||||
{ be_const_key_weak(set_bri, 24), be_const_closure(Leds_animator_set_bri_closure) },
|
{ be_const_key_weak(set_bri, 24), be_const_closure(Animate_core_set_bri_closure) },
|
||||||
{ be_const_key_weak(layer, 9), be_const_var(11) },
|
{ be_const_key_weak(layer, 9), be_const_var(11) },
|
||||||
{ be_const_key_weak(animate_method, 6), be_const_var(9) },
|
{ be_const_key_weak(animate_method, 6), be_const_var(9) },
|
||||||
{ be_const_key_weak(get_bri, -1), be_const_closure(Leds_animator_get_bri_closure) },
|
{ be_const_key_weak(get_bri, -1), be_const_closure(Animate_core_get_bri_closure) },
|
||||||
{ be_const_key_weak(painters, -1), be_const_var(5) },
|
{ be_const_key_weak(painters, -1), be_const_var(5) },
|
||||||
{ be_const_key_weak(clear, 3), be_const_closure(Leds_animator_clear_closure) },
|
{ be_const_key_weak(clear, 3), be_const_closure(Animate_core_clear_closure) },
|
||||||
{ be_const_key_weak(add_background_animator, 2), be_const_closure(Leds_animator_add_background_animator_closure) },
|
{ be_const_key_weak(add_background_animator, 2), be_const_closure(Animate_core_add_background_animator_closure) },
|
||||||
})),
|
})),
|
||||||
be_str_weak(Leds_animator)
|
be_str_weak(Animate_core)
|
||||||
);
|
);
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
|
|
||||||
void be_load_Leds_animator_class(bvm *vm) {
|
void be_load_Animate_core_class(bvm *vm) {
|
||||||
be_pushntvclass(vm, &be_class_Leds_animator);
|
be_pushntvclass(vm, &be_class_Animate_core);
|
||||||
be_setglobal(vm, "Leds_animator");
|
be_setglobal(vm, "Animate_core");
|
||||||
be_pop(vm, 1);
|
be_pop(vm, 1);
|
||||||
}
|
}
|
||||||
/********************************************************************/
|
/********************************************************************/
|
@ -1,15 +1,42 @@
|
|||||||
/* Solidification of leds_1_animate_effects.h */
|
/* Solidification of animate_1_animate_effects.h */
|
||||||
/********************************************************************\
|
/********************************************************************\
|
||||||
* Generated code, don't edit *
|
* Generated code, don't edit *
|
||||||
\********************************************************************/
|
\********************************************************************/
|
||||||
#include "be_constobj.h"
|
#include "be_constobj.h"
|
||||||
|
|
||||||
extern const bclass be_class_Leds_pulse;
|
extern const bclass be_class_Animate_pulse;
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
** Solidified function: set_pulse_size
|
||||||
|
********************************************************************/
|
||||||
|
be_local_closure(Animate_pulse_set_pulse_size, /* name */
|
||||||
|
be_nested_proto(
|
||||||
|
2, /* nstack */
|
||||||
|
2, /* argc */
|
||||||
|
2, /* varg */
|
||||||
|
0, /* has upvals */
|
||||||
|
NULL, /* no upvals */
|
||||||
|
0, /* has sup protos */
|
||||||
|
NULL, /* no sub protos */
|
||||||
|
1, /* has constants */
|
||||||
|
( &(const bvalue[ 1]) { /* constants */
|
||||||
|
/* K0 */ be_nested_str_weak(pulse_size),
|
||||||
|
}),
|
||||||
|
be_str_weak(set_pulse_size),
|
||||||
|
&be_const_str_solidified,
|
||||||
|
( &(const binstruction[ 2]) { /* code */
|
||||||
|
0x90020001, // 0000 SETMBR R0 K0 R1
|
||||||
|
0x80000000, // 0001 RET 0
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
/*******************************************************************/
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: set_slew_size
|
** Solidified function: set_slew_size
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_pulse_set_slew_size, /* name */
|
be_local_closure(Animate_pulse_set_slew_size, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
2, /* nstack */
|
2, /* nstack */
|
||||||
2, /* argc */
|
2, /* argc */
|
||||||
@ -36,7 +63,7 @@ be_local_closure(Leds_pulse_set_slew_size, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: set_back_color
|
** Solidified function: set_back_color
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_pulse_set_back_color, /* name */
|
be_local_closure(Animate_pulse_set_back_color, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
2, /* nstack */
|
2, /* nstack */
|
||||||
2, /* argc */
|
2, /* argc */
|
||||||
@ -61,9 +88,9 @@ be_local_closure(Leds_pulse_set_back_color, /* name */
|
|||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: set_index
|
** Solidified function: set_pos
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_pulse_set_index, /* name */
|
be_local_closure(Animate_pulse_set_pos, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
2, /* nstack */
|
2, /* nstack */
|
||||||
2, /* argc */
|
2, /* argc */
|
||||||
@ -74,9 +101,9 @@ be_local_closure(Leds_pulse_set_index, /* name */
|
|||||||
NULL, /* no sub protos */
|
NULL, /* no sub protos */
|
||||||
1, /* has constants */
|
1, /* has constants */
|
||||||
( &(const bvalue[ 1]) { /* constants */
|
( &(const bvalue[ 1]) { /* constants */
|
||||||
/* K0 */ be_nested_str_weak(index),
|
/* K0 */ be_nested_str_weak(pos),
|
||||||
}),
|
}),
|
||||||
be_str_weak(set_index),
|
be_str_weak(set_pos),
|
||||||
&be_const_str_solidified,
|
&be_const_str_solidified,
|
||||||
( &(const binstruction[ 2]) { /* code */
|
( &(const binstruction[ 2]) { /* code */
|
||||||
0x90020001, // 0000 SETMBR R0 K0 R1
|
0x90020001, // 0000 SETMBR R0 K0 R1
|
||||||
@ -88,9 +115,9 @@ be_local_closure(Leds_pulse_set_index, /* name */
|
|||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: set_pulse_size
|
** Solidified function: set_color
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_pulse_set_pulse_size, /* name */
|
be_local_closure(Animate_pulse_set_color, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
2, /* nstack */
|
2, /* nstack */
|
||||||
2, /* argc */
|
2, /* argc */
|
||||||
@ -101,9 +128,9 @@ be_local_closure(Leds_pulse_set_pulse_size, /* name */
|
|||||||
NULL, /* no sub protos */
|
NULL, /* no sub protos */
|
||||||
1, /* has constants */
|
1, /* has constants */
|
||||||
( &(const bvalue[ 1]) { /* constants */
|
( &(const bvalue[ 1]) { /* constants */
|
||||||
/* K0 */ be_nested_str_weak(pulse_size),
|
/* K0 */ be_nested_str_weak(color),
|
||||||
}),
|
}),
|
||||||
be_str_weak(set_pulse_size),
|
be_str_weak(set_color),
|
||||||
&be_const_str_solidified,
|
&be_const_str_solidified,
|
||||||
( &(const binstruction[ 2]) { /* code */
|
( &(const binstruction[ 2]) { /* code */
|
||||||
0x90020001, // 0000 SETMBR R0 K0 R1
|
0x90020001, // 0000 SETMBR R0 K0 R1
|
||||||
@ -117,7 +144,7 @@ be_local_closure(Leds_pulse_set_pulse_size, /* name */
|
|||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: init
|
** Solidified function: init
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_pulse_init, /* name */
|
be_local_closure(Animate_pulse_init, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
5, /* nstack */
|
5, /* nstack */
|
||||||
4, /* argc */
|
4, /* argc */
|
||||||
@ -169,37 +196,10 @@ be_local_closure(Leds_pulse_init, /* name */
|
|||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
** Solidified function: set_color
|
|
||||||
********************************************************************/
|
|
||||||
be_local_closure(Leds_pulse_set_color, /* name */
|
|
||||||
be_nested_proto(
|
|
||||||
2, /* nstack */
|
|
||||||
2, /* argc */
|
|
||||||
2, /* varg */
|
|
||||||
0, /* has upvals */
|
|
||||||
NULL, /* no upvals */
|
|
||||||
0, /* has sup protos */
|
|
||||||
NULL, /* no sub protos */
|
|
||||||
1, /* has constants */
|
|
||||||
( &(const bvalue[ 1]) { /* constants */
|
|
||||||
/* K0 */ be_nested_str_weak(color),
|
|
||||||
}),
|
|
||||||
be_str_weak(set_color),
|
|
||||||
&be_const_str_solidified,
|
|
||||||
( &(const binstruction[ 2]) { /* code */
|
|
||||||
0x90020001, // 0000 SETMBR R0 K0 R1
|
|
||||||
0x80000000, // 0001 RET 0
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
/*******************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified function: paint
|
** Solidified function: paint
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_closure(Leds_pulse_paint, /* name */
|
be_local_closure(Animate_pulse_paint, /* name */
|
||||||
be_nested_proto(
|
be_nested_proto(
|
||||||
22, /* nstack */
|
22, /* nstack */
|
||||||
2, /* argc */
|
2, /* argc */
|
||||||
@ -213,7 +213,7 @@ be_local_closure(Leds_pulse_paint, /* name */
|
|||||||
/* K0 */ be_nested_str_weak(back_color),
|
/* K0 */ be_nested_str_weak(back_color),
|
||||||
/* K1 */ be_const_int(-16777216),
|
/* K1 */ be_const_int(-16777216),
|
||||||
/* K2 */ be_nested_str_weak(fill_pixels),
|
/* K2 */ be_nested_str_weak(fill_pixels),
|
||||||
/* K3 */ be_nested_str_weak(index),
|
/* K3 */ be_nested_str_weak(pos),
|
||||||
/* K4 */ be_nested_str_weak(slew_size),
|
/* K4 */ be_nested_str_weak(slew_size),
|
||||||
/* K5 */ be_nested_str_weak(pulse_size),
|
/* K5 */ be_nested_str_weak(pulse_size),
|
||||||
/* K6 */ be_nested_str_weak(color),
|
/* K6 */ be_nested_str_weak(color),
|
||||||
@ -325,33 +325,33 @@ be_local_closure(Leds_pulse_paint, /* name */
|
|||||||
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
** Solidified class: Leds_pulse
|
** Solidified class: Animate_pulse
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
be_local_class(Leds_pulse,
|
be_local_class(Animate_pulse,
|
||||||
5,
|
5,
|
||||||
NULL,
|
NULL,
|
||||||
be_nested_map(12,
|
be_nested_map(12,
|
||||||
( (struct bmapnode*) &(const bmapnode[]) {
|
( (struct bmapnode*) &(const bmapnode[]) {
|
||||||
{ be_const_key_weak(paint, 9), be_const_closure(Leds_pulse_paint_closure) },
|
{ be_const_key_weak(paint, -1), be_const_closure(Animate_pulse_paint_closure) },
|
||||||
{ be_const_key_weak(set_slew_size, -1), be_const_closure(Leds_pulse_set_slew_size_closure) },
|
{ be_const_key_weak(set_slew_size, -1), be_const_closure(Animate_pulse_set_slew_size_closure) },
|
||||||
{ be_const_key_weak(pulse_size, -1), be_const_var(4) },
|
{ be_const_key_weak(pulse_size, -1), be_const_var(4) },
|
||||||
{ be_const_key_weak(set_back_color, 6), be_const_closure(Leds_pulse_set_back_color_closure) },
|
{ be_const_key_weak(set_back_color, 8), be_const_closure(Animate_pulse_set_back_color_closure) },
|
||||||
{ be_const_key_weak(set_index, 7), be_const_closure(Leds_pulse_set_index_closure) },
|
|
||||||
{ be_const_key_weak(back_color, -1), be_const_var(1) },
|
|
||||||
{ be_const_key_weak(set_color, 8), be_const_closure(Leds_pulse_set_color_closure) },
|
|
||||||
{ be_const_key_weak(color, -1), be_const_var(0) },
|
{ be_const_key_weak(color, -1), be_const_var(0) },
|
||||||
{ be_const_key_weak(init, -1), be_const_closure(Leds_pulse_init_closure) },
|
{ be_const_key_weak(back_color, -1), be_const_var(1) },
|
||||||
{ be_const_key_weak(set_pulse_size, -1), be_const_closure(Leds_pulse_set_pulse_size_closure) },
|
{ be_const_key_weak(set_pos, -1), be_const_closure(Animate_pulse_set_pos_closure) },
|
||||||
|
{ be_const_key_weak(set_color, -1), be_const_closure(Animate_pulse_set_color_closure) },
|
||||||
|
{ be_const_key_weak(init, 7), be_const_closure(Animate_pulse_init_closure) },
|
||||||
|
{ be_const_key_weak(pos, -1), be_const_var(2) },
|
||||||
{ be_const_key_weak(slew_size, 5), be_const_var(3) },
|
{ be_const_key_weak(slew_size, 5), be_const_var(3) },
|
||||||
{ be_const_key_weak(index, 0), be_const_var(2) },
|
{ be_const_key_weak(set_pulse_size, 0), be_const_closure(Animate_pulse_set_pulse_size_closure) },
|
||||||
})),
|
})),
|
||||||
be_str_weak(Leds_pulse)
|
be_str_weak(Animate_pulse)
|
||||||
);
|
);
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
|
|
||||||
void be_load_Leds_pulse_class(bvm *vm) {
|
void be_load_Animate_pulse_class(bvm *vm) {
|
||||||
be_pushntvclass(vm, &be_class_Leds_pulse);
|
be_pushntvclass(vm, &be_class_Animate_pulse);
|
||||||
be_setglobal(vm, "Leds_pulse");
|
be_setglobal(vm, "Animate_pulse");
|
||||||
be_pop(vm, 1);
|
be_pop(vm, 1);
|
||||||
}
|
}
|
||||||
/********************************************************************/
|
/********************************************************************/
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
|||||||
|
#
|
||||||
|
# Example for M5Stack Led Matrix
|
||||||
|
# 5 x 5 WS2812
|
||||||
|
#
|
||||||
|
import animate
|
||||||
|
|
||||||
|
var duration = 10000
|
||||||
|
var strip = Leds(5 * 5, gpio.pin(gpio.WS2812, 0))
|
||||||
|
var anim = animate(strip)
|
||||||
|
anim.add_background_animator(animate.palette(animate.PALETTE_RAINBOW_WHITE, duration))
|
||||||
|
anim.start()
|
23
tasmota/berry/animate_demo/animate_demo_pulse.be
Normal file
23
tasmota/berry/animate_demo/animate_demo_pulse.be
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#
|
||||||
|
# Example for M5Stack Led Matrix
|
||||||
|
# 5 x 5 WS2812
|
||||||
|
#
|
||||||
|
import animate
|
||||||
|
|
||||||
|
var duration = 10000
|
||||||
|
var strip = Leds(5 * 5, gpio.pin(gpio.WS2812, 0))
|
||||||
|
var anim = animate(strip)
|
||||||
|
anim.set_back_color(0x2222AA)
|
||||||
|
var pulse = animate.pulse(0xFF4444, 2, 1)
|
||||||
|
var osc1 = animate.oscillator(-3, 26, 5000, animate.COSINE)
|
||||||
|
osc1.set_cb(pulse, pulse.set_pos)
|
||||||
|
|
||||||
|
anim.add_animator(osc1)
|
||||||
|
anim.add_painter(pulse)
|
||||||
|
|
||||||
|
# animate color of pulse
|
||||||
|
var palette = animate.palette(animate.PALETTE_RAINBOW_WHITE, 30000)
|
||||||
|
palette.set_cb(pulse, pulse.set_color)
|
||||||
|
anim.add_animator(palette)
|
||||||
|
|
||||||
|
anim.start()
|
173
tasmota/berry/animate_demo/leds_animation.be
Normal file
173
tasmota/berry/animate_demo/leds_animation.be
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
#################################################################################
|
||||||
|
# Web UI for Leds animation
|
||||||
|
#
|
||||||
|
#################################################################################
|
||||||
|
|
||||||
|
var leds_animation = module('leds_animation')
|
||||||
|
|
||||||
|
#################################################################################
|
||||||
|
# Leds_animation_UI
|
||||||
|
#
|
||||||
|
# WebUI for the Leds animation
|
||||||
|
#################################################################################
|
||||||
|
class Leds_animation_UI
|
||||||
|
|
||||||
|
def init()
|
||||||
|
tasmota.add_driver(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
# create a method for adding a button to the main menu
|
||||||
|
# the button 'Leds animation' redirects to '/leds_anim?'
|
||||||
|
def web_add_button()
|
||||||
|
import webserver
|
||||||
|
webserver.content_send(
|
||||||
|
"<form id=but_part_mgr style='display: block;' action='leds_anim' method='get'><button>Leds animation</button></form><p></p>")
|
||||||
|
end
|
||||||
|
|
||||||
|
#- ---------------------------------------------------------------------- -#
|
||||||
|
#- Show page to migrate to factory layout + single OTA
|
||||||
|
#- ---------------------------------------------------------------------- -#
|
||||||
|
def show_migrate_to_factory(p)
|
||||||
|
# display ota partitions
|
||||||
|
import webserver
|
||||||
|
import string
|
||||||
|
|
||||||
|
if !self.factory_migrate_eligible(p) return end
|
||||||
|
|
||||||
|
webserver.content_send("<fieldset><legend><b> Migrate to safeboot partition layout </b></legend><p></p>")
|
||||||
|
|
||||||
|
webserver.content_send("<p>The `safeboot` layout allows for increased size<br>of firmware or file-system.</p>")
|
||||||
|
webserver.content_send("<p>Please see <a href='https://tasmota.github.io/docs/Safeboot/' target='_blank'>Safeboot layout documentation</a></p>")
|
||||||
|
webserver.content_send("<p> </p>")
|
||||||
|
|
||||||
|
webserver.content_send(string.format("<p>Step 1: %s</p>", self.display_step_state(self.test_step_1(p), "boot on `app1`")))
|
||||||
|
webserver.content_send(string.format("<p>Step 2: %s</p>", self.display_step_state(self.test_step_2(p), "flash `safeboot` to `app0`")))
|
||||||
|
webserver.content_send(string.format("<p>Step 3: %s</p>", self.display_step_state(self.test_step_3(p), "change partition map")))
|
||||||
|
webserver.content_send(string.format("<p>Step 4: %s</p>", self.display_step_state(self.test_step_4(p), "flash final firmware")))
|
||||||
|
|
||||||
|
webserver.content_send("<form action='/part_wiz' method='post' ")
|
||||||
|
webserver.content_send("onsubmit='return confirm(\"This will causes multiple restarts.\");'>")
|
||||||
|
var ota_url = tasmota.cmd("OtaUrl").find("OtaUrl", "")
|
||||||
|
webserver.content_send(string.format("<br><b>OTA Url</b><br><input id='o1' placeholder='OTA_URL' value='%s'><br>",
|
||||||
|
ota_url))
|
||||||
|
|
||||||
|
import persist
|
||||||
|
var safeboot_url = persist.find("safeboot_url", self.default_safeboot_URL())
|
||||||
|
webserver.content_send(string.format("<br><b>SAFEBOOT Url</b> (don't change)<input id='o2' placeholder='SAFEBOOT_URL' value='%s'><br>",
|
||||||
|
safeboot_url))
|
||||||
|
|
||||||
|
webserver.content_send("<p></p><button name='factory' class='button bred'>Start migration</button></form></p>")
|
||||||
|
|
||||||
|
webserver.content_send("<p></p></fieldset><p></p>")
|
||||||
|
end
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Show background colors
|
||||||
|
#######################################################################
|
||||||
|
def show_background_color()
|
||||||
|
import webserver
|
||||||
|
var back_color = 0xFF8800
|
||||||
|
var back_anim_time = 5.0
|
||||||
|
|
||||||
|
|
||||||
|
webserver.content_send("<fieldset><legend><b> Background </b></legend>"
|
||||||
|
"<form action='/leds_anim' method='post'>")
|
||||||
|
|
||||||
|
# webserver.content_send(f"<input type='color' min='1' max='256' name='leds_back' value='#{back_color:06X}'>")
|
||||||
|
# webserver.content_send("<hr>")
|
||||||
|
webserver.content_send("<label>Animation time (sec)</label>")
|
||||||
|
webserver.content_send(f"<input type='number' min='1' max='256' name='leds_size' value='{back_anim_time:.1f}'>")
|
||||||
|
webserver.content_send("<p></p>")
|
||||||
|
|
||||||
|
webserver.content_send("<label>Background color (static)</label>")
|
||||||
|
webserver.content_send("<table style='width:100%;background:white;'>")
|
||||||
|
webserver.content_send(f"<tr>"
|
||||||
|
"<td width='33%' style='color:#222;'><input type='radio' name='static' checked />Static</td>"
|
||||||
|
"<td width='67%'><input type='color' min='1' max='256' name='leds_back' value='#{back_color:06X}'></td>"
|
||||||
|
"</tr>")
|
||||||
|
webserver.content_send("<tr>"
|
||||||
|
"<td width='33%' style='color:#222;'><input type='radio' name='static' />Palette1</td>"
|
||||||
|
"<td width='67%' style='background:linear-gradient(to right,#FF0000 0.0%,#FFA500 14.3%,#FFFF00 28.6%,#00EE00 42.9%,#0000FF 57.1%,#4B00FF 71.4%,#FF82FF 85.7%,#FF0000 100.0%);'></td>"
|
||||||
|
"</tr>")
|
||||||
|
webserver.content_send("<tr>"
|
||||||
|
"<td width='33%' style='color:#222;'><input type='radio' name='static' />Palette1</td>"
|
||||||
|
"<td width='67%' style='background:linear-gradient(to right,#FF0000 0.0%,#FF0000 8.9%,#FFA500 14.3%,#FFA500 23.2%,#FFFF00 28.6%,#FFFF00 37.5%,#00FF00 42.9%,#00FF00 51.8%,#0000FF 57.1%,#0000FF 66.1%,#FF00FF 71.4%,#FF00FF 80.4%,#FFFFFF 85.7%,#FFFFFF 94.6%,#FF0000 100.0%);'></td>"
|
||||||
|
"</tr>")
|
||||||
|
webserver.content_send("<tr>"
|
||||||
|
"<td width='33%' style='color:#222;'><input type='radio' name='static' />Palette1</td>"
|
||||||
|
"<td width='67%' style='background:linear-gradient(to right,#E60611 0.0%,#B66022 36.9%,#A0402A 52.2%,#88030D 100.0%);'></td>"
|
||||||
|
"</tr>")
|
||||||
|
webserver.content_send("</table>")
|
||||||
|
webserver.content_send("<p></p><button name='save' class='button bgrn'>Save</button></form></p>"
|
||||||
|
"</fieldset><p></p>")
|
||||||
|
end
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Show main config
|
||||||
|
#######################################################################
|
||||||
|
def show_main_config()
|
||||||
|
import webserver
|
||||||
|
var leds_anim_enabled = true
|
||||||
|
var leds_size = 25
|
||||||
|
|
||||||
|
webserver.content_send("<fieldset><legend><b> Leds configuration </b></legend>"
|
||||||
|
"<p style='width:320px;'>Check the <a href='https://tasmota.github.io/docs/Leds_animation/' target='_blank'>Leds animation documentation</a>.</p>"
|
||||||
|
"<form action='/leds_anim' method='post'>")
|
||||||
|
|
||||||
|
# checkbox for Matter enable
|
||||||
|
var leds_anim_enabled_checked = leds_anim_enabled ? 'checked' : ''
|
||||||
|
webserver.content_send(f"<p><input id='menable' type='checkbox' name='menable' {leds_anim_enabled_checked}>")
|
||||||
|
webserver.content_send("<label for='menable'><b>Leds anim enabled</b></label></p>")
|
||||||
|
|
||||||
|
webserver.content_send("<label>Number of leds</label>")
|
||||||
|
webserver.content_send(f"<input type='number' min='1' max='256' name='leds_size' value='{leds_size:i}'>")
|
||||||
|
|
||||||
|
webserver.content_send("<p></p><button name='save' class='button bgrn'>Save</button></form></p>"
|
||||||
|
"</fieldset><p></p>")
|
||||||
|
end
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Display the complete page
|
||||||
|
#######################################################################
|
||||||
|
def page_view()
|
||||||
|
import webserver
|
||||||
|
if !webserver.check_privileged_access() return nil end
|
||||||
|
|
||||||
|
webserver.content_start("Leds animation") #- title of the web page -#
|
||||||
|
webserver.content_send_style() #- send standard Tasmota styles -#
|
||||||
|
|
||||||
|
self.show_main_config()
|
||||||
|
self.show_background_color()
|
||||||
|
webserver.content_button(webserver.BUTTON_MANAGEMENT) #- button back to management page -#
|
||||||
|
|
||||||
|
webserver.content_stop() #- end of web page -#
|
||||||
|
end
|
||||||
|
|
||||||
|
#- ---------------------------------------------------------------------- -#
|
||||||
|
# respond to web_add_handler() event to register web listeners
|
||||||
|
#- ---------------------------------------------------------------------- -#
|
||||||
|
#- this is called at Tasmota start-up, as soon as Wifi/Eth is up and web server running -#
|
||||||
|
def web_add_handler()
|
||||||
|
import webserver
|
||||||
|
#- we need to register a closure, not just a function, that captures the current instance -#
|
||||||
|
webserver.on("/leds_anim", / -> self.page_view(), webserver.HTTP_GET)
|
||||||
|
webserver.on("/leds_anim", / -> self.page_ctl(), webserver.HTTP_POST)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
leds_animation.Leds_animation_UI = Leds_animation_UI
|
||||||
|
|
||||||
|
|
||||||
|
#- create and register driver in Tasmota -#
|
||||||
|
if tasmota
|
||||||
|
var ui = leds_animation.Leds_animation_UI()
|
||||||
|
## can be removed if put in 'autoexec.bat'
|
||||||
|
ui.web_add_handler()
|
||||||
|
end
|
||||||
|
|
||||||
|
return leds_animation
|
||||||
|
|
||||||
|
#- Example
|
||||||
|
|
||||||
|
import leds_animation
|
||||||
|
|
||||||
|
-#
|
37
tasmota/berry/animate_demo/leds_blend_demo.be
Normal file
37
tasmota/berry/animate_demo/leds_blend_demo.be
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# test blending
|
||||||
|
|
||||||
|
import animate
|
||||||
|
|
||||||
|
var LEDS_LENGTH = 25
|
||||||
|
var strip
|
||||||
|
var front, back
|
||||||
|
var bri
|
||||||
|
|
||||||
|
strip = Leds(LEDS_LENGTH, gpio.pin(gpio.WS2812,0))
|
||||||
|
bri = 70
|
||||||
|
|
||||||
|
back = bytes().resize(LEDS_LENGTH * 4)
|
||||||
|
front = bytes().resize(LEDS_LENGTH * 4)
|
||||||
|
strip.clear_to(0x442211)
|
||||||
|
strip.show()
|
||||||
|
|
||||||
|
var back = animate.frame(LEDS_LENGTH)
|
||||||
|
var front = animate.frame(LEDS_LENGTH)
|
||||||
|
back.fill_pixels(0xFF2200, 80)
|
||||||
|
for i:0..24
|
||||||
|
front.set_pixel(i, 0, 255, 0, (i*255)/24)
|
||||||
|
end
|
||||||
|
back.blend_pixels(back, front)
|
||||||
|
|
||||||
|
print("front=", front.tohex())
|
||||||
|
print("back =", back.tohex())
|
||||||
|
var pixels_buffer = strip.pixels_buffer()
|
||||||
|
print("pixs =", pixels_buffer.tohex())
|
||||||
|
back.paste_pixels(pixels_buffer, bri, true)
|
||||||
|
strip.dirty()
|
||||||
|
strip.show()
|
||||||
|
|
||||||
|
## Output:
|
||||||
|
# front= 00FF000000FF000A00FF001500FF001F00FF002A00FF003500FF003F00FF004A00FF005500FF005F00FF006A00FF007400FF007F00FF008A00FF009400FF009F00FF00AA00FF00B400FF00BF00FF00C900FF00D400FF00DF00FF00E900FF00F400FF00FF
|
||||||
|
# back = 0022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF000022FF00
|
||||||
|
# pixs = 020701020701020701020701020701020701020701020701020701020701020701020701020701020701020701020701020701020701020701020701020701020701020701020701020701
|
42
tasmota/berry/emulator/Leds_frame.be
Normal file
42
tasmota/berry/emulator/Leds_frame.be
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# Leds_frame
|
||||||
|
|
||||||
|
class Leds_frame
|
||||||
|
var pixel_size
|
||||||
|
|
||||||
|
def init()
|
||||||
|
end
|
||||||
|
|
||||||
|
def blend(color_a, color_b, alpha)
|
||||||
|
var r = (color_a >> 16) & 0xFF
|
||||||
|
var g = (color_a >> 8) & 0xFF
|
||||||
|
var b = (color_a ) & 0xFF
|
||||||
|
var r2 = (color_b >> 16) & 0xFF
|
||||||
|
var g2 = (color_b >> 8) & 0xFF
|
||||||
|
var b2 = (color_b ) & 0xFF
|
||||||
|
var r3 = tasmota.scale_uint(alpha, 0, 255, r2, r)
|
||||||
|
var g3 = tasmota.scale_uint(alpha, 0, 255, g2, g)
|
||||||
|
var b3 = tasmota.scale_uint(alpha, 0, 255, b2, b)
|
||||||
|
var rgb = (r3 << 16) | (g3 << 8) | b3
|
||||||
|
return rgb
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return Leds_frame
|
||||||
|
|
||||||
|
# /* @const_object_info_begin
|
||||||
|
# class be_class_Leds_frame (scope: global, name: Leds_frame, super:be_class_bytes, strings: weak) {
|
||||||
|
# pixel_size, var
|
||||||
|
|
||||||
|
# init, closure(Leds_frame_be_init_closure)
|
||||||
|
|
||||||
|
# item, closure(Leds_frame_be_item_closure)
|
||||||
|
# setitem, closure(Leds_frame_be_setitem_closure)
|
||||||
|
# set_pixel, closure(Leds_frame_be_set_pixel_closure)
|
||||||
|
|
||||||
|
# // the following are on buffers
|
||||||
|
# blend, static_func(be_leds_blend)
|
||||||
|
# fill_pixels, func(be_leds_fill_pixels)
|
||||||
|
# blend_pixels, func(be_leds_blend_pixels)
|
||||||
|
# paste_pixels, func(be_leds_paste_pixels)
|
||||||
|
# }
|
@ -1,51 +0,0 @@
|
|||||||
#
|
|
||||||
# Example for M5Stack Led Matrix
|
|
||||||
# 5 x 5 WS2812
|
|
||||||
#
|
|
||||||
import animate
|
|
||||||
class Background_demo : Leds_animator
|
|
||||||
static var PALETTE_STANDARD_TAG = bytes(
|
|
||||||
"40" "FF0000" # red
|
|
||||||
"40" "FFA500" # orange
|
|
||||||
"40" "FFFF00" # yellow
|
|
||||||
"40" "00EE00" # green
|
|
||||||
"40" "0000FF" # blue
|
|
||||||
"40" "4B00FF" # indigo
|
|
||||||
"40" "FF82FF" # violet
|
|
||||||
"00" "FF0000" # red
|
|
||||||
)
|
|
||||||
|
|
||||||
static var PALETTE_RAINBOW_WHITE = bytes(
|
|
||||||
"50" "FF0000" # red
|
|
||||||
"30" "FF0000" # red
|
|
||||||
"50" "FFA500" # orange
|
|
||||||
"30" "FFA500" # orange
|
|
||||||
"50" "FFFF00" # yellow
|
|
||||||
"30" "FFFF00" # yellow
|
|
||||||
"50" "00FF00" # green
|
|
||||||
"30" "00FF00" # green
|
|
||||||
"50" "0000FF" # blue
|
|
||||||
"30" "0000FF" # blue
|
|
||||||
"50" "FF00FF" # indigo
|
|
||||||
"30" "FF00FF" # indigo
|
|
||||||
"50" "FFFFFF" # white
|
|
||||||
"30" "FFFFFF" # white
|
|
||||||
"00" "FF0000" # red
|
|
||||||
)
|
|
||||||
|
|
||||||
# duration in seconds
|
|
||||||
def init(strip, duration)
|
|
||||||
import animate
|
|
||||||
super(self).init(strip)
|
|
||||||
# var pal = animate.palette(self.PALETTE_STANDARD_TAG, duration)
|
|
||||||
var pal = animate.palette(self.PALETTE_RAINBOW_WHITE, duration)
|
|
||||||
self.add_background_animator(pal)
|
|
||||||
end
|
|
||||||
|
|
||||||
def animate()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
var strip = Leds(5 * 5, gpio.pin(gpio.WS2812, 0))
|
|
||||||
var r = Background_demo(strip, 20)
|
|
||||||
r.start()
|
|
@ -1,185 +0,0 @@
|
|||||||
# simple Rainbow animator
|
|
||||||
|
|
||||||
#-
|
|
||||||
# Ex: if WS2812 configured to WS2812 - channel 2
|
|
||||||
|
|
||||||
var strip = neopixelbus(25, gpio.pin(gpio.WS2812, 1))
|
|
||||||
rainbow = Rainbow(strip)
|
|
||||||
rainbow.start()
|
|
||||||
|
|
||||||
-#
|
|
||||||
|
|
||||||
import animate
|
|
||||||
|
|
||||||
class Rainbow : Leds_animator
|
|
||||||
var cur_offset # current offset in the palette
|
|
||||||
static palette = [ 0xFF0000, #- red -#
|
|
||||||
0xFFA500, #- orange -#
|
|
||||||
0xFFFF00, #- yellow -#
|
|
||||||
0x008800, #- green -#
|
|
||||||
0x0000FF, #- blue -#
|
|
||||||
0x4B0082, #- indigo -#
|
|
||||||
0xEE82EE, #- violet -#
|
|
||||||
]
|
|
||||||
|
|
||||||
def init(strip, duration)
|
|
||||||
import animate
|
|
||||||
super(self).init(strip)
|
|
||||||
self.cur_offset = 0
|
|
||||||
# add an animator to change `self.cur_offset` to each value of the palette
|
|
||||||
self.add_anim(animate.rotate(def(v) self.cur_offset = v end, 0, size(self.palette), int(duration * 1000)))
|
|
||||||
end
|
|
||||||
|
|
||||||
def animate()
|
|
||||||
# move instance variables to registers to avoid GETMBR inside the loop
|
|
||||||
var cur_offset = self.cur_offset
|
|
||||||
var modulus = size(self.palette)
|
|
||||||
var palette = self.palette
|
|
||||||
var strip = self.strip
|
|
||||||
var bri = self.bri
|
|
||||||
var set_pixel_color = strip.set_pixel_color
|
|
||||||
|
|
||||||
var i = 0
|
|
||||||
while i < self.pixel_count # doing a loop rather than a `for` prevents from allocating a new object
|
|
||||||
var col = palette[(cur_offset + i) % modulus]
|
|
||||||
set_pixel_color(strip, i, col, bri) # simulate the method call without GETMET
|
|
||||||
i += 1
|
|
||||||
end
|
|
||||||
strip.show()
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
#-
|
|
||||||
|
|
||||||
var strip = Leds.matrix(5,5, gpio.pin(gpio.WS2812, 1))
|
|
||||||
var r = Rainbow(strip, 1.0)
|
|
||||||
r.start()
|
|
||||||
|
|
||||||
-#
|
|
||||||
|
|
||||||
class Rainbow_stripes : Leds_animator
|
|
||||||
var cur_offset # current offset in the palette
|
|
||||||
static palette = [ 0xFF0000, #- red -#
|
|
||||||
0xFFA500, #- orange -#
|
|
||||||
0xFFFF00, #- yellow -#
|
|
||||||
0x008800, #- green -#
|
|
||||||
0x0000FF, #- blue -#
|
|
||||||
0x4B0082, #- indigo -#
|
|
||||||
0xEE82EE, #- violet -#
|
|
||||||
]
|
|
||||||
|
|
||||||
def init(strip, duration)
|
|
||||||
import animate
|
|
||||||
super(self).init(strip)
|
|
||||||
self.cur_offset = 0
|
|
||||||
# add an animator to change `self.cur_offset` to each value of the palette
|
|
||||||
self.add_anim(animate.rotate(def(v) self.cur_offset = v end, 0, size(self.palette), int(duration * 1000)))
|
|
||||||
end
|
|
||||||
|
|
||||||
def animate()
|
|
||||||
# move instance variables to registers to avoid GETMBR inside the loop
|
|
||||||
var cur_offset = self.cur_offset
|
|
||||||
var modulus = size(self.palette)
|
|
||||||
var palette = self.palette
|
|
||||||
var strip = self.strip
|
|
||||||
var bri = self.bri
|
|
||||||
var set_matrix_pixel_color = strip.set_matrix_pixel_color
|
|
||||||
var h = self.strip.h
|
|
||||||
var w = self.strip.w
|
|
||||||
|
|
||||||
var y = 0
|
|
||||||
while y < h
|
|
||||||
var x = 0
|
|
||||||
var col = palette[(cur_offset + y) % modulus]
|
|
||||||
while x < w
|
|
||||||
set_matrix_pixel_color(strip, x, y, col, bri) # simulate the method call without GETMET
|
|
||||||
x += 1
|
|
||||||
end
|
|
||||||
y += 1
|
|
||||||
end
|
|
||||||
strip.show()
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
#-
|
|
||||||
|
|
||||||
var strip = Leds.matrix(5,5, gpio.pin(gpio.WS2812, 1))
|
|
||||||
var r = Rainbow_stripes(strip, 0.5)
|
|
||||||
r.start()
|
|
||||||
|
|
||||||
-#
|
|
||||||
|
|
||||||
class Round : Leds_animator
|
|
||||||
var cur_val
|
|
||||||
var min_val, max_val
|
|
||||||
var incr_val
|
|
||||||
var h
|
|
||||||
|
|
||||||
def init(strip, glow_duration, color_duration)
|
|
||||||
import animate
|
|
||||||
super(self).init(strip)
|
|
||||||
self.cur_val = 5 << 8
|
|
||||||
self.h = 0 # start with hue = 0 (red)
|
|
||||||
# add animator for color over 30 colors
|
|
||||||
self.add_anim(animate.rotate(def(h) self.h = h end, 0, 359, int(color_duration * 1000)))
|
|
||||||
self.add_anim(animate.back_forth(def(v) self.cur_val = v end, 2 << 8, 6 << 8, int(glow_duration * 1000)))
|
|
||||||
end
|
|
||||||
|
|
||||||
def animate()
|
|
||||||
# move instance variables to registers to avoid GETMBR inside the loop
|
|
||||||
var strip = self.strip
|
|
||||||
var bri = self.bri
|
|
||||||
var set_matrix_pixel_color = strip.set_matrix_pixel_color
|
|
||||||
var h = self.strip.h
|
|
||||||
var w = self.strip.w
|
|
||||||
var ch = h / 2
|
|
||||||
var cw = w / 2
|
|
||||||
var col_ref = tasmota.hs2rgb(self.h)
|
|
||||||
|
|
||||||
var y = 0
|
|
||||||
while y < h
|
|
||||||
var x = 0
|
|
||||||
while x < w
|
|
||||||
var col = col_ref
|
|
||||||
var dist = self.fast_sqrt_int( ((y - ch)*(y - ch) + (x - cw)*(x - cw)) << 16)
|
|
||||||
var rel_bri = tasmota.scale_uint(dist, 0, self.cur_val, bri, 0)
|
|
||||||
set_matrix_pixel_color(strip, x, y, col, rel_bri) # simulate the method call without GETMET
|
|
||||||
x += 1
|
|
||||||
end
|
|
||||||
y += 1
|
|
||||||
end
|
|
||||||
strip.show()
|
|
||||||
end
|
|
||||||
|
|
||||||
# https://stackoverflow.com/questions/34187171/fast-integer-square-root-approximation
|
|
||||||
static def fast_sqrt_int(val)
|
|
||||||
var a, b
|
|
||||||
|
|
||||||
if val < 2 return val end
|
|
||||||
|
|
||||||
a = 1255 # starting point is relatively unimportant
|
|
||||||
|
|
||||||
b = val / a; a = (a+b) /2;
|
|
||||||
b = val / a; a = (a+b) /2;
|
|
||||||
b = val / a; a = (a+b) /2;
|
|
||||||
b = val / a; a = (a+b) /2;
|
|
||||||
b = val / a; a = (a+b) /2;
|
|
||||||
b = val / a; a = (a+b) /2;
|
|
||||||
if (val < 20000)
|
|
||||||
b = val / a; a = (a+b) /2;
|
|
||||||
b = val / a; a = (a+b) /2;
|
|
||||||
end
|
|
||||||
|
|
||||||
return a
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#-
|
|
||||||
|
|
||||||
var strip = Leds.matrix(5,5, gpio.pin(gpio.WS2812, 1))
|
|
||||||
var r = Round(strip, 2, 30)
|
|
||||||
r.start()
|
|
||||||
|
|
||||||
-#
|
|
@ -427,6 +427,61 @@ extern "C" {
|
|||||||
be_raise(vm, kTypeError, nullptr);
|
be_raise(vm, kTypeError, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Implements the 5-order polynomial approximation to sin(x).
|
||||||
|
@param i angle (with 2^15 units/circle)
|
||||||
|
@return 16 bit fixed point Sine value (4.12) (ie: +4096 = +1 & -4096 = -1)
|
||||||
|
|
||||||
|
The result is accurate to within +- 1 count. ie: +/-2.44e-4.
|
||||||
|
*/
|
||||||
|
int16_t fpsin(int16_t i)
|
||||||
|
{
|
||||||
|
/* Convert (signed) input to a value between 0 and 8192. (8192 is pi/2, which is the region of the curve fit). */
|
||||||
|
/* ------------------------------------------------------------------- */
|
||||||
|
i <<= 1;
|
||||||
|
uint8_t c = i<0; //set carry for output pos/neg
|
||||||
|
|
||||||
|
if(i == (i|0x4000)) // flip input value to corresponding value in range [0..8192)
|
||||||
|
i = (1<<15) - i;
|
||||||
|
i = (i & 0x7FFF) >> 1;
|
||||||
|
/* ------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* The following section implements the formula:
|
||||||
|
= y * 2^-n * ( A1 - 2^(q-p)* y * 2^-n * y * 2^-n * [B1 - 2^-r * y * 2^-n * C1 * y]) * 2^(a-q)
|
||||||
|
Where the constants are defined as follows:
|
||||||
|
*/
|
||||||
|
// enum {A1=3370945099UL, B1=2746362156UL, C1=292421UL};
|
||||||
|
// enum {n=13, p=32, q=31, r=3, a=12};
|
||||||
|
|
||||||
|
uint32_t y = (292421UL*((uint32_t)i))>>13;
|
||||||
|
y = 2746362156UL - (((uint32_t)i*y)>>3);
|
||||||
|
y = (uint32_t)i * (y>>13);
|
||||||
|
y = (uint32_t)i * (y>>13);
|
||||||
|
y = 3370945099UL - (y>>(32-31));
|
||||||
|
y = (uint32_t)i * (y>>13);
|
||||||
|
y = (y+(1UL<<(31-12-1)))>>(31-12); // Rounding
|
||||||
|
|
||||||
|
return c ? -y : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Berry: tasmota.sine_int(int) -> int
|
||||||
|
//
|
||||||
|
// Input: 8192 is pi/2
|
||||||
|
// Output: -4096 is -1, 4096 is +1
|
||||||
|
//
|
||||||
|
// https://www.nullhardware.com/blog/fixed-point-sine-and-cosine-for-embedded-systems/
|
||||||
|
int32_t l_sineint(struct bvm *vm);
|
||||||
|
int32_t l_sineint(struct bvm *vm) {
|
||||||
|
int32_t top = be_top(vm); // Get the number of arguments
|
||||||
|
if (top == 1 && be_isint(vm, 1)) {
|
||||||
|
int32_t val = be_toint(vm, 1);
|
||||||
|
|
||||||
|
be_pushint(vm, fpsin(val));
|
||||||
|
be_return(vm);
|
||||||
|
}
|
||||||
|
be_raise(vm, kTypeError, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
int32_t l_respCmnd(bvm *vm);
|
int32_t l_respCmnd(bvm *vm);
|
||||||
int32_t l_respCmnd(bvm *vm) {
|
int32_t l_respCmnd(bvm *vm) {
|
||||||
int32_t top = be_top(vm); // Get the number of arguments
|
int32_t top = be_top(vm); // Get the number of arguments
|
||||||
|
Loading…
x
Reference in New Issue
Block a user