Skip to content

Commit

Permalink
implement var sync (bri,fx,pal,pro), dmxchan, version, bri logarithmic
Browse files Browse the repository at this point in the history
general
- add logarithmic value to slider vars (used by brightness)
- add valChangedForInstancesTemp to trigger sync of values (temp)

index.js
- add linearToLogarithm and use in brightness
- remove target blank on url
- range: split input and change listener for ui and server update
- set instanceName as title
- if input value set, send input event so oninput is triggered

AppModLeds
- brightness logarithmic
- add dmxChannel WIP

SysModFiles: add delete button for files (WIP)

SysModNetwork: add rssi var

SysModSystem: Add version var + autoupdate

SysModUI: add linearToLogarithm for logarithmic sliders and add custom field to initVarAndUpdate (WIP)

SysModWeb: add addUpdate (WIP)

UserModInstances
- add AppData, SysData, WLEDSyncData
- implement var sync incl WLED
- add instance name
- add syncgroups
  • Loading branch information
ewowi committed Oct 23, 2023
1 parent 65da648 commit 9151869
Show file tree
Hide file tree
Showing 20 changed files with 1,586 additions and 1,230 deletions.
2 changes: 1 addition & 1 deletion data/index.htm
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
</script>
</head>
<body onload="onLoad()">
<h1>StarMod by MoonModules</h1>
<h1>StarMod by MoonModules 💫 <div id="instanceName"></div></h1>
<div class="container">
<div id="screenColumn0" class = "screenColumn">
</div>
Expand Down
59 changes: 42 additions & 17 deletions data/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,26 @@ function makeWS() {
}
}

function linearToLogarithm(json, value) {
if (value == 0) return 0;

var minp = json.min?json.min:0;
var maxp = json.max?json.max:255;

// The result should be between 100 an 10000000
var minv = minp?Math.log(minp):0;
var maxv = Math.log(maxp);

// calculate adjustment factor
var scale = (maxv-minv) / (maxp - minp);

let result = Math.exp(minv + scale*(value-minp));

console.log(json, minv, maxv, scale, result);

return Math.round(result);
}

function generateHTML(parentNode, json, rowNr = -1) {
// console.log("generateHTML", parentNode, json);
if (Array.isArray(json)) {
Expand Down Expand Up @@ -221,7 +241,7 @@ function generateHTML(parentNode, json, rowNr = -1) {

let valueNode = cE("a");
valueNode.setAttribute('href', json.value);
valueNode.setAttribute('target', "_blank");
// valueNode.setAttribute('target', "_blank"); //does not work well on mobile
valueNode.innerText = json.value;

if (rowNr == -1) {
Expand Down Expand Up @@ -263,21 +283,19 @@ function generateHTML(parentNode, json, rowNr = -1) {
valueNode.type = json.type;
valueNode.min = json.min?json.min:0;
valueNode.max = json.max?json.max:255; //range slider default 0..255
// valueNode.addEventListener('input', (event) => {console.log(json.type + " input", event);gId(json.id + "_rv").innerText = this.value;});
valueNode.disabled = json.ro;
if (json.value) valueNode.value = json.value;
//numerical ui value changes while draging the slider (oninput)
valueNode.addEventListener('input', (event) => {
gId(json.id + "_rv").innerText = event.target.value;
gId(json.id + "_rv").innerText = json.log?linearToLogarithm(json, event.target.value):event.target.value;
});
//server value changes after draging the slider (onchange)
valueNode.addEventListener('change', (event) => {
console.log(json.type + " change", event.target, json.id);
setInput(event.target);
});
rangeValueNode = cE("span");
rangeValueNode.id = json.id + "_rv"; //rangeValue
if (json.value) rangeValueNode.innerText = json.value;
if (json.value) rangeValueNode.innerText = json.log?linearToLogarithm(json, json.value):json.value;
} else {
//input types: text, search, tel, url, email, and password.

Expand Down Expand Up @@ -306,6 +324,8 @@ function generateHTML(parentNode, json, rowNr = -1) {
}
else {
if (json.max) valueNode.setAttribute('maxlength', json.max); //for text and textarea set max length valueNode.maxlength is not working for some reason
if (json.id == "serverName")
gId("instanceName").innerText = json.value;
}
}
} //not checkbox or button or range
Expand Down Expand Up @@ -386,7 +406,7 @@ function processUpdate(json) {
else { //uiFun or {variable:{label:value}}
for (var key of Object.keys(json)) {
if (key != "uiFun") { //was the request
if (gId(key)) {
if (gId(key)) { //is the key a var?
processVarNode(gId(key), key, json[key]);
}
else
Expand All @@ -400,7 +420,8 @@ function processVarNode(node, key, json) {
let overruleValue = false;

if (json.hasOwnProperty("label")) {
console.log("processUpdate label", key, json.label);
if (key != "insTbl") // tbd: table should not update
console.log("processVarNode label", key, json.label);
if (node.nodeName.toLocaleLowerCase() == "input" && node.type == "button") {
node.value = initCap(json.label);
}
Expand All @@ -416,7 +437,8 @@ function processVarNode(node, key, json) {
}
}
if (json.hasOwnProperty("comment")) {
console.log("processUpdate comment", key, json.comment);
if (key != "insTbl") // tbd: table should not update
console.log("processVarNode comment", key, json.comment);
// normal: <p><label><input id><comment></p>
// table or canvas <p><label><comment></p><canvas id>
// 1) if exist then replace else add
Expand All @@ -439,14 +461,14 @@ function processVarNode(node, key, json) {
commentNode.innerText = json.comment;
}
if (json.hasOwnProperty("select")) {
console.log("processUpdate select", key, json.select);
console.log("processVarNode select", key, json.select);
if (node.nodeName.toLocaleLowerCase() == "span") { //readonly. tbd: only the displayed value needs to be in the select
var index = 0;
for (var value of json.select) {
if (parseInt(node.textContent) == index) {
// console.log("processUpdate select1", value, node, node.textContent, index);
// console.log("processVarNode select1", value, node, node.textContent, index);
node.textContent = value; //replace the id by its value
// console.log("processUpdate select2", value, node, node.textContent, index);
// console.log("processVarNode select2", value, node, node.textContent, index);
overruleValue = true; //in this case we do not want the value set
}
index++;
Expand All @@ -473,7 +495,8 @@ function processVarNode(node, key, json) {

//find model info
let variable = findVar(key);
console.log("processUpdate table", key, variable, json.table);
if (key != "insTbl") // tbd: table should not update
console.log("processVarNode table", key, variable, json.table);

//add each row
let rowNr = 0;
Expand Down Expand Up @@ -511,7 +534,7 @@ function processVarNode(node, key, json) {
if (json.hasOwnProperty("value") && !overruleValue) { //after select, in case used
//hasOwnProperty needed to catch also boolean json.value when it is false
// if (key=="mdlEnabled" || key=="clIsFull" || key=="pin2")
// console.log("processUpdate value", key, json, json.value, node);
// console.log("processVarNode value", key, json, json.value, node);
if (node.nodeName.toLocaleLowerCase() == "span") //read only vars
node.textContent = json.value;
else if (node.nodeName.toLocaleLowerCase() == "a") { //url links
Expand All @@ -524,21 +547,23 @@ function processVarNode(node, key, json) {
else if (Array.isArray(json.value)) { //table column
let rowNr = 0;
for (let x of json.value) {
console.log(key, gId(key + "#" + rowNr), x);
// console.log(key, gId(key + "#" + rowNr), x);
if (gId(key + "#" + rowNr) && gId(key + "#" + rowNr).checked)
gId(key + "#" + rowNr).checked = x; //tbd support all types!!
rowNr++;
}
// node.checked = json.value;
} else //inputs
} else {//inputs
node.value = json.value;
node.dispatchEvent(new Event("input")); // triggers addEventListener('input',...). now only used for input type range (slider), needed e.g. for qlc+ input
}
}
if (json.hasOwnProperty("json")) { //json send html nodes cannot process, store in jsonValues array
console.log("processUpdate json", key, json.json, node);
console.log("processVarNode json", key, json.json, node);
jsonValues[key] = json.json;
}
if (json.hasOwnProperty("file")) { //json send html nodes cannot process, store in jsonValues array
console.log("processUpdate file", key, json.file, node);
console.log("processVarNode file", key, json.file, node);

//we need to send a request which the server can handle using request variable
let url = `http://${window.location.hostname}/file`;
Expand Down
17 changes: 12 additions & 5 deletions src/App/AppEffects.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/

#ifdef USERMOD_WLEDAUDIO
#include "User/UserModWLEDAudio.h"
#include "../User/UserModWLEDAudio.h"
#endif
#ifdef USERMOD_E131
#include "../User/UserModE131.h"
Expand Down Expand Up @@ -141,7 +141,7 @@ class RunningEffect: public Effect {
// ledsV[LedsV::nrOfLedsV -1 - pos2] = CHSV( gHue, 255, 192); //make sure the right physical leds get their value
}
bool controls(JsonObject parentVar) {
ui->initSlider(parentVar, "BPM", 60, 0, 255, false, [](JsonObject var) { //uiFun
ui->initSlider(parentVar, "BPM", 60, 0, 255, 0, false, [](JsonObject var) { //uiFun
web->addResponse(var["id"], "comment", "in BPM!");
});
ui->initSlider(parentVar, "fade", 128);
Expand Down Expand Up @@ -735,8 +735,15 @@ class GEQEffect:public Effect {

// Nice an effect can register it's own DMX channel, but not a fan of repeating the range and type of the param

e131mod->patchChannel(3, "fadeOut", 255); // TODO: add constant for name
e131mod->patchChannel(4, "ripple", 255);
#ifdef USERMOD_E131

if (e131mod->isEnabled) {
uint16_t dmxChannel = mdl->getValue("dmxChannel");
e131mod->patchChannel(dmxChannel + 3, "fadeOut", 255); // TODO: add constant for name
e131mod->patchChannel(dmxChannel + 4, "ripple", 255);
}

#endif

return true;
}
Expand Down Expand Up @@ -849,7 +856,7 @@ class Effects {
void loop(size_t index) {
now = millis(); //tbd timebase

effects[index]->loop();
effects[index%effects.size()]->loop();

call++;

Expand Down
40 changes: 30 additions & 10 deletions src/App/AppModLeds.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,23 @@ class AppModLeds:public Module {

parentVar = ui->initModule(parentVar, name);

ui->initSlider(parentVar, "bri", 5, 0, 255, false, [](JsonObject var) { //uiFun
//logarithmic slider (10)
ui->initSlider(parentVar, "bri", 5, 0, 255, 10, false, [](JsonObject var) { //uiFun
web->addResponse(var["id"], "label", "Brightness");
}, [](JsonObject var) { //chFun
uint8_t bri = var["value"];
FastLED.setBrightness(bri);
USER_PRINTF("Set Brightness to %d -> %d\n", var["value"].as<int>(), bri);

uint8_t result = linearToLogarithm(var, bri);

FastLED.setBrightness(result);

USER_PRINTF("Set Brightness to %d -> b:%d r:%d\n", var["value"].as<int>(), bri, result);
SysModUI::valChangedForInstancesTemp = true;
});

ui->initCanvas(parentVar, "pview", -1, false, [](JsonObject var) { //uiFun
web->addResponse(var["id"], "label", "Preview");
web->addResponse(var["id"], "comment", "Shows the preview");
web->addResponse(var["id"], "comment", "Shows the fixture");
// web->addResponse(var["id"], "comment", "Click to enlarge");
}, nullptr, [](JsonObject var, uint8_t* buffer) { //loopFun
// send leds preview to clients
Expand Down Expand Up @@ -82,6 +88,7 @@ class AppModLeds:public Module {
USER_PRINTF("%s Change %s to %d\n", "initSelect chFun", var["id"].as<const char *>(), fx);

doMap = effects.setEffect("fx", fx);
SysModUI::valChangedForInstancesTemp = true;
});

ui->initSelect(parentVar, "palette", 4, false, [](JsonObject var) { //uiFun.
Expand All @@ -107,7 +114,7 @@ class AppModLeds:public Module {
case 7: palette = HeatColors_p; break;
default: palette = PartyColors_p; break;
}

SysModUI::valChangedForInstancesTemp = true;
});

ui->initSelect(parentVar, "projection", 2, false, [](JsonObject var) { //uiFun.
Expand All @@ -123,6 +130,7 @@ class AppModLeds:public Module {

LedsV::projectionNr = var["value"];
doMap = true;
SysModUI::valChangedForInstancesTemp = true;
});

ui->initSelect(parentVar, "ledFix", 0, false, [](JsonObject var) { //uiFun
Expand Down Expand Up @@ -180,11 +188,23 @@ class AppModLeds:public Module {
});

#ifdef USERMOD_E131
e131mod->patchChannel(1, "bri", 255); //should be 256??
e131mod->patchChannel(2, "fx", effects.size());
// //add these temporary to test remote changing of this values do not crash the system
// e131mod->patchChannel(3, "projection", Projections::count);
// e131mod->patchChannel(4, "ledFix", 5); //assuming 5!!!
// if (e131mod->isEnabled) {
ui->initNumber(parentVar, "dmxChannel", 1, 1, 512, false, [](JsonObject var) { //uiFun
web->addResponse(var["id"], "comment", "First channel (bri, fx, palette + fx channels, total 5 now)");
}, [](JsonObject var) { //chFun
uint16_t dmxChannel = var["value"];
e131mod->patchChannel(dmxChannel + 0, "bri", 255); //should be 256??
e131mod->patchChannel(dmxChannel + 1, "fx", effects.size());
e131mod->patchChannel(dmxChannel + 2, "palette", 8); //tbd: calculate nr of palettes (from select)

ui->valChangedForInstancesTemp = true;
});
// //add these temporary to test remote changing of this values do not crash the system
// e131mod->patchChannel(3, "projection", Projections::count);
// e131mod->patchChannel(4, "ledFix", 5); //assuming 5!!!
// }
// else
// USER_PRINTF("Leds e131 not enabled\n");
#endif

effects.setup();
Expand Down
10 changes: 10 additions & 0 deletions src/Sys/SysModFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ void SysModFiles::setup() {
ui->initURL(tableVar, "flLink", nullptr, true, [](JsonObject var) { //uiFun
web->addResponse(var["id"], "label", "Show");
});
ui->initButton(tableVar, "flDel", "", false, [](JsonObject var) { //uiFun
web->addResponse(var["id"], "label", "Delete"); //table header title
}, [](JsonObject var) { //chFun
print->printJson("chFun", var); //not called yet for buttons...
//instead:
// processJson k:flDel r:6 (⌫ == ⌫ ? 1)
// we want an array for value but : {"id":"flDel","type":"button","ro":false,"o":23,"uiFun":25,"chFun":26,"value":"⌫"}
});

ui->initText(parentVar, "drsize", nullptr, 32, true, [](JsonObject var) { //uiFun
char details[32] = "";
Expand All @@ -69,6 +77,7 @@ void SysModFiles::setup() {
// ui->initURL(parentVar, "urlTest", "file/3DCube202005.json", true);

web->addUpload("/upload");
web->addUpdate("/update");

web->addFileServer("/file");

Expand Down Expand Up @@ -126,6 +135,7 @@ void SysModFiles::dirToJson(JsonArray array, bool nameOnly, const char * filter)
char urlString[32] = "file/";
strncat(urlString, file.name(), sizeof(urlString)-1);
row.add((char *)urlString); //create a copy!
row.add(""); //delete placeholder
}
// USER_PRINTF("FILE: %s %d\n", file.name(), file.size());
}
Expand Down
2 changes: 1 addition & 1 deletion src/Sys/SysModModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ JsonObject SysModModel::setValueP(const char * id, const char * format, ...) {
// size_t len = vprintf(format, args);
char value[128];
vsnprintf(value, sizeof(value)-1, format, args);
USER_PRINTF("%s\n", value);
// USER_PRINTF("%s\n", value);

va_end(args);

Expand Down
7 changes: 6 additions & 1 deletion src/Sys/SysModModules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ void SysModModules::setup() {
}
} else { //read array and set module enabled
for (bool isEnabled:var["value"].as<JsonArray>()) {
if (modules[rowNr]->isEnabled != isEnabled) {
if ((modules[rowNr]->isEnabled && !isEnabled) || (!modules[rowNr]->isEnabled && isEnabled)) {
USER_PRINTF(" mdlEnabled.chFun %d %s: %d->%d\n", rowNr, modules[rowNr]->name, modules[rowNr]->isEnabled, isEnabled);
modules[rowNr]->isEnabled = isEnabled;
modules[rowNr]->enabledChanged();
Expand All @@ -94,6 +94,11 @@ void SysModModules::loop() {
isConnected = true;
connectedChanged();
}
if (millis() - secondMillis >= 5000) {
secondMillis = millis();
USER_PRINTF("❤️"); //heartbeat
}

}

void SysModModules::add(Module* module) {
Expand Down
9 changes: 9 additions & 0 deletions src/Sys/SysModNetwork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,21 @@ void SysModNetwork::setup() {
ui->initText(parentVar, "nwstatus", nullptr, 32, true, [](JsonObject var) { //uiFun
web->addResponse(var["id"], "label", "Status");
});
ui->initText(parentVar, "rssi", nullptr, 32, true, [](JsonObject var) { //uiFun
web->addResponse(var["id"], "label", "Wifi signal");
});

USER_PRINT_FUNCTION("%s %s %s\n", __PRETTY_FUNCTION__, name, success?"success":"failed");
}

void SysModNetwork::loop() {
// Module::loop();
if (millis() - secondMillis >= 1000) {
secondMillis = millis();

mdl->setValueLossy("rssi", "%d dBm", WiFi.RSSI());
}

handleConnection();
}

Expand Down
6 changes: 3 additions & 3 deletions src/Sys/SysModPins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ void SysModPins::setup() {
buffer[3] = 10*10; //every 10 sec
});

ui->initCheckBox(parentVar, "pin2", true, false, nullptr, updateGPIO);
ui->initCheckBox(parentVar, "pin4");
ui->initCheckBox(parentVar, "pin33", true);
// ui->initCheckBox(parentVar, "pin2", true, false, nullptr, updateGPIO);
// ui->initCheckBox(parentVar, "pin4");
// ui->initCheckBox(parentVar, "pin33", true);

USER_PRINT_FUNCTION("%s %s %s\n", __PRETTY_FUNCTION__, name, success?"success":"failed");
}
Expand Down
Loading

0 comments on commit 9151869

Please sign in to comment.