Skip to content

Troubleshooting Guide~

Common issues and solutions for the Tasmota Berry Animation Framework.

Note: This guide focuses on DSL usage, which is the recommended way to create animations. For programmatic API issues, see the Animation Development Guide.

Installation Issues~

Framework Not Found~

Problem: import animation or import animation_dsl fails with "module not found"

Solutions: 1. Check Module Import:

import animation      # Core framework
import animation_dsl  # DSL compiler

  1. Set Module Path:

    berry -m lib/libesp32/berry_animation
    

  2. Verify File Structure:

    lib/libesp32/berry_animation/
    ├── animation.be          # Main module file
    ├── dsl/                  # DSL components
    ├── core/                 # Core classes
    ├── animations/           # Animation effects
    └── ...
    

Missing Dependencies~

Problem: Errors about missing tasmota or Leds classes

Solutions: 1. For Tasmota Environment: - Ensure you're running on actual Tasmota firmware - Check that Berry support is enabled

  1. For Development Environment:
    # Mock Tasmota for testing
    if !global.contains("tasmota")
      global.tasmota = {
        "millis": def() return 1000 end,
        "scale_uint": def(val, from_min, from_max, to_min, to_max)
          return int((val - from_min) * (to_max - to_min) / (from_max - from_min) + to_min)
        end
      }
    end
    

Animation Issues~

Animations Not Starting~

Problem: DSL animations compile but LEDs don't change

Diagnostic Steps:

import animation
import animation_dsl

# Test basic DSL execution
var dsl_code = "color red = 0xFF0000\n" +
               "animation red_anim = solid(color=red)\n" +
               "run red_anim"

try
  animation_dsl.execute(dsl_code)
  print("DSL executed successfully")
except .. as e, msg
  print("DSL Error:", msg)
end

Timing Behavior Note: The framework has updated timing behavior where: - The start() method only resets the time origin if the animation/value provider was already started previously - The first actual rendering tick occurs in update(), render(), or produce_value() methods - This ensures proper timing initialization and prevents premature time reference setting

Common Solutions:

  1. Missing Strip Declaration:

    # Add explicit strip length if needed
    strip length 30
    
    color red = 0xFF0000
    animation red_anim = solid(color=red)
    run red_anim
    

  2. Animation Not Executed:

    # Make sure you have a 'run' statement
    color red = 0xFF0000
    animation red_anim = solid(color=red)
    run red_anim  # Don't forget this!
    

  3. Strip Auto-Detection Issues:

    # Force strip length if auto-detection fails
    strip length 30  # Must be first statement
    
    color red = 0xFF0000
    animation red_anim = solid(color=red)
    run red_anim
    

Colors Look Wrong~

Problem: Colors appear different than expected

Common Issues:

  1. Missing Alpha Channel:

    # Note: 0xFF0000 is valid RGB format (alpha defaults to 0xFF)
    color red = 0xFF0000      # RGB format (alpha=255 assumed)
    
    # Explicit alpha channel (ARGB format)
    color red = 0xFFFF0000    # ARGB format (alpha=255, red=255)
    color semi_red = 0x80FF0000  # ARGB format (alpha=128, red=255)
    

  2. Color Format Confusion:

    # ARGB format: 0xAARRGGBB
    color red = 0xFFFF0000      # Alpha=FF, Red=FF, Green=00, Blue=00
    color green = 0xFF00FF00    # Alpha=FF, Red=00, Green=FF, Blue=00
    color blue = 0xFF0000FF     # Alpha=FF, Red=00, Green=00, Blue=FF
    

  3. Brightness Issues:

    # Use opacity parameter or property assignment
    animation red_anim = solid(color=red, opacity=255)  # Full brightness
    
    # Or assign after creation
    animation pulse_red = pulsating_animation(color=red, period=2s)
    pulse_red.opacity = 200  # Adjust brightness
    
    # Use value providers for dynamic brightness
    set brightness = smooth(min_value=50, max_value=255, period=3s)
    animation breathing = solid(color=red)
    breathing.opacity = brightness
    

Animations Too Fast/Slow~

Problem: Animation timing doesn't match expectations

Solutions:

  1. Check Time Units:

    # DSL uses time units (converted to milliseconds)
    animation pulse_anim = pulsating_animation(color=red, period=2s)    # 2 seconds
    animation fast_pulse = pulsating_animation(color=blue, period=500ms) # 0.5 seconds
    

  2. Adjust Periods:

    # Too fast - increase period
    animation slow_pulse = pulsating_animation(color=red, period=5s)   # 5 seconds
    
    # Too slow - decrease period
    animation fast_pulse = pulsating_animation(color=red, period=500ms) # 0.5 seconds
    

  3. Performance Limitations:

    # Use sequences instead of multiple simultaneous animations
    sequence optimized_show {
      play animation1 for 3s
      play animation2 for 3s
      play animation3 for 3s
    }
    run optimized_show
    
    # Instead of:
    # run animation1
    # run animation2  
    # run animation3
    

DSL Issues~

DSL Compilation Errors~

Problem: DSL code fails to compile

Diagnostic Approach:

try
  var berry_code = animation_dsl.compile(dsl_source)
  print("Compilation successful")
except "dsl_compilation_error" as e, msg
  print("DSL Error:", msg)
end

Common DSL Errors:

  1. Undefined Colors:

    # Wrong - color not defined
    animation red_anim = solid(color=red)
    
    # Correct - define color first
    color red = 0xFF0000
    animation red_anim = solid(color=red)
    

  2. Invalid Color Format:

    # Wrong - # prefix not supported (conflicts with comments)
    color red = #FF0000
    
    # Correct - use 0x prefix
    color red = 0xFF0000
    

  3. Missing Time Units:

    # Wrong - no time unit
    animation pulse_anim = pulsating_animation(color=red, period=2000)
    
    # Correct - with time unit
    animation pulse_anim = pulsating_animation(color=red, period=2s)
    

  4. Reserved Name Conflicts:

    # Wrong - 'red' is a predefined color
    color red = 0x800000
    
    # Correct - use different name
    color dark_red = 0x800000
    

  5. Invalid Parameter Names:

    # Wrong - invalid parameter name
    animation pulse_anim = pulsating_animation(color=red, invalid_param=123)
    # Error: "Parameter 'invalid_param' is not valid for pulsating_animation"
    
    # Correct - use valid parameters (see Dsl_Reference.md for complete list)
    animation pulse_anim = pulsating_animation(color=red, period=2s)
    

  6. Variable Duration Support:

    # Now supported - variables in play/wait durations
    set eye_duration = 5s
    
    sequence cylon_eye {
      play red_eye for eye_duration    # ✓ Variables now work
      wait eye_duration                # ✓ Variables work in wait too
    }
    
    # Also supported - value providers for dynamic duration
    set dynamic_time = triangle(min_value=1000, max_value=3000, period=10s)
    
    sequence demo {
      play animation for dynamic_time  # ✓ Dynamic duration
    }
    

  7. Template Definition Errors:

    # Wrong - missing braces
    template pulse_effect
      param color type color
      param speed
    # Error: Expected '{' after template name
    
    # Wrong - invalid parameter syntax
    template pulse_effect {
      param color as color  # Error: Use 'type' instead of 'as'
      param speed
    }
    
    # Wrong - missing template body
    template pulse_effect {
      param color type color
    }
    # Error: Template body cannot be empty
    
    # Correct - proper template syntax
    template pulse_effect {
      param color type color
      param speed
    
      animation pulse = pulsating_animation(
        color=color
        period=speed
      )
    
      run pulse
    }
    

  8. Template Call Errors:

    # Wrong - template not defined
    pulse_effect(red, 2s)
    # Error: "Undefined reference: 'pulse_effect'"
    
    # Wrong - incorrect parameter count
    template pulse_effect {
      param color type color
      param speed
      # ... template body ...
    }
    
    pulse_effect(red)  # Error: Expected 2 parameters, got 1
    
    # Correct - define template first, call with correct parameters
    template pulse_effect {
      param color type color
      param speed
    
      animation pulse = pulsating_animation(color=color, period=speed)
      run pulse
    }
    
    pulse_effect(red, 2s)  # ✓ Correct usage
    

  9. Parameter Constraint Violations:

    # Wrong - negative period not allowed
    animation bad_pulse = pulsating_animation(color=red, period=-2s)
    # Error: "Parameter 'period' value -2000 violates constraint: min=1"
    
    # Wrong - invalid enum value
    animation bad_comet = comet_animation(color=red, direction=5)
    # Error: "Parameter 'direction' value 5 not in allowed values: [-1, 1]"
    
    # Correct - valid parameters within constraints
    animation good_pulse = pulsating_animation(color=red, period=2s)
    animation good_comet = comet_animation(color=red, direction=1)
    

  10. Repeat Syntax Errors:

    # Wrong - old colon syntax no longer supported
    sequence bad_demo {
      repeat 3 times:  # Error: Expected '{' after 'times'
        play anim for 1s
    }
    
    # Wrong - missing braces
    sequence bad_demo2 {
      repeat 3 times
        play anim for 1s  # Error: Expected '{' after 'times'
    }
    
    # Correct - use braces for repeat blocks
    sequence good_demo {
      repeat 3 times {
        play anim for 1s
      }
    }
    
    # Also correct - alternative syntax
    sequence good_demo_alt repeat 3 times {
      play anim for 1s
    }
    
    # Correct - forever syntax
    sequence infinite_demo {
      repeat forever {
        play anim for 1s
        wait 500ms
      }
    }
    

Template Issues~

Template Definition Problems~

Problem: Template definitions fail to compile

Common Template Errors:

  1. Missing Template Body:

    # Wrong - empty template
    template empty_template {
      param color type color
    }
    # Error: "Template body cannot be empty"
    
    # Correct - template must have content
    template pulse_effect {
      param color type color
      param speed
    
      animation pulse = pulsating_animation(color=color, period=speed)
      run pulse
    }
    

  2. Invalid Parameter Syntax:

    # Wrong - old 'as' syntax
    template pulse_effect {
      param color as color
    }
    # Error: Expected 'type' keyword, got 'as'
    
    # Correct - use 'type' keyword
    template pulse_effect {
      param color type color
      param speed  # Type annotation is optional
    }
    

  3. Template Name Conflicts:

    # Wrong - template name conflicts with built-in function
    template solid {  # 'solid' is a built-in animation function
      param color type color
      # ...
    }
    # Error: "Template name 'solid' conflicts with built-in function"
    
    # Correct - use unique template names
    template solid_effect {
      param color type color
      # ...
    }
    

Template Usage Problems~

Problem: Template calls fail or behave unexpectedly

Common Issues:

  1. Undefined Template:

    # Wrong - calling undefined template
    my_effect(red, 2s)
    # Error: "Undefined reference: 'my_effect'"
    
    # Correct - define template first
    template my_effect {
      param color type color
      param speed
      # ... template body ...
    }
    
    my_effect(red, 2s)  # Now works
    

  2. Parameter Count Mismatch:

    template pulse_effect {
      param color type color
      param speed
      param brightness
    }
    
    # Wrong - missing parameters
    pulse_effect(red, 2s)  # Error: Expected 3 parameters, got 2
    
    # Correct - provide all parameters
    pulse_effect(red, 2s, 200)
    

  3. Parameter Type Issues:

    template pulse_effect {
      param color type color
      param speed
    }
    
    # Wrong - invalid color parameter
    pulse_effect("not_a_color", 2s)
    # Runtime error: Invalid color value
    
    # Correct - use valid color
    pulse_effect(red, 2s)      # Named color
    pulse_effect(0xFF0000, 2s) # Hex color
    

Template vs User Function Confusion~

Problem: Mixing template and user function concepts

Key Differences:

# Template (DSL-native) - Recommended for most cases
template pulse_effect {
  param color type color
  param speed

  animation pulse = pulsating_animation(color=color, period=speed)
  run pulse
}

# User Function (Berry-native) - For complex logic
def create_pulse_effect(engine, color, speed)
  var pulse = animation.pulsating_animation(engine)
  pulse.color = color
  pulse.period = speed
  return pulse
end
animation.register_user_function("pulse_effect", create_pulse_effect)

When to Use Each: - Templates: Simple to moderate effects, DSL syntax, type safety - User Functions: Complex logic, Berry features, return values

DSL Runtime Errors~

Problem: DSL compiles but fails at runtime

Common Issues:

  1. Strip Not Initialized:

    # Add strip declaration if needed
    strip length 30
    
    color red = 0xFF0000
    animation red_anim = solid(color=red)
    run red_anim
    

  2. Repeat Performance Issues:

    # Efficient - runtime repeats don't expand at compile time
    sequence efficient {
      repeat 1000 times {  # No memory overhead for large counts
        play anim for 100ms
        wait 50ms
      }
    }
    
    # Nested repeats work efficiently
    sequence nested {
      repeat 100 times {
        repeat 50 times {  # Total: 5000 iterations, but efficient
          play quick_flash for 10ms
        }
        wait 100ms
      }
    }
    

  3. Sequence Issues:

    # Make sure animations are defined before sequences
    color red = 0xFF0000
    animation red_anim = solid(color=red)  # Define first
    
    sequence demo {
      play red_anim for 3s  # Use after definition
      wait 1s               # Optional pause between animations
    }
    run demo
    

  4. Undefined References:

    # Wrong - using undefined animation in sequence
    sequence bad_demo {
      play undefined_animation for 3s
    }
    # Error: "Undefined reference: 'undefined_animation'"
    
    # Correct - define all references first
    color blue = 0x0000FF
    animation blue_anim = solid(color=blue)
    
    sequence good_demo {
      play blue_anim for 3s
    }
    run good_demo
    

Performance Issues~

CPU Metrics and Profiling~

Feature: Built-in CPU metrics tracking to monitor animation performance

The AnimationEngine automatically tracks CPU usage and provides detailed statistics every 5 seconds. This helps identify performance bottlenecks and optimize animations for ESP32 embedded systems.

Automatic Metrics:

When the engine is running, it automatically logs performance statistics:

AnimEngine: ticks=1000/1000 missed=0 total=0.50ms(0-2) anim=0.30ms(0-1) hw=0.20ms(0-1) cpu=10.0%
  Phase1(checks): mean=0.05ms(0-0)
  Phase2(events): mean=0.05ms(0-0)
  Phase3(anim): mean=0.20ms(0-1)

Metrics Explained: - ticks: Actual ticks executed vs expected (at 5ms intervals) - missed: Hint of missed ticks (negative means extra ticks, positive means missed) - total: Mean total tick time with (min-max) range in milliseconds - anim: Mean animation calculation time with (min-max) range - everything before hardware output - hw: Mean hardware output time with (min-max) range - just the LED strip update - cpu: Overall CPU usage percentage over the 5-second period

Phase Metrics (Optional): When intermediate measurement points are available, the engine also reports phase-based timing: - Phase1(checks): Initial checks (strip length, throttling, can_show) - Phase2(events): Event processing time - Phase3(anim): Animation update and render time (before hardware output)

Timestamp-Based Profiling:

The engine uses a timestamp-based profiling system that stores only timestamps (not durations) in instance variables:

  • ts_start - Tick start timestamp
  • ts_1 - After initial checks (optional)
  • ts_2 - After event processing (optional)
  • ts_3 - After animation update/render (optional)
  • ts_hw - After hardware output
  • ts_end - Tick end timestamp

Durations are computed from these timestamps in _record_tick_metrics() with nil checks to ensure values are valid.

Accessing Profiling Data:

import animation

var strip = Leds(30)
var engine = animation.create_engine(strip)

# Add an animation
var anim = animation.solid(engine)
anim.color = 0xFFFF0000
engine.add(anim)
engine.run()

# Run for a while to collect metrics
# After 5 seconds, metrics are automatically logged

# Access current metrics programmatically
print("Tick count:", engine.tick_count)
print("Total time sum:", engine.tick_time_sum)
print("Animation time sum:", engine.anim_time_sum)
print("Hardware time sum:", engine.hw_time_sum)

# Access phase metrics if available
if engine.phase1_time_sum > 0
  print("Phase 1 time sum:", engine.phase1_time_sum)
end

Profiling Benefits:

  1. Memory Efficient:
  2. Only stores timestamps (6 instance variables)
  3. No duration storage or arrays
  4. Streaming statistics with no memory overhead

  5. Automatic Tracking:

  6. No manual instrumentation needed
  7. Runs continuously in background
  8. Reports every 5 seconds

  9. Detailed Breakdown:

  10. Separates animation calculation from hardware output
  11. Optional phase-based timing for deeper analysis
  12. Min/max/mean statistics for all metrics

Interpreting Performance Metrics:

  1. High Animation Time:
  2. Too many simultaneous animations
  3. Complex value provider calculations
  4. Inefficient custom effects

Solution: Simplify animations or use sequences

  1. High Hardware Time:
  2. Large LED strip (many pixels)
  3. Slow SPI/I2C communication
  4. Hardware limitations

Solution: Reduce update frequency or strip length

  1. Missed Ticks:
  2. CPU overload (total time > 5ms per tick)
  3. Other Tasmota tasks interfering

Solution: Optimize animations or reduce complexity

  1. High CPU Percentage:
  2. Animations consuming too much CPU
  3. May affect other Tasmota functions

Solution: Increase animation periods or reduce effects

Example Performance Optimization:

import animation

var strip = Leds(60)
var engine = animation.create_engine(strip)

# Before optimization - complex animation
var complex_anim = animation.rainbow_animation(engine)
complex_anim.period = 100  # Very fast, high CPU

engine.add(complex_anim)
engine.run()

# Check metrics after 5 seconds:
# AnimEngine: ticks=950/1000 missed=50 total=5.2ms(4-8) cpu=104.0%
# ^ Too slow! Missing ticks and over 100% CPU

# After optimization - slower period
complex_anim.period = 2000  # 2 seconds instead of 100ms

# Check metrics after 5 seconds:
# AnimEngine: ticks=1000/1000 missed=0 total=0.8ms(0-2) cpu=16.0%
# ^ Much better! All ticks processed, reasonable CPU usage

Choppy Animations~

Problem: Animations appear jerky or stuttering

Solutions:

  1. Use Sequences Instead of Multiple Animations:

    # Good - sequential playback
    sequence smooth_show {
      play animation1 for 3s
      play animation2 for 3s
      play animation3 for 3s
    }
    run smooth_show
    
    # Avoid - too many simultaneous animations
    # run animation1
    # run animation2
    # run animation3
    

  2. Increase Animation Periods:

    # Smooth - longer periods
    animation smooth_pulse = pulsating_animation(color=red, period=3s)
    
    # Choppy - very short periods
    animation choppy_pulse = pulsating_animation(color=red, period=50ms)
    

  3. Optimize Value Providers:

    # Efficient - reuse providers
    set breathing = smooth(min_value=50, max_value=255, period=2s)
    
    color red = 0xFF0000
    color blue = 0x0000FF
    
    animation anim1 = pulsating_animation(color=red, period=2s)
    anim1.opacity = breathing
    
    animation anim2 = pulsating_animation(color=blue, period=2s)
    anim2.opacity = breathing  # Reuse same provider
    

  4. Monitor CPU Metrics:

    # Check if CPU is overloaded
    # Look for missed ticks or high CPU percentage in metrics
    # AnimEngine: ticks=950/1000 missed=50 ... cpu=95.0%
    # ^ This indicates performance issues
    
    # Use profiling to find bottlenecks
    engine.profile_start("suspect_code")
    # ... code that might be slow ...
    engine.profile_end("suspect_code")
    

Memory Issues~

Problem: Out of memory errors or system crashes

Solutions:

  1. Clear Unused Animations:

    # Clear before adding new animations
    engine.clear()
    engine.add(new_animation)
    

  2. Limit Palette Size:

    # Good - reasonable palette size
    palette simple_fire = [
      (0, 0x000000),
      (128, 0xFF0000),
      (255, 0xFFFF00)
    ]
    
    # Avoid - very large palettes
    # palette huge_palette = [
    #   (0, color1), (1, color2), ... (255, color256)
    # ]
    

  3. Use Sequences Instead of Simultaneous Animations:

    # Memory efficient - sequential playback
    sequence show {
      play animation1 for 5s
      play animation2 for 5s
      play animation3 for 5s
    }
    
    # Memory intensive - all at once
    # run animation1
    # run animation2
    # run animation3
    

Event System Issues~

Events Not Triggering~

Problem: Event handlers don't execute

Diagnostic Steps:

# Check if handler is registered
var handlers = animation.get_event_handlers("button_press")
print("Handler count:", size(handlers))

# Test event triggering
animation.trigger_event("test_event", {"debug": true})

Solutions:

  1. Verify Handler Registration:

    def test_handler(event_data)
      print("Event triggered:", event_data)
    end
    
    var handler = animation.register_event_handler("test", test_handler, 0)
    print("Handler registered:", handler != nil)
    

  2. Check Event Names:

    # Event names are case-sensitive
    animation.register_event_handler("button_press", handler)  # Correct
    animation.trigger_event("button_press", {})               # Must match exactly
    

  3. Verify Conditions:

    def condition_func(event_data)
      return event_data.contains("required_field")
    end
    
    animation.register_event_handler("event", handler, 0, condition_func)
    
    # Event data must satisfy condition
    animation.trigger_event("event", {"required_field": "value"})
    

Hardware Issues~

LEDs Not Responding~

Problem: Framework runs but LEDs don't light up

Hardware Checks:

  1. Power Supply:
  2. Ensure adequate power for LED count
  3. Check voltage (5V for WS2812)
  4. Verify ground connections

  5. Wiring:

  6. Data line connected to correct GPIO
  7. Ground connected between controller and LEDs
  8. Check for loose connections

  9. LED Strip:

  10. Test with known working code
  11. Check for damaged LEDs
  12. Verify strip type (WS2812, SK6812, etc.)

Software Checks:

# Test basic LED functionality
var strip = Leds(30)  # 30 LEDs
strip.set_pixel_color(0, 0xFFFF0000)  # Set first pixel red
strip.show()  # Update LEDs

# Test with animation framework
import animation
var engine = animation.create_engine(strip)
var red_anim = animation.solid(engine)
red_anim.color = 0xFFFF0000
engine.add(red_anim)
engine.run()

# If basic strip works but animation doesn't, check framework setup

Wrong Colors on Hardware~

Problem: Colors look different on actual LEDs vs. expected

Solutions:

  1. Color Order:

    # Some strips use different color orders
    # Try different strip types in Tasmota configuration
    # WS2812: RGB order
    # SK6812: GRBW order
    

  2. Gamma Correction:

    # Enable gamma correction in Tasmota
    # SetOption37 128  # Enable gamma correction
    

  3. Power Supply Issues:

  4. Voltage drop causes color shifts
  5. Use adequate power supply
  6. Add power injection for long strips

Debugging Techniques~

DSL vs Berry API Debugging~

For DSL Issues (Recommended):

# Enable DSL debug output
import animation_dsl

var dsl_code = "color red = 0xFF0000\nanimation test = solid(color=red)\nrun test"

# Check compilation
try
  var berry_code = animation_dsl.compile(dsl_code)
  print("DSL compilation successful")
  print("Generated Berry code:")
  print(berry_code)
except .. as e, msg
  print("DSL compilation error:", msg)
end

# Execute with debug
try
  animation_dsl.execute(dsl_code, true)  # debug=true
except .. as e, msg
  print("DSL execution error:", msg)
end

For Framework Issues (Advanced):

# Direct Berry API debugging (for framework developers)
import animation

var strip = Leds(30)
var engine = animation.create_engine(strip, true)  # debug=true

var anim = animation.solid(engine)
anim.color = 0xFFFF0000
engine.add(anim)
engine.run()

Step-by-Step Testing~

# Test each component individually
print("1. Creating strip...")
var strip = Leds(30)
print("Strip created:", strip != nil)

print("2. Creating engine...")
var engine = animation.create_engine(strip)
print("Engine created:", engine != nil)

print("3. Creating animation...")
var anim = animation.solid(engine)
anim.color = 0xFFFF0000
print("Animation created:", anim != nil)

print("4. Adding animation...")
engine.add(anim)
print("Animation count:", engine.size())

print("5. Starting engine...")
engine.run()
print("Engine active:", engine.is_active())

Monitor Performance~

# Check timing
var start_time = tasmota.millis()
# ... run animation code ...
var end_time = tasmota.millis()
print("Execution time:", end_time - start_time, "ms")

# Monitor memory (if available)
import gc
print("Memory before:", gc.allocated())
# ... create animations ...
print("Memory after:", gc.allocated())

Getting Help~

Information to Provide~

When asking for help, include:

  1. Hardware Setup:
  2. LED strip type and count
  3. GPIO pin used
  4. Power supply specifications

  5. Software Environment:

  6. Tasmota version
  7. Berry version
  8. Framework version

  9. Code:

  10. Complete minimal example that reproduces the issue
  11. Error messages (exact text)
  12. Expected vs. actual behavior

  13. Debugging Output:

  14. Debug mode output
  15. Generated Berry code (for DSL issues)
  16. Console output

Example Bug Report~

**Problem:** DSL animation compiles but LEDs don't change

**Hardware:**
- 30x WS2812 LEDs on GPIO 1
- ESP32 with 5V/2A power supply

**Code:**
```berry
color red = 0xFF0000
animation red_anim = solid(color=red)
run red_anim

Error Output:

DSL compilation successful
Engine created: true
Animation count: 1
Engine active: true

Expected: LEDs turn red Actual: LEDs remain off

Additional Info: - Basic strip.set_pixel_color(0, 0xFFFF0000); strip.show() works - Tasmota 13.2.0, Berry enabled

This format helps identify issues quickly and provide targeted solutions.

## Prevention Tips

### Code Quality

1. **Use Try-Catch Blocks:**
   ```berry
   try
     runtime.load_dsl(dsl_code)
   except .. as e, msg
     print("Error:", msg)
   end
   ```

2. **Validate Inputs:**
   ```berry
   if type(color) == "int" && color >= 0
     var anim = animation.solid(color)
   else
     print("Invalid color:", color)
   end
   ```

3. **Test Incrementally:**
   - Start with simple solid colors
   - Add one effect at a time
   - Test each change before proceeding

### Performance Best Practices

1. **Limit Complexity:**
   - 1-3 simultaneous animations
   - Reasonable animation periods (>1 second)
   - Moderate palette sizes

2. **Resource Management:**
   - Clear unused animations
   - Reuse value providers
   - Use sequences for complex shows

3. **Hardware Considerations:**
   - Adequate power supply
   - Proper wiring and connections
   - Appropriate LED strip for application

## Quick Reference: Common DSL Patterns

### Basic Animation
```berry
color red = 0xFF0000
animation red_solid = solid(color=red)
run red_solid

Templates~

# Define reusable template
template pulse_effect {
  param base_color type color    # Use descriptive names
  param speed type time          # Add type annotations for clarity

  animation pulse = pulsating_animation(color=base_color, period=speed)
  run pulse
}

# Use template multiple times
pulse_effect(red, 2s)
pulse_effect(blue, 1s)

Common Template Parameter Issues:

# ❌ AVOID: Parameter name conflicts
template bad_example {
  param color type color      # Error: conflicts with built-in color name
  param animation type number # Error: conflicts with reserved keyword
}

# ✅ CORRECT: Use descriptive, non-conflicting names
template good_example {
  param base_color type color    # Clear, non-conflicting name
  param anim_speed type time     # Descriptive parameter name
}

# ⚠️ WARNING: Unused parameters generate warnings
template unused_param_example {
  param used_color type color
  param unused_value type number  # Warning: never used in template body

  animation test = solid(color=used_color)
  run test
}

Animation with Parameters~

color blue = 0x0000FF
animation blue_pulse = pulsating_animation(color=blue, period=2s, opacity=200)
run blue_pulse

Using Value Providers~

set breathing = smooth(min_value=50, max_value=255, period=3s)
color green = 0x00FF00
animation breathing_green = solid(color=green)
breathing_green.opacity = breathing
run breathing_green

Sequences~

color red = 0xFF0000
color blue = 0x0000FF

animation red_anim = solid(color=red)
animation blue_anim = solid(color=blue)

sequence demo {
  play red_anim for 2s
  wait 500ms
  play blue_anim for 2s
}
run demo

Multiple Strip Lengths~

strip length 60  # Must be first statement

color rainbow = rainbow_color_provider(period=5s)
animation rainbow_anim = solid(color=rainbow)
run rainbow_anim

Following these guidelines will help you avoid most common issues and create reliable LED animations.