Berry animation init_strip (#23745)

This commit is contained in:
s-hadinger 2025-08-01 23:19:24 +02:00 committed by GitHub
parent 95f7e39672
commit be1e6df7ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 625 additions and 566 deletions

View File

@ -50,8 +50,7 @@ import animation
#strip length 60
# Define aurora color palette
# Auto-generated strip initialization (using Tasmota configuration)
var strip = global.Leds() # Get strip length from Tasmota configuration
var engine = animation.create_engine(strip)
var engine = animation.init_strip()
var aurora_colors_ = bytes("00000022" "40004400" "8000AA44" "C044AA88" "FF88FFAA")
# Secondary purple palette

View File

@ -52,8 +52,7 @@ import animation
# Breathing Colors - Slow color breathing effect
# Gentle pulsing through different colors
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Define breathing colors
var breathe_red_ = 0xFFFF0000
var breathe_green_ = 0xFF00FF00

View File

@ -57,8 +57,7 @@ import animation
# Candy Cane - Red and white stripes
# Classic Christmas candy cane pattern
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Define stripe colors
var candy_red_ = 0xFFFF0000
var candy_white_ = 0xFFFFFFFF

View File

@ -71,8 +71,7 @@ import animation
# Christmas Tree - Festive holiday colors
# Green base with colorful ornaments and twinkling
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Green tree base
var tree_green_ = 0xFF006600
var tree_base_ = animation.solid(animation.global('tree_green_', 'tree_green'))

View File

@ -50,8 +50,7 @@ import animation
# Comet Chase - Moving comet with trailing tail
# Bright head with fading tail
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Dark blue background
var space_blue_ = 0xFF000066 # Note: opaque 0xFF alpha channel is implicitly added
var background_ = animation.solid(animation.global('space_blue_', 'space_blue'))

View File

@ -63,8 +63,7 @@ import animation
# Disco Strobe - Fast colorful strobing
# Rapid color changes with strobe effects
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Define disco color palette
var disco_colors_ = bytes("00FF0000" "2AFF8000" "55FFFF00" "8000FF00" "AA0000FF" "D58000FF" "FFFF00FF")
# Fast color cycling base

View File

@ -43,8 +43,7 @@ import animation
# Fire Flicker - Realistic fire simulation
# Warm colors with random flickering intensity
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Define fire palette from black to yellow
var fire_colors_ = bytes("00000000" "40800000" "80FF0000" "C0FF4500" "FFFFFF00")
# Create base fire animation with palette

View File

@ -53,8 +53,7 @@ import animation
# Heartbeat Pulse - Rhythmic double pulse
# Red pulsing like a heartbeat
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Dark background
var heart_bg_ = 0xFF110000
var background_ = animation.solid(animation.global('heart_bg_', 'heart_bg'))

View File

@ -74,8 +74,7 @@ import animation
# Lava Lamp - Slow flowing warm colors
# Organic movement like a lava lamp
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Define lava colors (warm oranges and reds)
var lava_colors_ = bytes("00330000" "40660000" "80CC3300" "C0FF6600" "FFFFAA00")
# Base lava animation - very slow color changes

View File

@ -59,8 +59,7 @@ import animation
# Lightning Storm - Random lightning flashes
# Dark stormy background with bright lightning
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Dark stormy background with subtle purple/blue
var storm_colors_ = bytes("00000011" "80110022" "FF220033")
var storm_bg_ = animation.rich_palette_animation(animation.global('storm_colors_', 'storm_colors'), 12000, animation.global('smooth_', 'smooth'), 100)

View File

@ -68,8 +68,7 @@ import animation
# Matrix Rain - Digital rain effect
# Green cascading code like The Matrix
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Dark background
var matrix_bg_ = 0xFF000000
var background_ = animation.solid(animation.global('matrix_bg_', 'matrix_bg'))

View File

@ -73,8 +73,7 @@ import animation
# Meteor Shower - Multiple meteors with trails
# Fast moving bright objects with fading trails
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Dark space background
var space_bg_ = 0xFF000011
var background_ = animation.solid(animation.global('space_bg_', 'space_bg'))

View File

@ -76,8 +76,7 @@ import animation
# Neon Glow - Electric neon tube effect
# Bright saturated colors with flickering
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Define neon colors
var neon_colors_ = bytes("00FF0080" "5500FF80" "AA8000FF" "FFFF8000")
# Main neon glow with color cycling

View File

@ -62,8 +62,7 @@ import animation
# Ocean Waves - Blue-green wave simulation
# Flowing water colors with wave motion
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Define ocean color palette
var ocean_colors_ = bytes("00000080" "400040C0" "800080FF" "C040C0FF" "FF80FFFF")
# Base ocean animation with slow color cycling

View File

@ -51,8 +51,7 @@ import animation
# Palette Demo - Shows how to use custom palettes in DSL
# This demonstrates the new palette syntax
var strip = global.Leds(30)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(30)
# Define a fire palette
var fire_colors_ = bytes("00000000" "40800000" "80FF0000" "C0FF8000" "FFFFFF00")
# Define an ocean palette

View File

@ -92,8 +92,7 @@ import animation
# Palette Showcase - Demonstrates all palette features
# This example shows the full range of palette capabilities
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Example 1: Fire palette with hex colors
var fire_gradient_ = bytes("00000000" "20330000" "40660000" "60CC0000" "80FF3300" "A0FF6600" "C0FF9900" "E0FFCC00" "FFFFFF00")
# Example 2: Ocean palette with named colors

View File

@ -68,8 +68,7 @@ import animation
# Unified Pattern-Animation Demo
# This DSL example demonstrates the new unified architecture where Animation extends Pattern
var strip = global.Leds(30)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(30)
# UNIFIED ARCHITECTURE: solid() returns Animation (which IS a Pattern)
# No more artificial distinction between patterns and animations
var solid_red_ = animation.solid(0xFFFF0000) # Animation: solid red (infinite duration)

View File

@ -68,8 +68,7 @@ import animation
# Plasma Wave - Smooth flowing plasma colors
# Continuous color waves like plasma display
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Define plasma color palette with smooth transitions
var plasma_colors_ = bytes("00FF0080" "33FF8000" "66FFFF00" "9980FF00" "CC00FF80" "FF0080FF")
# Base plasma animation with medium speed

View File

@ -48,8 +48,7 @@ import animation
# Police Lights - Red and blue alternating flashes
# Emergency vehicle style lighting
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Define zones for left and right halves
var half_length_ = 30
# Left side red flashing

View File

@ -54,8 +54,7 @@ import animation
# Property Assignment Demo
# Shows how to set animation properties after creation
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Define colors
var red_custom_ = 0xFFFF0000
var blue_custom_ = 0xFF0000FF

View File

@ -24,8 +24,7 @@ import animation
# Rainbow Cycle - Classic WLED effect
# Smooth rainbow colors cycling across the strip
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Create smooth rainbow cycle animation
var rainbow_cycle_ = animation.color_cycle_animation([0xFFFF0000, 0xFFFF8000, 0xFFFFFF00, 0xFF00FF00, 0xFF0000FF, 0xFF8000FF, 0xFFFF00FF], 5000)
# Start the animation

View File

@ -47,8 +47,7 @@ import animation
# Scanner (Larson) - Knight Rider style scanner
# Red dot bouncing back and forth
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Dark background
var scanner_bg_ = 0xFF110000
var background_ = animation.solid(animation.global('scanner_bg_', 'scanner_bg'))

View File

@ -34,8 +34,7 @@ import animation
# Simple Palette Example
# Demonstrates basic palette usage in the DSL
var strip = global.Leds(20)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(20)
# Define a simple rainbow palette
var rainbow_ = bytes("00FF0000" "40FFA500" "80FFFF00" "C0008000" "FF0000FF")
# Create an animation using the palette

View File

@ -68,8 +68,7 @@ import animation
# Sunrise Sunset - Warm color transition
# Gradual transition from night to day colors
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Define time-of-day color palette
var daylight_colors_ = bytes("00000011" "20001133" "40FF4400" "60FFAA00" "80FFFF88" "A0FFAA44" "C0FF6600" "E0AA2200" "FF220011")
# Main daylight cycle - very slow transition

View File

@ -40,8 +40,7 @@ import animation
# Twinkle Stars - Random sparkling white stars
# White sparkles on dark blue background
var strip = global.Leds(60)
var engine = animation.create_engine(strip)
var engine = animation.init_strip(60)
# Dark blue background
var night_sky_ = 0xFF000033
var background_ = animation.solid(animation.global('night_sky_', 'night_sky'))

View File

@ -1,24 +1,41 @@
# this is the entry point for animation Framework
# it imports all other modules and register in the "animation" object
# Berry Animation Framework - Main Entry Point
#
# launch with "./berry -s -g -m lib/libesp32/berry_animation"
# This is the central module that imports and registers all animation framework components
# into a unified "animation" object for use in Tasmota LED strip control.
#
# The framework provides:
# - Unified Pattern-Animation architecture (Animation extends Pattern)
# - DSL (Domain Specific Language) for declarative animation definitions
# - Value providers for dynamic parameters (oscillators, color providers)
# - Event system for interactive animations
# - Optimized performance for embedded ESP32 systems
#
# Usage in Tasmota:
# import animation
# var engine = animation.create_engine(strip)
# var pulse_anim = animation.pulse(animation.solid(0xFF0000), 2000, 50, 255)
# engine.add_animation(pulse_anim).start()
#
# Launch standalone with: "./berry -s -g -m lib/libesp32/berry_animation"
# import in global scope all that is needed
# Import Tasmota integration if available (for embedded use)
import global
if !global.contains("tasmota")
import tasmota
end
# Create the main animation module and make it globally accessible
# The @solidify directive enables compilation to C++ for performance
#@ solidify:animation,weak
var animation = module("animation")
global.animation = animation
# Version information
# Version information for compatibility tracking
# Format: 0xAABBCCDD (AA=major, BB=minor, CC=patch, DD=build)
animation.VERSION = 0x00010000
# Convert version number to string format "major.minor.patch"
def animation_version_string(version_num)
# Convert version number to human-readable string format "major.minor.patch"
def animation_version_string(version_num)
if version_num == nil version_num = animation.VERSION end
var major = (version_num >> 24) & 0xFF
var minor = (version_num >> 16) & 0xFF
@ -29,32 +46,44 @@ animation.version_string = animation_version_string
import sys
# Takes a map returned by "import XXX" and add each key/value to module `animation`
# Helper function to register all exports from imported modules into the main animation object
# This creates a flat namespace where all animation functions are accessible as animation.function_name()
# Takes a map returned by "import XXX" and adds each key/value to module `animation`
def register_to_animation(m)
for k: m.keys()
animation.(k) = m[k]
end
end
# Import the core classes
# Import core framework components
# These provide the fundamental architecture for the animation system
# Frame buffer management for LED strip pixel data
import "core/frame_buffer" as frame_buffer
register_to_animation(frame_buffer)
# Base Pattern class - foundation for all visual elements
import "core/pattern_base" as pattern_base
register_to_animation(pattern_base)
# Base Animation class - extends Pattern with temporal behavior
import "core/animation_base" as animation_base
register_to_animation(animation_base)
# Sequence manager for complex animation choreography
import "core/sequence_manager" as sequence_manager
register_to_animation(sequence_manager)
# Import the unified animation engine
# Unified animation engine - central controller for all animations
# Provides priority-based layering, automatic blending, and performance optimization
import "core/animation_engine" as animation_engine
register_to_animation(animation_engine)
# Import event system
# Event system for interactive animations (button presses, timers, etc.)
import "core/event_handler" as event_handler
register_to_animation(event_handler)
# Import user functions registry
# User-defined function registry for DSL extensibility
import "core/user_functions" as user_functions
register_to_animation(user_functions)
@ -139,19 +168,36 @@ register_to_animation(dsl_transpiler)
import "dsl/runtime.be" as dsl_runtime
register_to_animation(dsl_runtime)
# Function called to initialize the `Leds` and `engine` objects
#
# Parameters:
# l - list of arguments (vararg)
#
# Returns:
# An instance of `AnimationEngine` managing the strip
def animation_init_strip(*l)
import global
import animation
var strip = call(global.Leds, l) # call global.Leds() with vararg
var engine = animation.create_engine(strip)
return engine
end
animation.init_strip = animation_init_strip
# Global variable resolver with error checking
# First checks animation module, then global scope
# Used by DSL transpiler to resolve variable names during compilation
# First checks animation module, then global scope for user-defined variables
def animation_global(name, module_name)
import global
import introspect
import animation
# First try to find in animation module
# First try to find in animation module (built-in functions/classes)
if (module_name != nil) && introspect.contains(animation, module_name)
return animation.(module_name)
end
# Then try global scope
# Then try global scope (user-defined variables)
if global.contains(name)
return global.(name)
else
@ -160,19 +206,30 @@ def animation_global(name, module_name)
end
animation.global = animation_global
# This function is called from C++ code to set up the Berry animation environment
# It creates a mutable 'animation' module on top of the immutable solidified
#
# Parameters:
# m - Solidified immutable module
#
# Returns:
# A new animation module instance that is return for `import animation`
def animation_init(m)
var animation_new = module("animation") # create new non-solidified module
animation_new._ntv = m # keep the native module
animation_new.event_manager = m.EventManager() # create monad for event manager
var animation_new = module("animation") # Create new non-solidified module for runtime use
animation_new._ntv = m # Keep reference to native solidified module
animation_new.event_manager = m.EventManager() # Create event manager instance for handling triggers
# create a member function that looks in current module then in solidified
# Create dynamic member lookup function for extensibility
# This allows the module to find members in both Berry and solidified components
#
# Note: if the module already contained the member, then `member()` would not be called in the first place
animation_new.member = def (k)
import animation
import introspect
if introspect.contains(animation._ntv, k)
return animation._ntv.(k)
return animation._ntv.(k) # Return native solidified member if available
else
return module("undefined")
return module("undefined") # Return undefined module for missing members
end
end

View File

@ -252,8 +252,7 @@ class SimpleDSLTranspiler
if prop == "length"
var length = self.expect_number()
var inline_comment = self.collect_inline_comment()
self.add(f"var strip = global.Leds({length}){inline_comment}")
self.add(f"var engine = animation.create_engine(strip)")
self.add(f"var engine = animation.init_strip({length}){inline_comment}")
self.strip_initialized = true # Mark that strip was initialized
end
end
@ -1112,8 +1111,7 @@ class SimpleDSLTranspiler
end
self.add("# Auto-generated strip initialization (using Tasmota configuration)")
self.add("var strip = global.Leds() # Get strip length from Tasmota configuration")
self.add("var engine = animation.create_engine(strip)")
self.add("var engine = animation.init_strip()")
self.add("")
self.strip_initialized = true
end

View File

@ -157,9 +157,9 @@ def test_strip_configuration()
print("Testing strip configuration...")
var strip_tests = [
["strip length 30", "var strip = global.Leds(30)"],
["strip length 60", "var strip = global.Leds(60)"],
["strip length 120", "var strip = global.Leds(120)"]
["strip length 30", "var engine = animation.init_strip(30)"],
["strip length 60", "var engine = animation.init_strip(60)"],
["strip length 120", "var engine = animation.init_strip(120)"]
]
for test : strip_tests
@ -169,7 +169,6 @@ def test_strip_configuration()
var berry_code = animation.compile_dsl(dsl_input)
assert(berry_code != nil, "Should compile strip config: " + dsl_input)
assert(string.find(berry_code, expected_output) >= 0, "Should contain: " + expected_output)
assert(string.find(berry_code, "var engine = animation.create_engine(strip)") >= 0, "Should create engine")
end
print("✓ Strip configuration test passed")

View File

@ -25,7 +25,7 @@ def test_basic_transpilation()
var berry_code = animation.compile_dsl(dsl_source)
assert(berry_code != nil, "Should generate Berry code")
assert(string.find(berry_code, "var strip = global.Leds(60)") >= 0, "Should generate strip configuration")
assert(string.find(berry_code, "var engine = animation.init_strip(60)") >= 0, "Should generate strip configuration")
assert(string.find(berry_code, "var custom_red_ = 0xFFFF0000") >= 0, "Should generate color definition")
assert(string.find(berry_code, "def sequence_demo()") >= 0, "Should generate sequence function")
assert(string.find(berry_code, "sequence_demo()") >= 0, "Should generate sequence call")
@ -97,9 +97,9 @@ def test_strip_configuration()
print("Testing strip configuration...")
var config_tests = [
["strip length 30", "var strip = global.Leds(30)"],
["strip length 60", "var strip = global.Leds(60)"],
["strip length 120", "var strip = global.Leds(120)"]
["strip length 30", "var engine = animation.init_strip(30)"],
["strip length 60", "var engine = animation.init_strip(60)"],
["strip length 120", "var engine = animation.init_strip(120)"]
]
for test : config_tests
@ -377,7 +377,7 @@ def test_complex_dsl()
print("Complex DSL compiled successfully!")
# Check for key components
assert(string.find(berry_code, "var strip = global.Leds(60)") >= 0, "Should have strip config")
assert(string.find(berry_code, "var engine = animation.init_strip(60)") >= 0, "Should have strip config")
assert(string.find(berry_code, "var custom_red_ = 0xFFFF0000") >= 0, "Should have color definitions")
assert(string.find(berry_code, "def sequence_demo()") >= 0, "Should have sequence definition")
assert(string.find(berry_code, "sequence_demo()") >= 0, "Should have execution")