Skip to content
2 changes: 1 addition & 1 deletion interface/src/routes/moonbase/monitor/Monitor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
// let offsetRed:number;
// let offsetGreen:number;
// let offsetBlue:number;
const lightPreset_RGB2040 = 9;
const lightPreset_RGB2040 = 10;

const handleHeader = (header: Uint8Array) => {
console.log('Monitor.handleHeader', header);
Expand Down
16 changes: 8 additions & 8 deletions lib/framework/WWWData.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <Arduino.h>
// index.html
const uint8_t ESP_SVELTEKIT_DATA_0[] = {
0x1F,0x8B,0x08,0x00,0xEC,0x05,0xA7,0x69,0x02,0xFF,0x85,0x52,0xB1,0x72,0xDC,0x20,
0x1F,0x8B,0x08,0x00,0xA2,0x43,0xA7,0x69,0x02,0xFF,0x85,0x52,0xB1,0x72,0xDC,0x20,
0x10,0xAD,0x75,0x5F,0x81,0xA9,0xEE,0x0A,0x41,0x93,0x22,0x63,0x83,0x9A,0xC4,0x9D,
0x3D,0xC9,0x4C,0xDC,0xB8,0xBA,0x41,0x62,0x4F,0x10,0x23,0x60,0x04,0xD2,0xF9,0xC6,
0xE3,0x3F,0xF0,0x0F,0xA4,0xCA,0x2F,0xE6,0x13,0x02,0x48,0x72,0x26,0x4D,0xD2,0xB0,
Expand Down Expand Up @@ -33,7 +33,7 @@ const uint8_t ESP_SVELTEKIT_DATA_0[] = {

// favicon.png
const uint8_t ESP_SVELTEKIT_DATA_1[] = {
0x1F,0x8B,0x08,0x00,0xEC,0x05,0xA7,0x69,0x02,0xFF,0x7D,0xBA,0x53,0x70,0x25,0x0C,
0x1F,0x8B,0x08,0x00,0xA2,0x43,0xA7,0x69,0x02,0xFF,0x7D,0xBA,0x53,0x70,0x25,0x0C,
0x13,0x2D,0x1A,0xDB,0xD9,0xC9,0xC4,0xB6,0x6D,0xDB,0xCE,0x44,0x13,0xDB,0xB6,0x93,
0x89,0x6D,0xDB,0xB6,0x6D,0x73,0xC7,0xE6,0xC4,0xB6,0xEF,0xF7,0xDF,0x87,0x7B,0xAB,
0xCE,0xC3,0xE9,0xAA,0xB5,0x56,0x63,0x55,0xF5,0x4B,0x3F,0x76,0x84,0x92,0x82,0x24,
Expand Down Expand Up @@ -747,7 +747,7 @@ const uint8_t ESP_SVELTEKIT_DATA_1[] = {

// manifest.json
const uint8_t ESP_SVELTEKIT_DATA_2[] = {
0x1F,0x8B,0x08,0x00,0xEC,0x05,0xA7,0x69,0x02,0xFF,0x1D,0x8D,0x4D,0x0E,0xC2,0x20,
0x1F,0x8B,0x08,0x00,0xA2,0x43,0xA7,0x69,0x02,0xFF,0x1D,0x8D,0x4D,0x0E,0xC2,0x20,
0x14,0x84,0xD7,0x70,0x0A,0xF2,0xD6,0x46,0x23,0xA9,0xFD,0x3B,0x83,0x9E,0xC0,0x18,
0x43,0x90,0x56,0x12,0x7C,0x34,0x40,0x0D,0xB5,0xE9,0xDD,0xE5,0x75,0x31,0x9B,0xF9,
0xBE,0xCC,0xAC,0x9C,0x01,0xAA,0x8F,0x81,0x5E,0xC0,0xCD,0x7B,0xBC,0xDA,0xF1,0x9D,
Expand All @@ -762,21 +762,21 @@ const uint8_t ESP_SVELTEKIT_DATA_2[] = {

// _app/version.json
const uint8_t ESP_SVELTEKIT_DATA_3[] = {
0x1F,0x8B,0x08,0x00,0xEC,0x05,0xA7,0x69,0x02,0xFF,0xAB,0x56,0x2A,0x4B,0x2D,0x2A,
0x1F,0x8B,0x08,0x00,0xA2,0x43,0xA7,0x69,0x02,0xFF,0xAB,0x56,0x2A,0x4B,0x2D,0x2A,
0xCE,0xCC,0xCF,0x53,0xB2,0x52,0x32,0x34,0x37,0x37,0x32,0x35,0x35,0x34,0x36,0x32,
0x34,0xB5,0x30,0x52,0xAA,0x05,0x00,0xA0,0x60,0xDB,0xE8,0x1B,0x00,0x00,0x00,
};

// _app/env.js
const uint8_t ESP_SVELTEKIT_DATA_4[] = {
0x1F,0x8B,0x08,0x00,0xEC,0x05,0xA7,0x69,0x02,0xFF,0x4B,0xAD,0x28,0xC8,0x2F,0x2A,
0x1F,0x8B,0x08,0x00,0xA2,0x43,0xA7,0x69,0x02,0xFF,0x4B,0xAD,0x28,0xC8,0x2F,0x2A,
0x51,0x48,0xCE,0xCF,0x2B,0x2E,0x51,0x48,0xCD,0x2B,0xB3,0xAD,0xAE,0x05,0x00,0x2C,
0x1E,0xAB,0xEF,0x13,0x00,0x00,0x00,
};

// _app/immutable/bundle.js
const uint8_t ESP_SVELTEKIT_DATA_5[] = {
0x1F,0x8B,0x08,0x00,0xEC,0x05,0xA7,0x69,0x02,0xFF,0xBC,0xBD,0x89,0x7A,0xDB,0x46,
0x1F,0x8B,0x08,0x00,0xA2,0x43,0xA7,0x69,0x02,0xFF,0xBC,0xBD,0x89,0x7A,0xDB,0x46,
0xD2,0x28,0xFA,0x2A,0x22,0x7F,0x1D,0x1E,0x20,0x6A,0xD1,0x92,0xED,0x64,0x1C,0xD0,
0x08,0x8F,0x77,0x3B,0xF1,0x16,0xDB,0x49,0xEC,0xD0,0x1C,0x05,0x22,0x9B,0x24,0x2C,
0xB2,0x41,0x03,0x4D,0x2D,0xA6,0x78,0x9F,0xE5,0x3E,0xCB,0x7D,0xB2,0x5B,0x4B,0x6F,
Expand Down Expand Up @@ -13740,7 +13740,7 @@ const uint8_t ESP_SVELTEKIT_DATA_5[] = {

// _app/immutable/assets/bundle.css
const uint8_t ESP_SVELTEKIT_DATA_6[] = {
0x1F,0x8B,0x08,0x00,0xEC,0x05,0xA7,0x69,0x02,0xFF,0xED,0x7D,0xDB,0xAE,0xE3,0xCA,
0x1F,0x8B,0x08,0x00,0xA2,0x43,0xA7,0x69,0x02,0xFF,0xED,0x7D,0xDB,0xAE,0xE3,0xCA,
0x72,0xD8,0x7B,0xBE,0x82,0x67,0x0E,0x16,0x66,0x71,0x0E,0xC9,0x11,0xA9,0xBB,0xE4,
0x19,0x6C,0x67,0xC3,0x46,0x0C,0xF8,0xD8,0x40,0xEC,0x04,0xB0,0x67,0x06,0x01,0x25,
0x51,0x12,0xCF,0x50,0xA2,0x4C,0x52,0xEB,0x32,0x8A,0xFC,0x9C,0xA7,0x3C,0x04,0x01,
Expand Down Expand Up @@ -14834,7 +14834,7 @@ const uint8_t ESP_SVELTEKIT_DATA_6[] = {

// _app/immutable/assets/logo.png
const uint8_t ESP_SVELTEKIT_DATA_7[] = {
0x1F,0x8B,0x08,0x00,0xEC,0x05,0xA7,0x69,0x02,0xFF,0x00,0x22,0x40,0xDD,0xBF,0x89,
0x1F,0x8B,0x08,0x00,0xA2,0x43,0xA7,0x69,0x02,0xFF,0x00,0x22,0x40,0xDD,0xBF,0x89,
0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52,0x00,
0x00,0x01,0x40,0x00,0x00,0x01,0x40,0x08,0x03,0x00,0x00,0x00,0xFA,0x4E,0x55,0x98,
0x00,0x00,0x03,0x00,0x50,0x4C,0x54,0x45,0x00,0x00,0x00,0x7D,0x75,0x8F,0xB9,0xC9,
Expand Down
2 changes: 1 addition & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ test_framework = doctest
; Override inherited [env] settings that are ESP32-specific
framework =
extra_scripts =
lib_deps =
lib_deps = ArduinoJson@>=7.0.0
lib_ignore = PsychicHttp, framework
build_src_filter = -<*> +<native_stub.cpp>
lib_compat_mode = off
Expand Down
268 changes: 268 additions & 0 deletions src/MoonBase/DriverNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
/**
@title MoonLight
@file DriverNode.cpp
@repo https://github.com/MoonModules/MoonLight, submit changes to this file as PRs
@Authors https://github.com/MoonModules/MoonLight/commits/main
@Doc https://moonmodules.org/MoonLight/moonlight/overview/
@Copyright © 2026 Github MoonLight Commit Authors
@license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
@license For non GPL-v3 usage, commercial licenses must be purchased. Contact us for more information.
**/

#if FT_MOONLIGHT

// #include "DriverNode.h" // Nodes.h will include it!
#include "Nodes.h"

#if HP_ALL_DRIVERS
I2SClocklessLedDriver ledsDriver;
#endif
Comment thread
ewowi marked this conversation as resolved.

void DriverNode::setup() {
addControl(layerP.lights.header.lightPreset, "lightPreset", "select");
addControlValue("RGB");
addControlValue("RBG");
addControlValue("GRB"); // default WS2812
addControlValue("GBR");
addControlValue("BRG");
addControlValue("BGR");
addControlValue("RGBW"); // e.g. 4 channel par/dmx light
addControlValue("GRBW"); // rgbw LED eg. sk6812
addControlValue("WRGB"); // rgbw ws2814 LEDs
addControlValue("Curtain GRB6"); // some LED curtains
addControlValue("Curtain RGB2040"); // curtain RGB2040
addControlValue("Lightbar RGBWYP"); // 6 channel par/dmx light with UV etc
addControlValue("MH BeeEyes 150W-15"); // 15 channels moving head, see https://moonmodules.org/MoonLight/moonlight/drivers/#art-net
addControlValue("MH BeTopper 19x15W-32"); // 32 channels moving head
addControlValue("MH 19x15W-24"); // 24 channels moving heads
}

void DriverNode::loop() {
LightsHeader* header = &layerP.lights.header;

// use ledsDriver LUT for super efficient leds dimming 🔥 (used by rgbwBufferMapping)

uint8_t brightness = (header->offsetBrightness == UINT8_MAX) ? header->brightness : 255; // set brightness to 255 if offsetBrightness is set (fixture will do its own brightness)

if (brightness != brightnessSaved || layerP.maxPower != maxPowerSaved) {
// Use FastLED for setMaxPowerInMilliWatts stuff, don't use if more then 8096 LEDs, decent power is assumed then! Also in case of Art-Net to HUB75 panels this calculation is not using the right mW per LED
uint8_t correctedBrightness = layerP.lights.header.nrOfLights > 8096 ? brightness : calculate_max_brightness_for_power_mW((CRGB*)&layerP.lights.channelsD, layerP.lights.header.nrOfLights, brightness, layerP.maxPower * 1000); // calculate_max_brightness_for_power_mW supports max 65K LEDs
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
// EXT_LOGD(ML_TAG, "setBrightness b:%d + p:%d -> cb:%d", brightness, layerP.maxPower, correctedBrightness);
ledsDriver.setBrightness(correctedBrightness);
brightnessSaved = brightness;
maxPowerSaved = layerP.maxPower;
}

#if HP_ALL_DRIVERS
if (savedColorCorrection.red != layerP.lights.header.red || savedColorCorrection.green != layerP.lights.header.green || savedColorCorrection.blue != layerP.lights.header.blue) {
ledsDriver.setGamma(layerP.lights.header.red / 255.0, layerP.lights.header.blue / 255.0, layerP.lights.header.green / 255.0, 1.0);
Comment thread
ewowi marked this conversation as resolved.
Outdated
// EXT_LOGD(ML_TAG, "setColorCorrection r:%d, g:%d, b:%d (%d %d %d)", layerP.lights.header.red, layerP.lights.header.green, layerP.lights.header.blue,
// savedColorCorrection.red, savedColorCorrection.green, savedColorCorrection.blue);
savedColorCorrection.red = layerP.lights.header.red;
savedColorCorrection.green = layerP.lights.header.green;
savedColorCorrection.blue = layerP.lights.header.blue;
}
#else // ESP32_LEDSDRIVER
CRGB correction;
uint8_t white;
ledsDriver.getColorCorrection(correction.red, correction.green, correction.blue, white);
if (correction.red != header->red || correction.green != header->green || correction.blue != header->blue) {
EXT_LOGD(ML_TAG, "setColorCorrection r:%d, g:%d, b:%d (%d %d %d)", header->red, header->green, header->blue, correction.red, correction.green, correction.blue);
ledsDriver.setColorCorrection(header->red, header->green, header->blue);
}
#endif
}

void DriverNode::onUpdate(const Char<20>& oldValue, const JsonObject& control) {
LightsHeader* header = &layerP.lights.header;

// EXT_LOGD(ML_TAG, "%s: %s ", control["name"].as<const char*>(), control["value"].as<String>().c_str());

if (control["name"] == "lightPreset") {
uint8_t oldChannelsPerLight = header->channelsPerLight;

header->resetOffsets();

switch (header->lightPreset) {
case lightPreset_RGB:
header->channelsPerLight = 3;
header->offsetRed = 0;
header->offsetGreen = 1;
header->offsetBlue = 2;
break;
case lightPreset_RBG:
header->channelsPerLight = 3;
header->offsetRed = 0;
header->offsetGreen = 2;
header->offsetBlue = 1;
break;
case lightPreset_GRB:
header->channelsPerLight = 3;
header->offsetRed = 1;
header->offsetGreen = 0;
header->offsetBlue = 2;
break;
case lightPreset_GBR:
header->channelsPerLight = 3;
header->offsetRed = 2;
header->offsetGreen = 0;
header->offsetBlue = 1;
break;
case lightPreset_BRG:
header->channelsPerLight = 3;
header->offsetRed = 1;
header->offsetGreen = 2;
header->offsetBlue = 0;
break;
case lightPreset_BGR:
header->channelsPerLight = 3;
header->offsetRed = 2;
header->offsetGreen = 1;
header->offsetBlue = 0;
break;
case lightPreset_RGBW:
header->channelsPerLight = 4;
header->offsetRed = 0;
header->offsetGreen = 1;
header->offsetBlue = 2;
header->offsetWhite = 3;
break;
case lightPreset_GRBW:
header->channelsPerLight = 4;
header->offsetRed = 1;
header->offsetGreen = 0;
header->offsetBlue = 2;
header->offsetWhite = 3;
break;
case lightPreset_WRGB:
header->channelsPerLight = 4;
header->offsetRed = 1;
header->offsetGreen = 2;
header->offsetBlue = 3;
header->offsetWhite = 0;
break;
case lightPreset_GRB6:
header->channelsPerLight = 6;
header->offsetRed = 1;
header->offsetGreen = 0;
header->offsetBlue = 2;
break;
case lightPreset_RGB2040:
// RGB2040 uses standard RGB offsets but has special channel remapping
// for dual-channel-group architecture (handled in VirtualLayer)
header->channelsPerLight = 3;
header->offsetRed = 0;
header->offsetGreen = 1;
header->offsetBlue = 2;
break;
case lightPreset_RGBWYP:
header->channelsPerLight = 6;
header->offsetRed = 0;
header->offsetGreen = 1;
header->offsetBlue = 2;
header->offsetWhite = 3;
break;
case lightPreset_MHBeeEyes150W15:
header->channelsPerLight = 15; // set channels per light to 15 (RGB + Pan + Tilt + Zoom + Brightness)
header->offsetRGBW = 10; // set offset for RGB lights in DMX map
header->offsetRed = 0;
header->offsetGreen = 1;
header->offsetBlue = 2;
header->offsetPan = 0;
header->offsetTilt = 1;
header->offsetZoom = 7;
header->offsetBrightness = 8; // set offset for brightness
header->offsetGobo = 5; // set offset for color wheel in DMX map
header->offsetBrightness2 = 3; // set offset for color wheel brightness in DMX map } //BGR
break;
case lightPreset_MHBeTopper19x15W32:
header->channelsPerLight = 32;
header->offsetRGBW = 9;
header->offsetRed = 0;
header->offsetGreen = 1;
header->offsetBlue = 2;
header->offsetRGBW1 = 13;
header->offsetRGBW2 = 17;
header->offsetRGBW3 = 24;
header->offsetPan = 0;
header->offsetTilt = 2;
header->offsetZoom = 5;
header->offsetBrightness = 6;
break;
case lightPreset_MH19x15W24:
header->channelsPerLight = 24;
header->offsetRGBW = 4;
header->offsetRed = 0;
header->offsetGreen = 1;
header->offsetBlue = 2;
header->offsetWhite = 3;
header->offsetPan = 0;
header->offsetTilt = 1;
header->offsetBrightness = 3;
header->offsetRGBW1 = 8;
header->offsetRGBW2 = 12;
header->offsetZoom = 17;
break;
default:
EXT_LOGW(ML_TAG, "Invalid lightPreset value: %d", header->lightPreset);
// Fall back to GRB (most common default)
header->lightPreset = lightPreset_GRB;
header->channelsPerLight = 3;
header->offsetRed = 1;
header->offsetGreen = 0;
header->offsetBlue = 2;
break;
}

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

// FASTLED_ASSERT(true, "oki");

#if HP_ALL_DRIVERS
#ifndef CONFIG_IDF_TARGET_ESP32P4
if (initDone) {
// ledsDriver.setOffsets(header->offsetRed, header->offsetGreen, header->offsetBlue, header->offsetWhite);

// if (oldChannelsPerLight != header->channelsPerLight)
// restartNeeded = true; //in case
}
#endif

#else // ESP32_LEDSDRIVER
if (ledsDriver.initLedsDone) {
ledsDriver.setOffsets(header->offsetRed, header->offsetGreen, header->offsetBlue, header->offsetWhite);

if (oldChannelsPerLight != header->channelsPerLight) restartNeeded = true; // in case
}
#endif

lightPresetSaved = true;
}
}

void DriverNode::rgbwBufferMapping(uint8_t* packetRGBChannel, uint8_t* lightsRGBChannel) {
// use ledsDriver.__rbg_map[0]; for super fast brightness and gamma correction! see secondPixel in ESP32-LedDriver!
// apply the LUT to the RGB channels !

uint8_t red = lightsRGBChannel[0];
uint8_t green = lightsRGBChannel[1];
uint8_t blue = lightsRGBChannel[2];
// extract White from RGB
if (layerP.lights.header.offsetWhite != UINT8_MAX) {
// if white is filled, use that and do not extract rgbw
uint8_t white = lightsRGBChannel[3];
if (!white) {
white = MIN(MIN(red, green), blue);
red -= white;
green -= white;
blue -= white;
}
packetRGBChannel[layerP.lights.header.offsetWhite] = ledsDriver.__white_map[white];
}

packetRGBChannel[layerP.lights.header.offsetRed] = ledsDriver.__red_map[red];
packetRGBChannel[layerP.lights.header.offsetGreen] = ledsDriver.__green_map[green];
packetRGBChannel[layerP.lights.header.offsetBlue] = ledsDriver.__blue_map[blue];
}

#endif // FT_MOONLIGHT
Loading
Loading