Skip to content

Commit ec32b83

Browse files
authored
Berry animation improvements (#24162)
1 parent 07a1a98 commit ec32b83

31 files changed

+18034
-16965
lines changed

lib/libesp32/berry_animation/anim_examples/compiled/compilation_summary.md

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,26 @@ SUCCESS
377377
SUCCESS
378378
```
379379

380+
## demo_value_meter.anim
381+
382+
**Status:** ✅ Success
383+
384+
## Symbol Table
385+
386+
| Symbol | Type | Builtin | Dangerous | Takes Args |
387+
|---------------------------|----------------------------|---------|-----------|------------|
388+
| `back_pattern` | animation | | | |
389+
| `closure_value` | value_provider_constructor || ⚠️ ||
390+
| `palette_meter_animation` | animation_constructor || ⚠️ ||
391+
| `rainbow_with_white` | palette | | | |
392+
| `rand_meter` | user_function | | ||
393+
394+
### Compilation Output
395+
396+
```
397+
SUCCESS
398+
```
399+
380400
## disco_strobe.anim
381401

382402
**Status:** ✅ Success
@@ -702,34 +722,6 @@ SUCCESS
702722
SUCCESS
703723
```
704724

705-
## plasma_wave.anim
706-
707-
**Status:** ✅ Success
708-
709-
## Symbol Table
710-
711-
| Symbol | Type | Builtin | Dangerous | Takes Args |
712-
|--------------------------|----------------------------|---------|-----------|------------|
713-
| `SINE` | constant || | |
714-
| `beacon_animation` | animation_constructor || ⚠️ ||
715-
| `plasma_base` | animation | | | |
716-
| `plasma_colors` | palette | | | |
717-
| `plasma_wave1` | animation | | | |
718-
| `plasma_wave2` | animation | | | |
719-
| `plasma_wave3` | animation | | | |
720-
| `rich_palette_animation` | animation_constructor || ⚠️ ||
721-
| `rich_palette` | color_constructor || ⚠️ ||
722-
| `smooth` | value_provider_constructor || ⚠️ ||
723-
| `wave1_pattern` | color | | | |
724-
| `wave2_pattern` | color | | | |
725-
| `wave3_pattern` | color | | | |
726-
727-
### Compilation Output
728-
729-
```
730-
SUCCESS
731-
```
732-
733725
## palette_demo.anim
734726

735727
**Status:** ✅ Success
@@ -789,6 +781,34 @@ SUCCESS
789781
SUCCESS
790782
```
791783

784+
## plasma_wave.anim
785+
786+
**Status:** ✅ Success
787+
788+
## Symbol Table
789+
790+
| Symbol | Type | Builtin | Dangerous | Takes Args |
791+
|--------------------------|----------------------------|---------|-----------|------------|
792+
| `SINE` | constant || | |
793+
| `beacon_animation` | animation_constructor || ⚠️ ||
794+
| `plasma_base` | animation | | | |
795+
| `plasma_colors` | palette | | | |
796+
| `plasma_wave1` | animation | | | |
797+
| `plasma_wave2` | animation | | | |
798+
| `plasma_wave3` | animation | | | |
799+
| `rich_palette_animation` | animation_constructor || ⚠️ ||
800+
| `rich_palette` | color_constructor || ⚠️ ||
801+
| `smooth` | value_provider_constructor || ⚠️ ||
802+
| `wave1_pattern` | color | | | |
803+
| `wave2_pattern` | color | | | |
804+
| `wave3_pattern` | color | | | |
805+
806+
### Compilation Output
807+
808+
```
809+
SUCCESS
810+
```
811+
792812
## police_lights.anim
793813

794814
**Status:** ✅ Success
@@ -1236,8 +1256,8 @@ SUCCESS
12361256

12371257
## Summary
12381258

1239-
- **Total files processed:** 50
1240-
- **Successfully compiled:** 47
1259+
- **Total files processed:** 51
1260+
- **Successfully compiled:** 48
12411261
- **Failed to compile:** 3
12421262

12431263
### Successful Files
@@ -1257,6 +1277,7 @@ SUCCESS
12571277
- ✅ demo_shutter_rainbow_central.anim
12581278
- ✅ demo_shutter_rainbow_leftright.anim
12591279
- ✅ demo_shutter_rainbow2.anim
1280+
- ✅ demo_value_meter.anim
12601281
- ✅ disco_strobe.anim
12611282
- ✅ fire_flicker.anim
12621283
- ✅ heartbeat_pulse.anim
@@ -1267,9 +1288,9 @@ SUCCESS
12671288
- ✅ meteor_shower.anim
12681289
- ✅ neon_glow.anim
12691290
- ✅ ocean_waves.anim
1270-
- ✅ plasma_wave.anim
12711291
- ✅ palette_demo.anim
12721292
- ✅ palette_showcase.anim
1293+
- ✅ plasma_wave.anim
12731294
- ✅ police_lights.anim
12741295
- ✅ property_assignment_demo.anim
12751296
- ✅ rainbow_cycle.anim
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Generated Berry code from Animation DSL
2+
# Source: demo_value_meter.anim
3+
#
4+
# This file was automatically generated by compile_all_examples.sh
5+
# Do not edit manually - changes will be overwritten
6+
7+
import animation
8+
9+
# Pattern of colors in the background based on palette, rotating over 5 s
10+
# Auto-generated strip initialization (using Tasmota configuration)
11+
var engine = animation.init_strip()
12+
13+
# Berry code block
14+
15+
def rand_meter(time_ms, self)
16+
import math
17+
var r = math.rand() % 101
18+
return r
19+
end
20+
21+
# End berry code block
22+
# External function declaration: rand_meter
23+
animation.register_user_function("rand_meter", rand_meter)
24+
# define a palette of rainbow colors including white with constant brightness
25+
var rainbow_with_white_ = bytes(
26+
"FFFC0000" # Red
27+
"FFFF8000" # Orange
28+
"FFFFFF00" # Yellow
29+
"FF00FF00" # Green
30+
"FF00FFFF" # Cyan
31+
"FF0080FF" # Blue
32+
"FF8000FF" # Violet
33+
"FFCCCCCC" # White
34+
"FFFC0000" # Red - need to add the first color at last position to ensure roll-over
35+
)
36+
# define a gradient across the whole strip
37+
var back_pattern_ = animation.palette_meter_animation(engine)
38+
back_pattern_.value_func = animation.create_closure_value(engine, def (engine) return animation.get_user_function('rand_meter')(engine) end)
39+
engine.add(back_pattern_)
40+
engine.run()
41+
42+
43+
#- Original DSL source:
44+
# Pattern of colors in the background based on palette, rotating over 5 s
45+
46+
berry """
47+
def rand_meter(time_ms, self)
48+
import math
49+
var r = math.rand() % 101
50+
return r
51+
end
52+
"""
53+
54+
extern function rand_meter
55+
56+
# define a palette of rainbow colors including white with constant brightness
57+
palette rainbow_with_white = [
58+
0xFC0000 # Red
59+
0xFF8000 # Orange
60+
0xFFFF00 # Yellow
61+
0x00FF00 # Green
62+
0x00FFFF # Cyan
63+
0x0080FF # Blue
64+
0x8000FF # Violet
65+
0xCCCCCC # White
66+
0xFC0000 # Red - need to add the first color at last position to ensure roll-over
67+
]
68+
69+
# define a gradient across the whole strip
70+
animation back_pattern = palette_meter_animation(value_func = rand_meter)
71+
72+
run back_pattern
73+
74+
-#
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Pattern of colors in the background based on palette, rotating over 5 s
2+
3+
berry """
4+
def rand_meter(time_ms, self)
5+
import math
6+
var r = math.rand() % 101
7+
return r
8+
end
9+
"""
10+
11+
extern function rand_meter
12+
13+
# define a palette of rainbow colors including white with constant brightness
14+
palette rainbow_with_white = [
15+
0xFC0000 # Red
16+
0xFF8000 # Orange
17+
0xFFFF00 # Yellow
18+
0x00FF00 # Green
19+
0x00FFFF # Cyan
20+
0x0080FF # Blue
21+
0x8000FF # Violet
22+
0xCCCCCC # White
23+
0xFC0000 # Red - need to add the first color at last position to ensure roll-over
24+
]
25+
26+
# define a gradient across the whole strip
27+
animation back_pattern = palette_meter_animation(value_func = rand_meter)
28+
29+
run back_pattern

lib/libesp32/berry_animation/anim_tutorials/chap_1_33_color_pattern_spatial_rotate.anim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ palette rainbow_with_white = [
1313
0xFC0000 # Red - need to add the first color at last position to ensure roll-over
1414
]
1515

16-
# define a color attribute that cycles over time, cycle is 10 seconds
16+
# define a color attribute cycles color in space
1717
color rainbow_rich_color = rich_palette(palette=rainbow_with_white, cycle_period=0, transition_type=SINE)
1818

1919
# define a gradient across the whole strip

lib/libesp32/berry_animation/anim_tutorials/chap_1_40_color_pattern_meter.anim

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ def rand_meter(time_ms, self)
88
end
99
"""
1010
11+
extern function rand_meter
12+
1113
# define a palette of rainbow colors including white with constant brightness
1214
palette rainbow_with_white = [
1315
0xFC0000 # Red
@@ -21,7 +23,10 @@ palette rainbow_with_white = [
2123
0xFC0000 # Red - need to add the first color at last position to ensure roll-over
2224
]
2325
26+
# define a color attribute cycles color in space
27+
color rainbow_rich_color = rich_palette(palette=rainbow_with_white, cycle_period=0, transition_type=SINE)
28+
2429
# define a gradient across the whole strip
25-
animation back_pattern = palette_meter_animation(value_func = rand_meter)
30+
animation back_pattern = palette_meter_animation(color_source = rainbow_rich_color, value_func = rand_meter)
2631
2732
run back_pattern

lib/libesp32/berry_animation/docs/ANIMATION_CLASS_HIERARCHY.md

Lines changed: 33 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ ParameterizedObject (base class with parameter management and playable interface
2222
│ ├── BeaconAnimation (pulse at specific position)
2323
│ ├── CrenelPositionAnimation (crenel/square wave pattern)
2424
│ ├── BreatheAnimation (breathing effect)
25-
│ ├── PalettePatternAnimation (base for palette-based animations)
25+
│ ├── PaletteGradientAnimation (gradient patterns with palette colors)
26+
│ │ └── PaletteMeterAnimation (meter/bar patterns)
2627
│ ├── CometAnimation (moving comet with tail)
2728
│ ├── FireAnimation (realistic fire effect)
2829
│ ├── TwinkleAnimation (twinkling stars effect)
@@ -243,11 +244,11 @@ Generates oscillating values using various waveforms. Inherits from `ValueProvid
243244
| Parameter | Type | Default | Constraints | Description |
244245
|-----------|------|---------|-------------|-------------|
245246
| `min_value` | int | 0 | - | Minimum oscillation value |
246-
| `max_value` | int | 100 | - | Maximum oscillation value |
247+
| `max_value` | int | 255 | - | Maximum oscillation value |
247248
| `duration` | int | 1000 | min: 1 | Oscillation period in milliseconds |
248249
| `form` | int | 1 | enum: [1,2,3,4,5,6,7,8,9] | Waveform type |
249-
| `phase` | int | 0 | 0-100 | Phase shift percentage |
250-
| `duty_cycle` | int | 50 | 0-100 | Duty cycle for square/triangle waves |
250+
| `phase` | int | 0 | 0-255 | Phase shift in 0-255 range (mapped to duration) |
251+
| `duty_cycle` | int | 127 | 0-255 | Duty cycle for square/triangle waves in 0-255 range |
251252

252253
**Waveform Constants**:
253254
- `1` (SAWTOOTH) - Linear ramp from min to max
@@ -301,6 +302,18 @@ The ClosureValueProvider includes built-in mathematical helper methods that can
301302
- **Cosine Behavior**: Matches oscillator COSINE waveform (starts at minimum, not maximum)
302303
- **Scale Function**: Uses `tasmota.scale_int()` for efficient integer scaling
303304

305+
#### Closure Signature
306+
307+
Closures used with ClosureValueProvider must follow this signature:
308+
```berry
309+
def closure_func(engine, param_name, time_ms)
310+
# engine: AnimationEngine reference
311+
# param_name: Name of the parameter being computed
312+
# time_ms: Current time in milliseconds
313+
return computed_value
314+
end
315+
```
316+
304317
#### Usage in Computed Values
305318

306319
These methods are automatically available in DSL computed expressions:
@@ -1029,51 +1042,23 @@ animation strobe = wave_animation(
10291042

10301043

10311044

1032-
### PalettePatternAnimation
1045+
### PaletteGradientAnimation
10331046

1034-
Applies colors from a color provider to specific patterns using an efficient bytes() buffer. Inherits from `Animation`.
1047+
Creates shifting gradient patterns with palette colors. Inherits from `Animation`.
10351048

10361049
| Parameter | Type | Default | Constraints | Description |
10371050
|-----------|------|---------|-------------|-------------|
10381051
| `color_source` | instance | nil | - | Color provider for pattern mapping |
1039-
| `pattern_func` | function | nil | - | Function that generates pattern values (0-255) for each pixel |
1052+
| `shift_period` | int | 0 | min: 0 | Time for one complete shift cycle in ms (0 = static gradient) |
1053+
| `spatial_period` | int | 0 | min: 0 | Spatial period in pixels (0 = full strip length) |
1054+
| `phase_shift` | int | 0 | 0-255 | Phase shift in 0-255 range (mapped to spatial period) |
10401055
| *(inherits all Animation parameters)* | | | | |
10411056

10421057
**Implementation Details:**
10431058
- Uses `bytes()` buffer for efficient storage of per-pixel values
1044-
- Pattern function should return values in 0-255 range
10451059
- Color source receives values in 0-255 range via `get_color_for_value(value, time_ms)`
10461060
- Buffer automatically resizes when strip length changes
1047-
1048-
**Factory**: `animation.palette_pattern_animation(engine)`
1049-
1050-
### PaletteWaveAnimation
1051-
1052-
Creates sine wave patterns with palette colors. Inherits from `PalettePatternAnimation`.
1053-
1054-
| Parameter | Type | Default | Constraints | Description |
1055-
|-----------|------|---------|-------------|-------------|
1056-
| `wave_period` | int | 5000 | min: 1 | Wave animation period in ms |
1057-
| `wave_length` | int | 10 | min: 1 | Wave length in pixels |
1058-
| *(inherits all PalettePatternAnimation parameters)* | | | | |
1059-
1060-
**Pattern Generation:**
1061-
- Generates sine wave values in 0-255 range using `tasmota.sine_int()`
1062-
- Wave position advances based on `wave_period` timing
1063-
- Each pixel's value calculated as: `sine_value = tasmota.scale_int(sine_int(angle), -4096, 4096, 0, 255)`
1064-
1065-
**Factory**: `animation.palette_wave_animation(engine)`
1066-
1067-
### PaletteGradientAnimation
1068-
1069-
Creates shifting gradient patterns with palette colors. Inherits from `PalettePatternAnimation`.
1070-
1071-
| Parameter | Type | Default | Constraints | Description |
1072-
|-----------|------|---------|-------------|-------------|
1073-
| `shift_period` | int | 10000 | min: 0 | Time for one complete shift cycle in ms (0 = static gradient) |
1074-
| `spatial_period` | int | 0 | min: 0 | Spatial period in pixels (0 = full strip length) |
1075-
| `phase_shift` | int | 0 | 0-100 | Phase shift as percentage of spatial period |
1076-
| *(inherits all PalettePatternAnimation parameters)* | | | | |
1061+
- Optimized LUT (Lookup Table) support for color providers
10771062

10781063
**Pattern Generation:**
10791064
- Generates linear gradient values in 0-255 range across the specified spatial period
@@ -1084,23 +1069,27 @@ Creates shifting gradient patterns with palette colors. Inherits from `PalettePa
10841069
- `0`: Gradient spans the full strip length (single gradient across entire strip)
10851070
- `> 0`: Gradient repeats every N pixels
10861071
- **phase_shift**: Shifts the gradient pattern spatially by a percentage of the spatial period
1087-
- Each pixel's value calculated as: `value = tasmota.scale_uint(spatial_position, 0, spatial_period-1, 0, 255)`
1072+
- Each pixel's value calculated using optimized fixed-point arithmetic
10881073

10891074
**Factory**: `animation.palette_gradient_animation(engine)`
10901075

10911076
### PaletteMeterAnimation
10921077

1093-
Creates meter/bar patterns based on a value function. Inherits from `PalettePatternAnimation`.
1078+
Creates meter/bar patterns based on a value function. Inherits from `PaletteGradientAnimation`.
10941079

10951080
| Parameter | Type | Default | Constraints | Description |
10961081
|-----------|------|---------|-------------|-------------|
1097-
| `value_func` | function | nil | - | Function that provides meter values (0-100 range) |
1098-
| *(inherits all PalettePatternAnimation parameters)* | | | | |
1082+
| `value_func` | function | nil | - | Function that provides meter values (0-255 range) |
1083+
| *(inherits all PaletteGradientAnimation parameters)* | | | | |
10991084

11001085
**Pattern Generation:**
1101-
- Value function returns percentage (0-100) representing meter level
1086+
- Value function signature: `value_func(engine, time_ms, self)` where:
1087+
- `engine`: AnimationEngine reference
1088+
- `time_ms`: Elapsed time since animation start
1089+
- `self`: Reference to the animation instance
1090+
- Value function returns value in 0-255 range representing meter level
11021091
- Pixels within meter range get value 255, others get value 0
1103-
- Meter position calculated as: `position = tasmota.scale_uint(value, 0, 100, 0, strip_length)`
1092+
- Meter position calculated as: `position = tasmota.scale_uint(value, 0, 255, 0, strip_length)`
11041093

11051094
**Factory**: `animation.palette_meter_animation(engine)`
11061095

0 commit comments

Comments
 (0)