Skip to content

Commit 225a3f3

Browse files
committed
Curtain RGB2040 tuning
Front-End ======== - Monitor: lightPreset_RGB2040 tuning Back-End ======= - Nodes: add LightPresetsEnum - Virtual layer: optimise lightPreset_RGB2040 in set/getLight, fix fastled_fadeToBlackBy , fastled_fill_solid, fastled_fill_rainbow
1 parent 1dadf47 commit 225a3f3

File tree

10 files changed

+11685
-11659
lines changed

10 files changed

+11685
-11659
lines changed

interface/src/routes/moonbase/monitor/Monitor.svelte

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,12 @@
5454
let offsetRGB: number;
5555
let offsetWhite: number;
5656
let isPositions: boolean = false;
57-
let lightPreset: number = 2;
57+
let lightPreset: number;
5858
let nrOfChannels: number = 0;
5959
// let offsetRed:number;
6060
// let offsetGreen:number;
6161
// let offsetBlue:number;
62+
const lightPreset_RGB2040 = 9;
6263
6364
const handleHeader = (header: Uint8Array) => {
6465
console.log('Monitor.handleHeader', header);
@@ -129,11 +130,11 @@
129130
done = true;
130131
}
131132
clearColors();
132-
let rgb2040 = lightPreset == 13;
133+
const groupSize = 20 * channelsPerLight; // RGB2040 groups: 20 lights per physical group (will be 3 channelsPerLight)
133134
//max size supported is 255x255x255 (index < width * height * depth) ... todo: only any of the component < 255
134135
for (let index = 0; index < nrOfChannels; index += channelsPerLight) {
135-
if (!rgb2040 || Math.floor(index / 60) % 2 == 0) {
136-
// RGB2040 Skip the empty channels
136+
if (lightPreset != lightPreset_RGB2040 || Math.floor(index / groupSize) % 2 == 0) {
137+
// Math.floor: RGB2040 Skip the empty channels
137138
// && index < width * height * depth
138139
const r = channels[index + offsetRGB + 0] / 255;
139140
const g = channels[index + offsetRGB + 1] / 255;

lib/framework/WWWData.h

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

platformio.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ build_flags =
5656
-D BUILD_TARGET=\"$PIOENV\"
5757
-D APP_NAME=\"MoonLight\" ; 🌙 Must only contain characters from [a-zA-Z0-9-_] as this is converted into a filename
5858
-D APP_VERSION=\"0.6.1\" ; semver compatible version string
59-
-D APP_DATE=\"2025121309\" ; 🌙
59+
-D APP_DATE=\"2025121511\" ; 🌙
6060

6161
-D PLATFORM_VERSION=\"pioarduino-55.03.34\" ; 🌙 make sure it matches with above plaftform
6262

src/MoonBase/Modules/ModuleIO.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
#include "MoonBase/Module.h"
1818

19-
enum IO_PinUsage {
19+
enum IO_PinUsageEnum {
2020
pin_Unused, // 0
2121
pin_LED,
2222
pin_LED_CW,
@@ -63,7 +63,7 @@ enum IO_PinUsage {
6363
pin_count
6464
};
6565

66-
enum IO_Boards {
66+
enum IO_BoardsEnum {
6767
board_none, //
6868
board_QuinLEDDigUnoV3,
6969
board_QuinLEDDigQuadV3,
@@ -275,7 +275,7 @@ class ModuleIO : public Module {
275275
if (boardID == board_SE16V1) {
276276
object["maxPower"] = 500;
277277
uint8_t ledPins[] = {47, 48, 21, 38, 14, 39, 13, 40, 12, 41, 11, 42, 10, 2, 3, 1}; // LED_PINS
278-
for (int i = 0; i < sizeof(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
278+
for (int i = 0; i < std::size(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
279279
pinAssigner.assignPin(0, pin_ButtonPush);
280280
pinAssigner.assignPin(45, pin_ButtonPush);
281281
pinAssigner.assignPin(46, pin_Button_LightsOn);
@@ -311,7 +311,7 @@ class ModuleIO : public Module {
311311
// esp32-d0 (4MB)
312312
object["maxPower"] = 150;
313313
uint8_t ledPins[] = {16, 3, 1, 4}; // LED_PINS
314-
for (int i = 0; i < sizeof(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
314+
for (int i = 0; i < std::size(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
315315
pinAssigner.assignPin(0, pin_ButtonPush);
316316

317317
pinAssigner.assignPin(15, pin_Relay);
@@ -325,7 +325,7 @@ class ModuleIO : public Module {
325325
// Dig-Octa-32-8L
326326
object["maxPower"] = 400; // 10A Fuse * 8 ... 400 W
327327
uint8_t ledPins[] = {0, 1, 2, 3, 4, 5, 12, 13}; // LED_PINS
328-
for (int i = 0; i < sizeof(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
328+
for (int i = 0; i < std::size(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
329329
pinAssigner.assignPin(33, pin_Relay);
330330
pinAssigner.assignPin(34, pin_ButtonPush);
331331
} else if (boardID == board_QuinLEDDig2Go) {
@@ -345,7 +345,7 @@ class ModuleIO : public Module {
345345
// pinAssigner.assignPin(xx, pin_I2S_MCLK);
346346
// } else if (boardID == board_QuinLEDPenta) {
347347
// uint8_t ledPins[] = {14, 13, 12, 4, 2}; // LED_PINS
348-
// for (int i = 0; i < sizeof(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
348+
// for (int i = 0; i < std::size(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
349349
// pinAssigner.assignPin(34, pin_ButtonPush);
350350
// pinAssigner.assignPin(35, pin_ButtonPush);
351351
// pinAssigner.assignPin(39, pin_ButtonPush);
@@ -412,7 +412,7 @@ class ModuleIO : public Module {
412412
object["maxPower"] = 100; // Assuming decent LED power!!
413413
if (_state.data["jumper1"]) { // on
414414
uint8_t ledPins[] = {21, 20, 25, 5, 7, 23, 8, 27}; // 8 LED_PINS
415-
for (int i = 0; i < sizeof(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
415+
for (int i = 0; i < std::size(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
416416
// per default used as LED Pins
417417
pinAssigner.assignPin(3, pin_RS485);
418418
pinAssigner.assignPin(4, pin_RS485);
@@ -424,7 +424,7 @@ class ModuleIO : public Module {
424424
pinAssigner.assignPin(48, pin_Exposed);
425425
} else { // off - default
426426
uint8_t ledPins[] = {21, 20, 25, 5, 7, 23, 8, 27, 3, 22, 24, 4, 46, 47, 2, 48}; // 16 LED_PINS
427-
for (int i = 0; i < sizeof(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
427+
for (int i = 0; i < std::size(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
428428
}
429429
pinAssigner.assignPin(33, pin_I2S_SD);
430430
pinAssigner.assignPin(26, pin_I2S_WS);
@@ -435,7 +435,7 @@ class ModuleIO : public Module {
435435
} else if (boardID == board_TroyP4Nano) {
436436
object["maxPower"] = 10; // USB compliant
437437
uint8_t ledPins[] = {2, 3, 4, 5, 6, 20, 21, 22, 23, 26, 27, 32, 33, 36, 47, 48}; // LED_PINS
438-
for (int i = 0; i < sizeof(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
438+
for (int i = 0; i < std::size(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
439439
pinAssigner.assignPin(7, pin_I2C_SDA);
440440
pinAssigner.assignPin(8, pin_I2C_SCL);
441441
pinAssigner.assignPin(9, pin_Reserved); // I2S Sound Output Pin
@@ -462,12 +462,12 @@ class ModuleIO : public Module {
462462
// 54 is "C4 EN pin" so I guess we shouldn't fuck with that.
463463
} else if (boardID == board_AtomS3) {
464464
uint8_t ledPins[] = {5, 6, 7, 8}; // LED_PINS
465-
for (int i = 0; i < sizeof(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
465+
for (int i = 0; i < std::size(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
466466
} else if (boardID == board_Cube202010) {
467467
object["maxPower"] = 50;
468468
uint8_t ledPins[] = {22, 21, 14, 18, 5, 4, 2, 15, 13, 12}; // LED_PINS
469469
// char pins[80] = "2,3,4,16,17,18,19,21,22,23,25,26,27,32,33"; //(D0), more pins possible. to do: complete list.
470-
for (int i = 0; i < sizeof(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
470+
for (int i = 0; i < std::size(ledPins); i++) pinAssigner.assignPin(ledPins[i], pin_LED);
471471
} else { // default
472472
object["maxPower"] = 10; // USB compliant
473473
#ifdef CONFIG_IDF_TARGET_ESP32P4

src/MoonBase/Nodes.cpp

Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -352,14 +352,14 @@ void DriverNode::setup() {
352352
addControlValue("GBR");
353353
addControlValue("BRG");
354354
addControlValue("BGR");
355-
addControlValue("RGBW"); // e.g. 4 channel par/dmx light
356-
addControlValue("GRBW"); // rgbw LED eg. sk6812
357-
addControlValue("GRB6"); // some LED curtains
358-
addControlValue("RGBWYP"); // 6 channel par/dmx light with UV etc
359-
addControlValue("MHBeeEyes150W-15 🐺"); // 15 channels moving head, see https://moonmodules.org/MoonLight/moonlight/drivers/#art-net
360-
addControlValue("MHBeTopper19x15W-32 🐺"); // 32 channels moving head
361-
addControlValue("MH19x15W-24"); // 24 channels moving heads
362-
addControlValue("RGB2040"); // curtain 2040
355+
addControlValue("RGBW"); // e.g. 4 channel par/dmx light
356+
addControlValue("GRBW"); // rgbw LED eg. sk6812
357+
addControlValue("Curtain GRB6"); // some LED curtains
358+
addControlValue("Curtain RGB2040"); // curtain RGB2040
359+
addControlValue("Lightbar RGBWYP"); // 6 channel par/dmx light with UV etc
360+
addControlValue("MH BeeEyes 150W-15 🐺"); // 15 channels moving head, see https://moonmodules.org/MoonLight/moonlight/drivers/#art-net
361+
addControlValue("MH BeTopper 19x15W-32 🐺"); // 32 channels moving head
362+
addControlValue("MH 19x15W-24"); // 24 channels moving heads
363363
}
364364

365365
void DriverNode::loop() {
@@ -409,84 +409,78 @@ void DriverNode::onUpdate(const Char<20>& oldValue, const JsonObject& control) {
409409
header->resetOffsets();
410410

411411
switch (header->lightPreset) {
412-
case 0:
412+
case lightPreset_RGB:
413413
header->channelsPerLight = 3;
414414
header->offsetRed = 0;
415415
header->offsetGreen = 1;
416416
header->offsetBlue = 2;
417-
break; // RGB
418-
case 1:
417+
break;
418+
case lightPreset_RBG:
419419
header->channelsPerLight = 3;
420420
header->offsetRed = 0;
421421
header->offsetGreen = 2;
422422
header->offsetBlue = 1;
423-
break; // RBG
424-
case 2:
423+
break;
424+
case lightPreset_GRB:
425425
header->channelsPerLight = 3;
426426
header->offsetRed = 1;
427427
header->offsetGreen = 0;
428428
header->offsetBlue = 2;
429-
break; // GRB
430-
case 3:
429+
break;
430+
case lightPreset_GBR:
431431
header->channelsPerLight = 3;
432432
header->offsetRed = 2;
433433
header->offsetGreen = 0;
434434
header->offsetBlue = 1;
435-
break; // GBR
436-
case 4:
435+
break;
436+
case lightPreset_BRG:
437437
header->channelsPerLight = 3;
438438
header->offsetRed = 1;
439439
header->offsetGreen = 2;
440440
header->offsetBlue = 0;
441-
break; // BRG
442-
case 5:
441+
break;
442+
case lightPreset_BGR:
443443
header->channelsPerLight = 3;
444444
header->offsetRed = 2;
445445
header->offsetGreen = 1;
446446
header->offsetBlue = 0;
447-
break; // BGR
448-
case 6:
447+
break;
448+
case lightPreset_RGBW:
449449
header->channelsPerLight = 4;
450450
header->offsetRed = 0;
451451
header->offsetGreen = 1;
452452
header->offsetBlue = 2;
453453
header->offsetWhite = 3;
454-
break; // RGBW - Par Lights
455-
case 7:
454+
break;
455+
case lightPreset_GRBW:
456456
header->channelsPerLight = 4;
457457
header->offsetRed = 1;
458458
header->offsetGreen = 0;
459459
header->offsetBlue = 2;
460460
header->offsetWhite = 3;
461-
break; // GRBW - RGBW Leds
462-
case 8:
461+
break;
462+
case lightPreset_GRB6:
463463
header->channelsPerLight = 6;
464464
header->offsetRed = 1;
465465
header->offsetGreen = 0;
466466
header->offsetBlue = 2;
467-
break; // GRB6
468-
case 9:
469-
header->channelsPerLight = 6;
467+
break;
468+
case lightPreset_RGB2040:
469+
// RGB2040 uses standard RGB offsets but has special channel remapping
470+
// for dual-channel-group architecture (handled in VirtualLayer)
471+
header->channelsPerLight = 3;
470472
header->offsetRed = 0;
471473
header->offsetGreen = 1;
472474
header->offsetBlue = 2;
473-
header->offsetWhite = 3;
474-
break; // RGBWYP - 6 channel Par/DMX Lights with UV etc
475-
case 10: // MHBeTopper19x15W-32
476-
layer->layerP->lights.header.channelsPerLight = 32;
475+
break;
476+
case lightPreset_RGBWYP:
477+
header->channelsPerLight = 6;
477478
header->offsetRed = 0;
478479
header->offsetGreen = 1;
479480
header->offsetBlue = 2;
480-
layer->layerP->lights.header.offsetRGB = 9;
481-
layer->layerP->lights.header.offsetRGB1 = 13;
482-
layer->layerP->lights.header.offsetRGB2 = 17;
483-
layer->layerP->lights.header.offsetRGB3 = 24;
484-
layer->layerP->lights.header.offsetPan = 0;
485-
layer->layerP->lights.header.offsetTilt = 2;
486-
layer->layerP->lights.header.offsetZoom = 5;
487-
layer->layerP->lights.header.offsetBrightness = 6;
481+
header->offsetWhite = 3;
488482
break;
489-
case 11: // MHBeeEyes150W-15
483+
case lightPreset_MHBeeEyes150W15:
490484
layer->layerP->lights.header.channelsPerLight = 15; // set channels per light to 15 (RGB + Pan + Tilt + Zoom + Brightness)
491485
header->offsetRed = 0;
492486
header->offsetGreen = 1;
@@ -499,7 +493,21 @@ void DriverNode::onUpdate(const Char<20>& oldValue, const JsonObject& control) {
499493
layer->layerP->lights.header.offsetGobo = 5; // set offset for color wheel in DMX map
500494
layer->layerP->lights.header.offsetBrightness2 = 3; // set offset for color wheel brightness in DMX map } //BGR
501495
break;
502-
case 12: // MH19x15W-24
496+
case lightPreset_MHBeTopper19x15W32:
497+
layer->layerP->lights.header.channelsPerLight = 32;
498+
header->offsetRed = 0;
499+
header->offsetGreen = 1;
500+
header->offsetBlue = 2;
501+
layer->layerP->lights.header.offsetRGB = 9;
502+
layer->layerP->lights.header.offsetRGB1 = 13;
503+
layer->layerP->lights.header.offsetRGB2 = 17;
504+
layer->layerP->lights.header.offsetRGB3 = 24;
505+
layer->layerP->lights.header.offsetPan = 0;
506+
layer->layerP->lights.header.offsetTilt = 2;
507+
layer->layerP->lights.header.offsetZoom = 5;
508+
layer->layerP->lights.header.offsetBrightness = 6;
509+
break;
510+
case lightPreset_MH19x15W24:
503511
layer->layerP->lights.header.channelsPerLight = 24;
504512
header->offsetRed = 0;
505513
header->offsetGreen = 1;
@@ -512,12 +520,6 @@ void DriverNode::onUpdate(const Char<20>& oldValue, const JsonObject& control) {
512520
layer->layerP->lights.header.offsetRGB2 = 12;
513521
layer->layerP->lights.header.offsetZoom = 17;
514522
break;
515-
case 13: // curtain RGB2040
516-
header->channelsPerLight = 3;
517-
header->offsetRed = 0;
518-
header->offsetGreen = 1;
519-
header->offsetBlue = 2;
520-
break;
521523
}
522524

523525
EXT_LOGI(ML_TAG, "setLightPreset %d (cPL:%d, o:%d,%d,%d,%d)", header->lightPreset, header->channelsPerLight, header->offsetRed, header->offsetGreen, header->offsetBlue, header->offsetWhite);

src/MoonBase/Nodes.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@
1818
#include "MoonBase/Modules/ModuleIO.h" // Includes also Module.h but also enum IO_Pins
1919
#include "MoonLight/Layers/VirtualLayer.h" //VirtualLayer.h will include PhysicalLayer.h
2020

21+
enum LightPresetsEnum {
22+
lightPreset_RGB,
23+
lightPreset_RBG,
24+
lightPreset_GRB, // default WS2812
25+
lightPreset_GBR,
26+
lightPreset_BRG,
27+
lightPreset_BGR,
28+
lightPreset_RGBW, // e.g. 4 channel par/dmx light
29+
lightPreset_GRBW, // rgbw LED eg. sk6812
30+
lightPreset_GRB6, // some LED curtains
31+
lightPreset_RGB2040, // curtain 2040
32+
lightPreset_RGBWYP, // 6 channel par/dmx light with UV etc
33+
lightPreset_MHBeeEyes150W15, // 15 channels moving head, see https://moonmodules.org/MoonLight/moonlight/drivers/#art-net
34+
lightPreset_MHBeTopper19x15W32, // 32 channels moving head
35+
lightPreset_MH19x15W24, // 24 channels moving heads
36+
lightPreset_count
37+
};
38+
2139
#define NODE_METADATA_VIRTUALS() \
2240
const char* getName() const override { return name(); } \
2341
uint8_t getDim() const override { return dim(); } \

src/MoonLight/Layers/PhysicalLayer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ void PhysicalLayer::nextPin(uint8_t ledPinDIO) {
184184
}
185185
// ledsPerPin[i] is the first empty slot
186186
if (i < MAXLEDPINS) {
187-
ledsPerPin[i] = (lights.header.nrOfLights - prevNrOfLights) * ((lights.header.lightPreset == 13) ? 2 : 1); // RGB2040 has empty channels
187+
ledsPerPin[i] = (lights.header.nrOfLights - prevNrOfLights) * ((lights.header.lightPreset == lightPreset_RGB2040) ? 2 : 1); // RGB2040 has empty channels
188188
if (ledPinDIO != UINT8_MAX)
189189
ledPinsAssigned[i] = ledPinDIO; // override order
190190
else
@@ -198,7 +198,7 @@ void PhysicalLayer::nextPin(uint8_t ledPinDIO) {
198198
void PhysicalLayer::onLayoutPost() {
199199
if (pass == 1) {
200200
lights.header.size += Coord3D{1, 1, 1};
201-
lights.header.nrOfChannels = lights.header.nrOfLights * lights.header.channelsPerLight * ((lights.header.lightPreset == 13) ? 2 : 1); // RGB2040 has empty channels
201+
lights.header.nrOfChannels = lights.header.nrOfLights * lights.header.channelsPerLight * ((lights.header.lightPreset == lightPreset_RGB2040) ? 2 : 1); // RGB2040 has empty channels
202202
EXT_LOGD(ML_TAG, "pass %d mp:%d #:%d / %d s:%d,%d,%d", pass, monitorPass, lights.header.nrOfLights, lights.header.nrOfChannels, lights.header.size.x, lights.header.size.y, lights.header.size.z);
203203
// send the positions to the UI _socket_emit
204204
EXT_LOGD(ML_TAG, "positions stored (%d -> %d)", lights.header.isPositions, lights.header.nrOfLights ? 2 : 3);

src/MoonLight/Layers/PhysicalLayer.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class VirtualLayer; // Forward as PhysicalLayer refers back to VirtualLayer
2828
class Node; // Forward as PhysicalLayer refers back to Node
2929
class Modifier; // Forward as PhysicalLayer refers back to Modifier
3030

31+
// make changes to LightsHeader carefully as the alignment of this struct must be preserved as Monitor.svelte is depending on it
3132
struct LightsHeader {
3233
Coord3D size = Coord3D(16, 16, 1); // 0 max position of light, counted by onLayoutPre/Post and addLight. 12 bytes not 0,0,0 to prevent div0 eg in Octopus2D
3334
uint16_t nrOfLights = 256; // 12 nr of physical lights, counted by addLight
@@ -58,7 +59,7 @@ struct LightsHeader {
5859
uint8_t lightPreset; // 34, so we can deal with exceptional cases e.g. RGB2040
5960
// =============
6061
// 35 bytes total
61-
uint8_t fill[5]; //->37 max (prime number)!!! needed so pack up until 40
62+
uint8_t fill[5]; // padding to align struct to 40 bytes total. lightsControl will send 37 bytes (prime number)!!! so Monitor.svelte can recognize this
6263
// support for more channels, like white, pan, tilt etc.
6364

6465
void resetOffsets() {
@@ -78,7 +79,7 @@ struct LightsHeader {
7879
offsetRGB2 = UINT8_MAX;
7980
offsetRGB3 = UINT8_MAX;
8081
offsetBrightness2 = UINT8_MAX;
81-
// lightPreset = 2; // don't reset as managed by Drivers
82+
// lightPreset = lightPreset_GRB; // don't reset as managed by Drivers
8283
nrOfChannels = 0;
8384
memset(fill, 0, sizeof(fill)); // set to 0
8485
}

0 commit comments

Comments
 (0)