1414
1515#if FT_MOONLIGHT == 1
1616
17- #include " Module.h"
18- #include " Leds.h"
19-
2017#undef TAG
2118#define TAG " 💫"
2219
2320#include " FastLED.h"
24- #define MAXLEDS 8192
21+
22+ #include " Module.h"
23+ #include " PhysicalLayer.h"
2524
2625#if FT_LIVESCRIPT
2726 #include " ESPLiveScript.h" // note: contains declarations AND definitions, therefore can only be included once!
3029class ModuleAnimations ;
3130static ModuleAnimations *gAnimations = nullptr ;
3231
33- LedsModel ledsModel;
34- static void _addPixel (uint16_t x, uint16_t y, uint16_t z) {ledsModel.addPixel (x, y, z);}
32+ PhysicalLayer layerP;
3533
34+ static void _addPin (uint8_t pinNr) {layerP.addPin (pinNr);}
35+ static void _addPixelsPre () {layerP.addPixelsPre ();}
36+ static void _addPixel (uint16_t x, uint16_t y, uint16_t z) {layerP.addPixel ({x, y, z});}
37+ static void _addPixelsPost () {layerP.addPixelsPost ();}
3638
3739class ModuleAnimations : public Module
3840{
3941public:
4042
41- CRGB leds[MAXLEDS];
42- uint16_t nrOfLeds = 256 ;
4343 #if FT_LIVESCRIPT
4444 Parser parser = Parser();
4545 #endif
@@ -89,6 +89,12 @@ class ModuleAnimations : public Module
8989
9090 property = root.add <JsonObject>(); property[" name" ] = " lightsOn" ; property[" type" ] = " checkbox" ; property[" default" ] = true ;
9191 property = root.add <JsonObject>(); property[" name" ] = " brightness" ; property[" type" ] = " range" ; property[" min" ] = 0 ; property[" max" ] = 255 ; property[" default" ] = 10 ;
92+ property = root.add <JsonObject>(); property[" name" ] = " red" ; property[" type" ] = " range" ; property[" min" ] = 0 ; property[" max" ] = 255 ; property[" default" ] = 10 ;
93+ property = root.add <JsonObject>(); property[" name" ] = " green" ; property[" type" ] = " range" ; property[" min" ] = 0 ; property[" max" ] = 255 ; property[" default" ] = 10 ;
94+ property = root.add <JsonObject>(); property[" name" ] = " blue" ; property[" type" ] = " range" ; property[" min" ] = 0 ; property[" max" ] = 255 ; property[" default" ] = 10 ;
95+ property = root.add <JsonObject>(); property[" name" ] = " preset" ; property[" type" ] = " select" ; property[" default" ] = " solid" ; values = property[" values" ].to <JsonArray>();
96+ values.add (" Preset1" );
97+ values.add (" Preset2" );
9298 property = root.add <JsonObject>(); property[" name" ] = " driverOn" ; property[" type" ] = " checkbox" ; property[" default" ] = true ;
9399 property = root.add <JsonObject>(); property[" name" ] = " pin" ; property[" type" ] = " select" ; property[" default" ] = 2 ; values = property[" values" ].to <JsonArray>();
94100 values.add (" 2" );
@@ -97,11 +103,13 @@ class ModuleAnimations : public Module
97103 property = root.add <JsonObject>(); property[" name" ] = " nodes" ; property[" type" ] = " array" ; details = property[" n" ].to <JsonArray>();
98104 {
99105 property = details.add <JsonObject>(); property[" name" ] = " animation" ; property[" type" ] = " selectFile" ; property[" default" ] = " Random" ; values = property[" values" ].to <JsonArray>();
106+ values.add (" Solid" );
100107 values.add (" Random" );
101108 values.add (" Sinelon" );
102109 values.add (" Rainbow" );
103110 values.add (" Sinus" );
104111 values.add (" Lissajous" );
112+ values.add (" Lines" );
105113 // find all the .sc files on FS
106114 File rootFolder = ESPFS.open (" /" );
107115 walkThroughFiles (rootFolder, [&](File folder, File file) {
@@ -117,7 +125,6 @@ class ModuleAnimations : public Module
117125 values.add (" Effect" );
118126 values.add (" Modifier" );
119127 values.add (" Driver show" );
120- property = details.add <JsonObject>(); property[" name" ] = " size" ; property[" type" ] = " number" ; property[" default" ] = 85 ;
121128 property = details.add <JsonObject>(); property[" name" ] = " error" ; property[" type" ] = " text" ; property[" ro" ] = true ;
122129 property = details.add <JsonObject>(); property[" name" ] = " controls" ; property[" type" ] = " array" ; details = property[" n" ].to <JsonArray>();
123130 {
@@ -146,40 +153,28 @@ class ModuleAnimations : public Module
146153 }
147154 }
148155
149- void removeLeds () {
150- // Turn off all LEDs
151- for (int i = 0 ; i < nrOfLeds; i++) {
152- leds[i] = CRGB::Black;
153- }
154- FastLED.show ();
155-
156- // Clear the FastLED configuration
157- FastLED.clear (true ); // Pass 'true' to reset internal FastLED data
158- ESP_LOGD (TAG, " LEDs removed and FastLED configuration reset." );
159- }
160-
161156 // implement business logic
162157 void onUpdate (UpdatedItem &updatedItem) override
163158 {
164- if (equal (updatedItem.name , " pin" )) {
159+ if (equal (updatedItem.name , " pin" ) || equal (updatedItem. name , " red " ) || equal (updatedItem. name , " green " ) || equal (updatedItem. name , " blue " ) ) {
165160 ESP_LOGD (TAG, " handle %s = %s -> %s" , updatedItem.name , updatedItem.oldValue .c_str (), updatedItem.value .as <String>().c_str ());
166161
167- removeLeds ();
168-
169- // In constructor so before onUpdate ...
170- switch (updatedItem.value .as <int >()) {
162+ // addLeds twice is temp hack to make rgb sliders work
163+ switch (_state.data [" pin" ].as <int >()) {
171164 case 2 :
172- FastLED.addLeds <WS2812B, 2 , GRB>(leds, 0 , nrOfLeds);
165+ FastLED.addLeds <WS2812B, 16 , GRB>(layerP.leds , 0 , layerP.nrOfLeds ).setCorrection (CRGB (_state.data [" red" ],_state.data [" green" ],_state.data [" blue" ]));
166+ FastLED.addLeds <WS2812B, 2 , GRB>(layerP.leds , 0 , layerP.nrOfLeds ).setCorrection (CRGB (_state.data [" red" ],_state.data [" green" ],_state.data [" blue" ]));
173167 break ;
174168 case 16 :
175- FastLED.addLeds <WS2812B, 16 , GRB>(leds, 0 , nrOfLeds);
169+ FastLED.addLeds <WS2812B, 2 , GRB>(layerP.leds , 0 , layerP.nrOfLeds ).setCorrection (CRGB (_state.data [" red" ],_state.data [" green" ],_state.data [" blue" ]));
170+ FastLED.addLeds <WS2812B, 16 , GRB>(layerP.leds , 0 , layerP.nrOfLeds ).setCorrection (CRGB (_state.data [" red" ],_state.data [" green" ],_state.data [" blue" ]));
176171 break ;
177172 default :
178- ESP_LOGD (TAG, " unknown pin %d" , updatedItem. value .as <int >());
173+ ESP_LOGD (TAG, " unknown pin %d" , _state. data [ " pin " ] .as <int >());
179174 }
180175 FastLED.setMaxPowerInMilliWatts (10000 ); // 5v, 2000mA, to protect usb while developing
181176 FastLED.setBrightness (_state.data [" lightsOn" ]?_state.data [" brightness" ]:0 );
182- ESP_LOGD (TAG, " FastLED.addLeds n:%d" , nrOfLeds);
177+ ESP_LOGD (TAG, " FastLED.addLeds n:%d" , layerP. nrOfLeds );
183178 } else if (equal (updatedItem.name , " lightsOn" ) || equal (updatedItem.name , " brightness" )) {
184179 ESP_LOGD (TAG, " handle %s = %s -> %s" , updatedItem.name , updatedItem.oldValue .c_str (), updatedItem.value .as <String>().c_str ());
185180 FastLED.setBrightness (_state.data [" lightsOn" ]?_state.data [" brightness" ]:0 );
@@ -198,86 +193,22 @@ class ModuleAnimations : public Module
198193 ESP_LOGD (TAG, " no handle for %s = %s -> %s" , updatedItem.name , updatedItem.oldValue .c_str (), updatedItem.value .as <String>().c_str ());
199194 }
200195
201- // AI generated
202- void sinusEffect (CRGB* leds, uint16_t numLeds, uint8_t hueOffset = 0 , uint8_t brightness = 255 , uint16_t speed = 10 ) {
203- static uint16_t phase = 0 ; // Tracks the phase of the sine wave
204- // ESP_LOGD(TAG, "sinusEffect %d %d %d %d", numLeds, hueOffset, brightness, speed);
205-
206- for (uint16_t i = 0 ; i < numLeds; i++) {
207- // Calculate the sine wave value for the current LED
208- uint8_t wave = sin8 ((i * 255 / numLeds) + phase);
209-
210- // Map the sine wave value to a color hue
211- uint8_t hue = wave + hueOffset;
212-
213- // Set the LED color using the calculated hue
214- leds[i] = CHSV (hue, 255 , brightness);
215- }
216-
217- // Increment the phase to animate the wave
218- phase += speed;
219- }
220-
221196 // run effects
222197 void loop ()
223198 {
224199 bool showLeds = false ;
225200
226201 for (JsonObject node: _state.data [" nodes" ].as <JsonArray>()) {
227- String animation = node[" animation" ];
228202 // select the right effect
229- if (animation == " Random" ) {
230- fadeToBlackBy (leds, nrOfLeds, 70 );
231- leds[random16 (nrOfLeds)] = CRGB (255 , random8 (), 0 );
232- showLeds = true ;
233- } else if (animation == " Sinelon" ) {
234- fadeToBlackBy (leds, nrOfLeds, 20 );
235- uint8_t bpm = 60 ;
236- int pos = beatsin16 ( bpm, 0 , 255 );
237- leds[pos] += CHSV ( millis ()/50 , 255 , 255 ); // = CRGB(255, random8(), 0);
238- showLeds = true ;
239- } else if (animation == " Rainbow" ) {
240- static uint8_t hue = 0 ;
241- fill_rainbow (leds, nrOfLeds, hue++, 7 );
242- showLeds = true ;
243- } else if (animation == " Sinus" ) {
244- fadeToBlackBy (leds, nrOfLeds, 70 );
245- sinusEffect (leds, nrOfLeds, millis () / 10 , 255 , 5 );
246- showLeds = true ;
247- } else if (animation == " Lissajous" ) {
248-
249- uint8_t xFrequency = 64 ;// = leds.effectControls.read<uint8_t>();
250- uint8_t fadeRate = 128 ;// = leds.effectControls.read<uint8_t>();
251- uint8_t speed = 128 ;// = leds.effectControls.read<uint8_t>();
252- CRGBPalette16 palette = PartyColors_p;
253-
254- EffectNode leds;
255-
256- leds.fadeToBlackBy (fadeRate);
257- uint_fast16_t phase = millis () * speed / 256 ; // allow user to control rotation speed, speed between 0 and 255!
258- Coord3D locn = {0 ,0 ,0 };
259- for (int i=0 ; i < 256 ; i ++) {
260- // WLEDMM: stick to the original calculations of xlocn and ylocn
261- locn.x = sin8 (phase/2 + (i*xFrequency)/64 );
262- locn.y = cos8 (phase/2 + i*2 );
263- locn.x = (leds.size .x < 2 ) ? 1 : (::map (2 *locn.x , 0 ,511 , 0 ,2 *(leds.size .x -1 )) +1 ) /2 ; // softhack007: "*2 +1" for proper rounding
264- // leds.setPixelColor((uint8_t)xlocn, (uint8_t)ylocn, leds.color_from_palette(sys->now/100+i, false, PALETTE_SOLID_WRAP, 0));
265- // leds[locn] = ColorFromPalette(leds.palette, sys->now/100+i);
266- // leds.setPixelColorPal(locn, millis()/100+i);
267- leds.setPixelColor (locn, ColorFromPalette (palette, millis ()/100 +i, 255 ));
268- }
269- showLeds = true ;
270- } else {
271- // Done by live script (Yves)
272- }
203+ showLeds |= layerP.effectFrame (node[" animation" ]);
273204 }
274205
275206 // show connected clients on the led display
276207 // static uint8_t lastConnectedClients = 0;
277208 // if (_socket->getConnectedClients() == 0) lastConnectedClients++;
278209 for (int i = 0 ; i < _socket->getConnectedClients (); i++) {
279210 // ESP_LOGD(TAG, "socket %d", i);
280- leds[i] = CRGB (0 , 0 , 128 );
211+ layerP. leds [i] = CRGB (0 , 0 , 128 );
281212 }
282213
283214 // Serial.printf(" %s", animation.c_str());
@@ -370,25 +301,38 @@ class ModuleAnimations : public Module
370301
371302 gAnimations = this ;
372303 if (equal (type, " Effect" )) {
373- addExternalVariable (" leds" , " CRGB *" , " " , (void *)leds);
304+ addExternalVariable (" leds" , " CRGB *" , " " , (void *)layerP. leds );
374305 // addExternalFunction("fadeToBlackBy", "void", "uint8_t", (void *)fadeToBlackBy_static);
375306 uint16_t (*_random16)(uint16_t )=random16; // enforce specific random16 function
376307 addExternalFunction (" random16" , " uint16_t" , " uint16_t" , (void *)_random16);
377308 addExternalFunction (" sin8" , " uint8_t" , " uint8_t" , (void *)sin8);
309+ scScript += " #define NUM_LEDS " + std::to_string (layerP.nrOfLeds ) + " \n " ; // NUM_LEDS is used in arrays -> must be define e.g. uint8_t rMapRadius[NUM_LEDS];
310+ // scScript += "void main(){setup();while(2>1){loop();sync();}}";
378311 } else if (equal (type, " Fixture definition" )) {
379- if (findLink (" addPixel" , externalType::function) == -1 )
380- addExternalFunction (" addPixel" , " void" , " uint16_t,uint16_t,uint16_t" , (void *)_addPixel);
312+ addExternalFunction (" addPin" , " void" , " uint8_t" , (void *)_addPin);
313+ addExternalFunction (" addPixelsPre" , " void" , " " , (void *)_addPixelsPre);
314+ addExternalFunction (" addPixel" , " void" , " uint16_t,uint16_t,uint16_t" , (void *)_addPixel);
315+ addExternalFunction (" addPixelsPost" , " void" , " " , (void *)_addPixelsPost);
316+ // scScript += "void main(){addPixelsPre();setup();addPixelsPost();}";
381317 }
382-
318+
383319 Executable executable = parser.parseScript (&scScript);
384320 executable.name = animation;
385321 ESP_LOGD (TAG, " parsing %s done\n " , animation);
386322 scriptRuntime.addExe (executable); // if already exists, delete it first
387323 ESP_LOGD (TAG, " addExe success %s\n " , executable.exeExist ?" true" :" false" );
388324
389- if (executable.exeExist )
390- executable.execute (" main" ); // background task (async - vs sync)
391- else
325+ if (executable.exeExist ) {
326+ if (equal (type, " Fixture definition" )) {
327+ executable.execute (" main" ); // background task (async - vs sync)
328+ // pass = 1;
329+ // liveM->executeTask(liveFixtureID, "c");
330+ // pass = 2;
331+ // liveM->executeTask(liveFixtureID, "c");
332+ }
333+ // if (equal(type, "Effect")) // not working yet!!!
334+ // executable.executeAsTask("main"); //background task (async - vs sync)
335+ } else
392336 ESP_LOGD (TAG, " error %s" , executable.error .error_message .c_str ());
393337
394338 for (asm_external el: external_links) {
0 commit comments