Skip to content

Commit a70996c

Browse files
committed
Live scripts as Node Part 2-2
Server ===== - ModuleDemo: add test buttons - ModuleAnimations: use liveScriptNode, add free, delete and execute buttons, loop1s: getScriptsJson, add findLiveScriptNode - Nodes: add cons/destructor, LiveScriptNode: add getScriptsJson, compileAndRun and kill functions - VirtualLayer: sPC/gPC using uint16_t
1 parent bdf7ade commit a70996c

File tree

11 files changed

+12860
-12775
lines changed

11 files changed

+12860
-12775
lines changed

docs/moonbase/modules.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ void setupDefinition(JsonArray root) override{
8383
if (updatedItem.value.as<String>().length())
8484
compileAndRun(updatedItem.value);
8585
} else
86-
ESP_LOGD(TAG, "no handle for %s = %s -> %s", updatedItem.name, updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
86+
ESP_LOGD(TAG, "no handle for %s.%s[%d] = %s -> %s", updatedItem.parent[0]?updatedItem.parent[0]:"", updatedItem.name, updatedItem.index[0], updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
8787
}
8888
```
8989

interface/src/routes/moonbase/module/Module.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@
122122
//loop over properties
123123
for (let key in newData) {
124124
if (typeof newData[key] != 'object') {
125-
// console.log("updateRecursive", key, newData[key], oldData);
126125
if (newData[key] != oldData[key]) {
126+
// console.log("updateRecursive", key, newData[key], oldData[key]);
127127
oldData[key] = newData[key]; //trigger reactiveness
128128
}
129129
} else {

lib/framework/WWWData.h

Lines changed: 12685 additions & 12681 deletions
Large diffs are not rendered by default.

src/MoonBase/ModuleDemo.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class ModuleDemo : public Module
2525
FilesService *filesService
2626
) : Module("demo", server, sveltekit, filesService) {
2727
ESP_LOGD(TAG, "constructor");
28-
}
28+
}
2929

3030
void setupDefinition(JsonArray root) override{
3131
ESP_LOGD(TAG, "");
@@ -51,6 +51,8 @@ class ModuleDemo : public Module
5151
property = details.add<JsonObject>(); property["name"] = "number"; property["type"] = "number"; property["default"] = 1000; property["min"] = 1000; property["max"] = 9999;
5252
property = details.add<JsonObject>(); property["name"] = "name"; property["type"] = "text"; property["default"] = "ewowi";
5353
property = details.add<JsonObject>(); property["name"] = "date"; property["type"] = "date"; property["default"] = "2025-03-21";
54+
property = details.add<JsonObject>(); property["name"] = "print"; property["type"] = "button";
55+
property = details.add<JsonObject>(); property["name"] = "credit"; property["type"] = "button";
5456
property = details.add<JsonObject>(); property["name"] = "lines"; property["type"] = "array"; details = property["n"].to<JsonArray>();
5557
{
5658
property = details.add<JsonObject>(); property["name"] = "service"; property["type"] = "text"; property["default"] = "consulting";
@@ -67,7 +69,7 @@ class ModuleDemo : public Module
6769

6870
void onUpdate(UpdatedItem &updatedItem) override
6971
{
70-
ESP_LOGD(TAG, "no handle for %s = %s -> %s", updatedItem.name, updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
72+
ESP_LOGD(TAG, "no handle for %s.%s[%d] = %s -> %s", updatedItem.parent[0]?updatedItem.parent[0]:"", updatedItem.name, updatedItem.index[0], updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
7173
}
7274

7375
void loop1s() {
@@ -78,7 +80,7 @@ class ModuleDemo : public Module
7880
newData["millis"] = millis()/1000;
7981

8082
JsonObject newDataObject = newData.as<JsonObject>();
81-
}
83+
_socket->emitEvent("demo", newDataObject);}
8284
};
8385

8486
#endif

src/MoonBase/ModuleInstances.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class ModuleInstances : public Module
6464

6565
void onUpdate(UpdatedItem &updatedItem) override
6666
{
67-
ESP_LOGD(TAG, "no handle for %s = %s -> %s", updatedItem.name, updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
67+
ESP_LOGD(TAG, "no handle for %s.%s[%d] = %s -> %s", updatedItem.parent[0]?updatedItem.parent[0]:"", updatedItem.name, updatedItem.index[0], updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
6868
}
6969

7070
void loop1s() {

src/MoonLight/ModuleAnimations.h

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ class ModuleAnimations : public Module
5656

5757
if (updatedItem == animation) {
5858
ESP_LOGD(TAG, "updateHandler updatedItem %s", updatedItem.c_str());
59-
compileAndRun(node["animation"], node["type"], node["error"]);
59+
LiveScriptNode *liveScriptNode = findLiveScriptNode(node["animation"]);
60+
if (liveScriptNode) liveScriptNode->compileAndRun();
6061
}
6162
}
6263
}
@@ -138,6 +139,9 @@ class ModuleAnimations : public Module
138139
property = details.add<JsonObject>(); property["name"] = "data_size"; property["type"] = "number"; property["ro"] = true;
139140
property = details.add<JsonObject>(); property["name"] = "error"; property["type"] = "text"; property["ro"] = true;
140141
property = details.add<JsonObject>(); property["name"] = "kill"; property["type"] = "button";
142+
property = details.add<JsonObject>(); property["name"] = "free"; property["type"] = "button";
143+
property = details.add<JsonObject>(); property["name"] = "delete"; property["type"] = "button";
144+
property = details.add<JsonObject>(); property["name"] = "execute"; property["type"] = "button";
141145
}
142146
}
143147

@@ -167,20 +171,40 @@ class ModuleAnimations : public Module
167171
ESP_LOGD(TAG, "handle %s = %s -> %s", updatedItem.name, updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
168172
FastLED.setBrightness(_state.data["lightsOn"]?_state.data["brightness"]:0);
169173
} else if (equal(updatedItem.parent[0], "nodes") && (equal(updatedItem.name, "animation") || equal(updatedItem.name, "type"))) {
170-
animationsChanged = true;
171174
JsonVariant node = _state.data["nodes"][updatedItem.index[0]];
175+
animationsChanged = true;
172176
ESP_LOGD(TAG, "handle %s = %s -> %s", updatedItem.name, updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
173-
if (updatedItem.oldValue.length())
177+
if (updatedItem.oldValue.length()) {
174178
ESP_LOGD(TAG, "delete %s %s ...", updatedItem.name, updatedItem.oldValue.c_str());
175-
if (!node["animation"].isNull() && !node["type"].isNull())
176-
compileAndRun(node["animation"], node["type"], node["error"]);
177-
} else if (equal(updatedItem.parent[0], "scripts") && equal(updatedItem.name, "kill")) {
178-
ESP_LOGD(TAG, "handle %s[%d].%s = %s -> %s (%d)", updatedItem.parent[0], updatedItem.index[0], updatedItem.name, updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str(), updatedItem.oldValue.length());
179-
if (updatedItem.oldValue != "null") //do not run at boot!
180-
kill(updatedItem.index[0]);
179+
LiveScriptNode *liveScriptNode = findLiveScriptNode(node["animation"]);
180+
if (liveScriptNode) liveScriptNode->kill();
181+
else ESP_LOGW(TAG, "liveScriptNode not found %s", node["animation"].as<String>().c_str());
182+
}
183+
if (!node["animation"].isNull() && !node["type"].isNull()) {
184+
LiveScriptNode *liveScriptNode = findLiveScriptNode(node["animation"]); //todo: can be 2 nodes with the same name ...
185+
if (liveScriptNode) liveScriptNode->compileAndRun();
186+
// not needed as creating the node is already running it ...
187+
}
188+
} else if (equal(updatedItem.parent[0], "scripts")) {
189+
JsonVariant script = _state.data["scripts"][updatedItem.index[0]];
190+
ESP_LOGD(TAG, "handle %s[%d]%s.%s = %s -> %s", updatedItem.parent[0], updatedItem.index[0], script["name"].as<String>().c_str(), updatedItem.name, updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
191+
if (updatedItem.oldValue != "null") {//do not run at boot!
192+
LiveScriptNode *liveScriptNode = findLiveScriptNode(script["name"]);
193+
if (liveScriptNode) {
194+
if (equal(updatedItem.name, "kill"))
195+
liveScriptNode->kill();
196+
if (equal(updatedItem.name, "free"))
197+
liveScriptNode->free();
198+
if (equal(updatedItem.name, "delete"))
199+
liveScriptNode->killAndDelete();
200+
if (equal(updatedItem.name, "execute"))
201+
liveScriptNode->execute();
202+
// updatedItem.value = 0;
203+
} else ESP_LOGW(TAG, "liveScriptNode not found %s", script["name"].as<String>().c_str());
204+
}
181205
}
182206
// else
183-
// ESP_LOGD(TAG, "no handle for %s = %s -> %s", updatedItem.name, updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
207+
// ESP_LOGD(TAG, "no handle for %s.%s[%d] = %s -> %s", updatedItem.parent[0]?updatedItem.parent[0]:"", updatedItem.name, updatedItem.index[0], updatedItem.oldValue.c_str(), updatedItem.value.as<String>().c_str());
184208
}
185209

186210
//run effects
@@ -194,6 +218,7 @@ class ModuleAnimations : public Module
194218
//rebuild layerP->layerV->effects
195219
for (Node* node : layerP.layerV[0]->nodes) {
196220
ESP_LOGD(TAG, "delete effect %s", node->name());
221+
node->destructor();
197222
delete node;
198223
}
199224
layerP.layerV[0]->nodes.clear(); //remove all effects
@@ -229,10 +254,13 @@ class ModuleAnimations : public Module
229254

230255
JsonArray scripts = newData["scripts"].to<JsonArray>(); //to: remove old array
231256

232-
// liveScript.updateScripts(scripts); //update the scripts in the UI ...
257+
LiveScriptNode node;
258+
node.getScriptsJson(scripts);
233259

234260
//only if changed
235261
if (_state.data["scripts"] != newData["scripts"]) {
262+
// UpdatedItem updatedItem;
263+
// _state.compareRecursive("scripts", _state.data["scripts"], newData["scripts"], updatedItem); //compare and update
236264
_state.data["scripts"] = newData["scripts"]; //update without compareRecursive -> without handles
237265
JsonObject newDataObject = newData.as<JsonObject>();
238266
_socket->emitEvent("animations", newDataObject);
@@ -250,18 +278,21 @@ class ModuleAnimations : public Module
250278
}
251279
}
252280

253-
//ESPLiveScript functions
254-
//=======================
255-
256-
void compileAndRun(const char * animation, const char * type, JsonVariant error) {
281+
LiveScriptNode *findLiveScriptNode(const char *animation) {
282+
for (Node *node : layerP.layerV[0]->nodes) {
283+
// Check if the node is of type LiveScriptNode
257284

258-
259-
//stop UI spinner
260-
}
261-
262-
void kill(int index) {
263-
ESP_LOGD(TAG, "kill %d", index);
285+
if (equal(node->name(), "LiveScriptNode")) {
286+
LiveScriptNode *liveScriptNode = (LiveScriptNode *)node;
287+
if (equal(liveScriptNode->animation, animation)) {
288+
ESP_LOGD(TAG, "found %s", animation);
289+
return liveScriptNode;
290+
}
291+
}
292+
}
293+
return nullptr;
264294
}
295+
265296
}; // class ModuleAnimations
266297

267298
#endif

src/MoonLight/Nodes.cpp

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,16 @@
1616
#define USE_FASTLED //as ESPLiveScript.h calls hsv ! one of the reserved functions!!
1717
#include "ESPLiveScript.h"
1818

19-
PhysicalLayer *glayerP = nullptr;
2019
VirtualLayer *glayerV = nullptr;
2120

22-
static void _addPin(uint8_t pinNr) {glayerP->addPin(pinNr);}
23-
static void _addPixelsPre() {glayerP->addPixelsPre();}
24-
static void _addPixel(uint16_t x, uint16_t y, uint16_t z) {glayerP->addPixel({x, y, z});}
25-
static void _addPixelsPost() {glayerP->addPixelsPost();}
21+
static void _addPin(uint8_t pinNr) {glayerV->layerP->addPin(pinNr);}
22+
static void _addPixelsPre() {glayerV->layerP->addPixelsPre();}
23+
static void _addPixel(uint16_t x, uint16_t y, uint16_t z) {glayerV->layerP->addPixel({x, y, z});}
24+
static void _addPixelsPost() {glayerV->layerP->addPixelsPost();}
2625

2726
void _fadeToBlackBy(uint8_t fadeValue) { glayerV->fadeToBlackBy(fadeValue);}
28-
static void _sPC(uint16_t pixel, CRGB color) {glayerV->setPixelColor(pixel, color);} //setPixelColor with color
29-
static void _sCFP(uint16_t pixel, uint8_t index, uint8_t brightness) { glayerV->setPixelColor(pixel, ColorFromPalette(PartyColors_p, index, brightness));} //setPixelColor within palette
27+
static void _sPC(uint16_t pixel, CRGB color) {glayerV->setPixelColor(pixel, color);}
28+
static void _sCFP(uint16_t pixel, uint8_t index, uint8_t brightness) { glayerV->setPixelColor(pixel, ColorFromPalette(PartyColors_p, index, brightness));}
3029

3130
static float _triangle(float j) {return 1.0 - fabs(fmod(2 * j, 2.0) - 1.0);}
3231
static float _time(float j) {
@@ -120,13 +119,17 @@ void LiveScriptNode::setup() {
120119
ESP_LOGD(TAG, "elink %s %s %d", el.shortname.c_str(), el.name.c_str(), el.type);
121120
}
122121

122+
compileAndRun();
123+
}
124+
125+
void LiveScriptNode::compileAndRun() {
123126
runningPrograms.setFunctionToSync(sync);
124127

125128
//send UI spinner
126129

127130
//run the recompile not in httpd but in main loopTask (otherwise we run out of stack space)
128131
// runInLoopTask.push_back([&, animation, type, error] {
129-
ESP_LOGD(TAG, "compileAndRun %s %s", animation, type);
132+
ESP_LOGD(TAG, "%s %s", animation, scriptType);
130133
File file = ESPFS.open(animation);
131134
if (file) {
132135
Char<32> pre;
@@ -137,9 +140,9 @@ void LiveScriptNode::setup() {
137140
file.close();
138141

139142
const char * post = "";
140-
if (equal(type, "Effect")) {
143+
if (equal(scriptType, "Effect")) {
141144
post= "void main(){setup();while(2>1){loop();sync();}}"; //;
142-
} else if (equal(type, "Fixture definition")) {
145+
} else if (equal(scriptType, "Fixture definition")) {
143146
post = "void main(){addPixelsPre();setup();addPixelsPost();}";
144147
}
145148

@@ -158,26 +161,10 @@ void LiveScriptNode::setup() {
158161
scriptRuntime.addExe(executable); //if already exists, delete it first
159162
ESP_LOGD(TAG, "addExe success %s\n", executable.exeExist?"true":"false");
160163

161-
glayerP = layerV->layerP;
162-
glayerV = layerV;
164+
glayerV = layerV; //todo: this is not working well with multiple scripts running!!!
163165

164166
if (executable.exeExist) {
165-
if (equal(type, "Fixture definition")) {
166-
// executable.execute("main"); //background task (async - vs sync)
167-
scriptRuntime.execute(executable.name, "main"); //background task (async - vs sync)
168-
// pass = 1;
169-
// liveM->executeTask(liveFixtureID, "c");
170-
// pass = 2;
171-
// liveM->executeTask(liveFixtureID, "c");
172-
}
173-
if (equal(type, "Effect")) {
174-
// setup : create controls
175-
// executable.execute("setup");
176-
// send controls to UI
177-
// executable.executeAsTask("main"); //background task (async - vs sync)
178-
scriptRuntime.executeAsTask(executable.name, "main"); //background task (async - vs sync)
179-
//assert failed: xEventGroupSync event_groups.c:228 (uxBitsToWaitFor != 0)
180-
}
167+
execute();
181168
} else
182169
ESP_LOGD(TAG, "error %s", executable.error.error_message.c_str());
183170

@@ -190,6 +177,43 @@ void LiveScriptNode::setup() {
190177

191178
//stop UI spinner
192179
}
180+
void LiveScriptNode::kill() {
181+
ESP_LOGD(TAG, "%s", animation);
182+
scriptRuntime.kill(animation);
183+
// scriptRuntime.execute(animation, "main"); //todo: not working yet
184+
// scriptRuntime.free(animation);
185+
}
186+
187+
void LiveScriptNode::execute() {
188+
ESP_LOGD(TAG, "%s %s", animation, scriptType);
189+
if (equal(scriptType, "Fixture definition")) {
190+
// executable.execute("main"); //background task (async - vs sync)
191+
scriptRuntime.execute(animation, "main"); //background task (async - vs sync)
192+
// pass = 1;
193+
// liveM->executeTask(liveFixtureID, "c");
194+
// pass = 2;
195+
// liveM->executeTask(liveFixtureID, "c");
196+
}
197+
if (equal(scriptType, "Effect")) {
198+
// setup : create controls
199+
// executable.execute("setup");
200+
// send controls to UI
201+
// executable.executeAsTask("main"); //background task (async - vs sync)
202+
scriptRuntime.executeAsTask(animation, "main"); //background task (async - vs sync)
203+
//assert failed: xEventGroupSync event_groups.c:228 (uxBitsToWaitFor != 0)
204+
}
205+
}
206+
207+
208+
void LiveScriptNode::free() {
209+
ESP_LOGD(TAG, "%s", animation);
210+
scriptRuntime.free(animation);
211+
}
212+
213+
void LiveScriptNode::killAndDelete() {
214+
ESP_LOGD(TAG, "%s", animation);
215+
scriptRuntime.deleteExe(animation);
216+
};
193217

194218
void LiveScriptNode::loop() {
195219

@@ -199,4 +223,24 @@ void LiveScriptNode::loop() {
199223
// }
200224
}
201225

226+
void LiveScriptNode::getScriptsJson(JsonArray scripts) {
227+
for (Executable &exec: scriptRuntime._scExecutables) {
228+
exe_info exeInfo = scriptRuntime.getExecutableInfo(exec.name);
229+
JsonObject object = scripts.add<JsonObject>();
230+
object["name"] = exec.name;
231+
object["isRunning"] = exec.isRunning();
232+
object["isHalted"] = exec.isHalted;
233+
object["exeExist"] = exec.exeExist;
234+
object["handle"] = exec.__run_handle_index;
235+
object["binary_size"] = exeInfo.binary_size;
236+
object["data_size"] = exeInfo.data_size;
237+
object["error"] = exec.error.error_message;
238+
object["kill"] = 0;
239+
object["free"] = 0;
240+
object["delete"] = 0;
241+
object["execute"] = 0;
242+
// ESP_LOGD(TAG, "scriptRuntime exec %s r:%d h:%d, e:%d h:%d b:%d + d:%d = %d", exec.name.c_str(), exec.isRunning(), exec.isHalted, exec.exeExist, exec.__run_handle_index, exeInfo.binary_size, exeInfo.data_size, exeInfo.total_size);
243+
}
244+
}
245+
202246
#endif

src/MoonLight/Nodes.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ class Node {
2323
public:
2424
VirtualLayer *layerV = nullptr; //the virtual layer this effect is using
2525

26+
//C++ constructor and destructor are not inherited, so declare it as normal functions
27+
virtual void constructor(VirtualLayer *layerV) {
28+
this->layerV = layerV;
29+
}
30+
virtual void destructor() {
31+
//delete any allocated memory
32+
}
33+
2634
virtual const char * name() {return "noname";}
2735
virtual const char * tags() {return "";}
2836
virtual uint8_t dim() {return _1D;};
@@ -36,7 +44,7 @@ class Node {
3644
//projection
3745
virtual void addPixelsPre() {}
3846
virtual void addPixel(Coord3D &pixel) {} //not const as pixel is changed
39-
virtual void XYZ(Coord3D &pixel) {}
47+
virtual void XYZ(Coord3D &pixel) {} //modifies the pixel
4048
};
4149

4250
class SolidEffect: public Node {
@@ -246,11 +254,18 @@ class Node {
246254
const char * name() override {return "LiveScriptNode";}
247255

248256
const char *animation;
249-
const char *type;
257+
const char *scriptType; //fixdef, effect, projection, ...
250258

251259
void setup() override;
252-
253260
void loop() override;
261+
262+
void getScriptsJson(JsonArray scripts);
263+
264+
void compileAndRun();
265+
void kill();
266+
void free();
267+
void killAndDelete();
268+
void execute();
254269

255270
};
256271

0 commit comments

Comments
 (0)