Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ ssl_certs/cacert.pem
/site
.DS_Store
*.bak
.idea
compile_commands.json
4 changes: 2 additions & 2 deletions docs/develop/nodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ This is the current list of supported lights ranging from 3 channels per light (
* GRBW: rgbw LED eg. SK6812
* GRB6: some LED curtains
* RGBWYP: 6 channel par/dmx light with UV etc
* MHBeeEyes150W-15 🐺: 15 channels moving head, see https://moonmodules.org/MoonLight/moonbase/module/drivers/#art-net
* MHBeTopper19x15W-32 🐺: 32 channels moving head
* MHBeeEyes150W-15: 15 channels moving head, see https://moonmodules.org/MoonLight/moonbase/module/drivers/#art-net
* MHBeTopper19x15W-32: 32 channels moving head
* MH19x15W-24: 24 channels moving heads

Based on the chosen value, the channels per light and the offsets will be set e.g. for GRB: header->channelsPerLight = 3; header->offsetRed = 1; header->offsetGreen = 0; header->offsetBlue = 2;. Drivers should not make this mapping, the code calling drivers should do.
Expand Down
2 changes: 1 addition & 1 deletion docs/moonlight/drivers.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Sends Lights in Art-Net compatible packages to an Art-Net controller specified b
**Controls**

* **Light preset**: See above.
* **Controller IPs**: The last segment of the IP address within your local network, of the hardware Art-Net controller. Add more IPs if you send to more than one controller, comma separated.
* **Controller IPs**: The last segment of the IP address within your local network, of the hardware Art-Net controller. Add more IPs if you send to more than one controller, comma separated or use a hyphen for a range of IPs.
* **Port**: The network port added to the IP address, 6454 is the default for Art-Net.
* **FPS Limiter**: set the max frames per second Art-Net packages are send out (also all the other nodes will run at this speed).
* Art-Net specs recommend about 44 FPS but higher framerates will work mostly (up to until ~130FPS tested)
Expand Down
2 changes: 2 additions & 0 deletions lib/framework/WiFiSettingsService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ void WiFiSettingsService::initWiFi()
{
WiFi.mode(WIFI_MODE_STA); // this is the default.

WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); // 🌙 from WLED-MM bugfix: ensure that all channels are scanned, and the strongest signal is used, see https://github.com/wled/WLED/pull/5351 and https://github.com/MoonModules/WLED-MM/commit/812c5ca31532c741cb45b83d856c102a37877ca4

// Disable WiFi config persistance and auto reconnect
#ifndef CONFIG_IDF_TARGET_ESP32P4
WiFi.persistent(false);
Expand Down
59 changes: 54 additions & 5 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ build_flags =
-D BUILD_TARGET=\"$PIOENV\"
-D APP_NAME=\"MoonLight\" ; 🌙 Must only contain characters from [a-zA-Z0-9-_] as this is converted into a filename
-D APP_VERSION=\"0.8.1\" ; semver compatible version string
-D APP_DATE=\"20260218\" ; 🌙
-D APP_DATE=\"20260221\" ; 🌙

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

Expand Down Expand Up @@ -116,7 +116,56 @@ build_flags =
; -D EVENT_USE_JSON=1 ; 💫 switch off for FT_MONITOR

-D NROF_END_POINTS=160 ; 💫 sets _server->config.max_uri_handlers. increase number of endpoints to 160, default is 120, one PsychicEndpoint is 56 bytes -> 8960 bytes


; -O2
; Speed optimization.
; On ESP32 (Xtensa), this aggressively inlines functions and expands templates,
; which can greatly increase function size.
; Large functions may exceed Xtensa's literal (l32r) range limits (±256 KB),
; causing "dangerous relocation: literal target out of range".
; In practice, -O2 is often NOT faster than -Os on ESP32 due to flash/i-cache effects.

-ffunction-sections
; Places each function in its own section.
; Required for --gc-sections to remove unused functions at link time.

-fdata-sections
; Same as above, but for global/static data.
; Allows unused data to be removed by the linker.

-Wl,--gc-sections
; Linker flag: removes unused functions and data.
; Essential for minimizing flash usage.
; Without this, unused library code stays in the final binary.

-fno-exceptions
; Disables C++ exception handling.
; Removes unwind tables and exception support code.
; HUGE flash savings (~10–20% typical on ESP32 projects).
; Must ensure no code throws or relies on try/catch.

; -fno-rtti
; Disables Run-Time Type Information (dynamic_cast, typeid).
; Only affects C++ compilation.
; If applied globally, C compiler emits a harmless warning.
; Flash savings are usually small unless dynamic_cast/typeid are used heavily.
; Most embedded projects see little to no gain.

; build_unflags =
; -frtti
; Removes explicit RTTI enable flag if framework forces it.
; In most Arduino/ESP32 setups this is unnecessary.

; -Os (not unflagged, so stays active)
; Default ESP-IDF / Arduino-ESP32 optimization level.
; Optimizes for size.
; Keeps functions smaller and avoids Xtensa literal pool overflow issues.
; Removing this and using -O2 can cause:
; "dangerous relocation: l32r: literal target out of range"
; Usually safer to keep -Os globally and selectively optimize hot paths.
; #pragma GCC push_options #pragma GCC optimize ("O3") void hotFunction() {} #pragma GCC pop_options
;

lib_compat_mode = strict

; Uncomment to include the a Root CA SSL Certificate Bundle for all SSL needs
Expand All @@ -125,7 +174,7 @@ board_build.embed_files = src/certs/x509_crt_bundle.bin
; Source for SSL Cert Store can bei either downloaded from Mozilla with 'mozilla' ('https://curl.se/ca/cacert.pem')
; or from a curated Adafruit repository with 'adafruit' (https://raw.githubusercontent.com/adafruit/certificates/main/data/roots-filtered.pem)
; or complied from a 'folder' full of *.pem / *.dem files stored in the ./ssl_certs folder
;board_ssl_cert_source = mozilla
; board_ssl_cert_source = mozilla
board_ssl_cert_source = adafruit

monitor_speed = 115200
Expand Down Expand Up @@ -155,9 +204,9 @@ build_flags =
-D DRIVERS_STACK_SIZE=4096 ; psramFound() ? 4 * 1024 : 3 * 1024, 4096 is sufficient for now

; -D FASTLED_TESTING ; causes duplicate definition of initSpiHardware(); - workaround: removed implementation in spi_hw_manager_esp32.cpp.hpp
-D FASTLED_BUILD=\"20260217\"
-D FASTLED_BUILD=\"20260221\"
lib_deps =
https://github.com/FastLED/FastLED#99e55a02ebf54ff89aa687972f0589870540cb2a ; master 20260217
https://github.com/FastLED/FastLED#9d0b0eb9b5e59e4093982e0c2bdcfdff72ca80cb ; master 20260221
https://github.com/ewowi/WLED-sync#25f280b5e8e47e49a95282d0b78a5ce5301af4fe ; sourceIP + fftUdp.clear() if arduino >=3 (20251104)

; 💫 currently only enabled on s3 as esp32dev runs over 100%
Expand Down
2 changes: 2 additions & 0 deletions src/MoonBase/Char.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct Char {

char operator[](const uint16_t indexV) const { return (indexV < sizeof(s)) ? s[indexV] : '\0'; }

// returns a substring from begin (inclusive) to end (exclusive)
Char<N> substring(uint16_t begin, uint16_t end = sizeof(s) - 1) {
Char<N> sub;
if (begin >= sizeof(s) || end >= sizeof(s) || end < begin)
Expand All @@ -102,6 +103,7 @@ struct Char {
int toInt() const { return atoi(s); }
float toFloat() const { return atof(s); }
bool contains(const char* rhs) const { return strnstr(s, rhs, sizeof(s)) != nullptr; }
// returns index of first character of token (starting with 0)
size_t indexOf(const char* token) const {
const char* pos = strnstr(s, token, sizeof(s));
return pos ? (pos - s) : SIZE_MAX;
Expand Down
4 changes: 2 additions & 2 deletions src/MoonBase/Nodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,8 @@ void DriverNode::setup() {
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 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
}

Expand Down
74 changes: 61 additions & 13 deletions src/MoonLight/Modules/ModuleEffects.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ class ModuleEffects : public NodeManager {
addControlValue(control, getNameAndTags<LinesEffect>());
addControlValue(control, getNameAndTags<FireEffect>());
addControlValue(control, getNameAndTags<FixedRectangleEffect>());
addControlValue(control, getNameAndTags<ParticlesEffect>());
addControlValue(control, getNameAndTags<PraxisEffect>());
addControlValue(control, getNameAndTags<StarSkyEffect>());
#if USE_M5UNIFIED
addControlValue(control, getNameAndTags<MoonManEffect>());
#endif
addControlValue(control, getNameAndTags<FreqSawsEffect>());
addControlValue(control, getNameAndTags<MarioTestEffect>());
addControlValue(control, getNameAndTags<ParticlesEffect>());
addControlValue(control, getNameAndTags<PixelMapEffect>());
addControlValue(control, getNameAndTags<PraxisEffect>());
addControlValue(control, getNameAndTags<RadarEffect>());
addControlValue(control, getNameAndTags<RandomEffect>());
addControlValue(control, getNameAndTags<RingRandomFlowEffect>());
addControlValue(control, getNameAndTags<RipplesEffect>());
Expand All @@ -108,6 +108,7 @@ class ModuleEffects : public NodeManager {
addControlValue(control, getNameAndTags<SphereMoveEffect>());
addControlValue(control, getNameAndTags<SpiralFireEffect>());
addControlValue(control, getNameAndTags<StarFieldEffect>());
addControlValue(control, getNameAndTags<StarSkyEffect>());
addControlValue(control, getNameAndTags<VUMeterEffect>());
addControlValue(control, getNameAndTags<WaveEffect>());

Expand All @@ -118,14 +119,14 @@ class ModuleEffects : public NodeManager {

// WLED effects, alphabetically
addControlValue(control, getNameAndTags<BlackholeEffect>());
addControlValue(control, getNameAndTags<BouncingBallsEffect>());
addControlValue(control, getNameAndTags<BlinkRainbowEffect>());
addControlValue(control, getNameAndTags<BlurzEffect>());
addControlValue(control, getNameAndTags<BouncingBallsEffect>());
addControlValue(control, getNameAndTags<ColorTwinkleEffect>());
addControlValue(control, getNameAndTags<DistortionWavesEffect>());
addControlValue(control, getNameAndTags<DJLightEffect>());
addControlValue(control, getNameAndTags<DNAEffect>());
addControlValue(control, getNameAndTags<DripEffect>());
addControlValue(control, getNameAndTags<FreqMatrixEffect>());
addControlValue(control, getNameAndTags<FireworksEffect>());
addControlValue(control, getNameAndTags<FlowEffect>());
addControlValue(control, getNameAndTags<FrizzlesEffect>());
Expand All @@ -134,17 +135,39 @@ class ModuleEffects : public NodeManager {
addControlValue(control, getNameAndTags<HeartBeatEffect>());
addControlValue(control, getNameAndTags<JuliaEffect>());
addControlValue(control, getNameAndTags<LissajousEffect>());
addControlValue(control, getNameAndTags<MeteorEffect>());
addControlValue(control, getNameAndTags<Noise2DEffect>());
addControlValue(control, getNameAndTags<NoiseMeterEffect>());
addControlValue(control, getNameAndTags<NoisefireEffect>());
addControlValue(control, getNameAndTags<NoisemoveEffect>());
addControlValue(control, getNameAndTags<OctopusEffect>());
addControlValue(control, getNameAndTags<OscillateEffect>());
addControlValue(control, getNameAndTags<PacManEffect>());
addControlValue(control, getNameAndTags<PhasedNoiseEffect>());
addControlValue(control, getNameAndTags<PlasmaEffect>());
addControlValue(control, getNameAndTags<PoliceEffect>());
addControlValue(control, getNameAndTags<PopCornEffect>());
addControlValue(control, getNameAndTags<RainEffect>());
addControlValue(control, getNameAndTags<TetrixEffect>());
addControlValue(control, getNameAndTags<WaverlyEffect>());

addControlValue(control, getNameAndTags<FreqmapEffect>());
addControlValue(control, getNameAndTags<FreqMatrixEffect>());
addControlValue(control, getNameAndTags<FreqpixelsEffect>());
addControlValue(control, getNameAndTags<FreqwaveEffect>());
addControlValue(control, getNameAndTags<GravfreqEffect>());
addControlValue(control, getNameAndTags<GravimeterEffect>());
addControlValue(control, getNameAndTags<GravcenterEffect>());
addControlValue(control, getNameAndTags<GravcentricEffect>());
addControlValue(control, getNameAndTags<MidnoiseEffect>());
addControlValue(control, getNameAndTags<NoiseMeterEffect>());
addControlValue(control, getNameAndTags<PixelwaveEffect>());
addControlValue(control, getNameAndTags<PlasmoidEffect>());
addControlValue(control, getNameAndTags<PuddlepeakEffect>());
addControlValue(control, getNameAndTags<PuddlesEffect>());
addControlValue(control, getNameAndTags<RipplepeakEffect>());
addControlValue(control, getNameAndTags<RocktavesEffect>());
addControlValue(control, getNameAndTags<WaterfallEffect>());

// FastLED effects
addControlValue(control, getNameAndTags<RainbowEffect>());

Expand All @@ -162,6 +185,7 @@ class ModuleEffects : public NodeManager {
addControlValue(control, getNameAndTags<MirrorModifier>());
addControlValue(control, getNameAndTags<TransposeModifier>());
addControlValue(control, getNameAndTags<CircleModifier>());
addControlValue(control, getNameAndTags<BlockModifier>());
addControlValue(control, getNameAndTags<RotateModifier>());
addControlValue(control, getNameAndTags<CheckerboardModifier>());
addControlValue(control, getNameAndTags<PinwheelModifier>());
Expand Down Expand Up @@ -189,24 +213,25 @@ class ModuleEffects : public NodeManager {
if (!node) node = checkAndAlloc<FreqSawsEffect>(name);
if (!node) node = checkAndAlloc<LinesEffect>(name);
if (!node) node = checkAndAlloc<MarioTestEffect>(name);
if (!node) node = checkAndAlloc<StarSkyEffect>(name);
#if USE_M5UNIFIED
if (!node) node = checkAndAlloc<MoonManEffect>(name);
#endif
if (!node) node = checkAndAlloc<ParticlesEffect>(name);
if (!node) node = checkAndAlloc<PraxisEffect>(name);
if (!node) node = checkAndAlloc<PixelMapEffect>(name);
if (!node) node = checkAndAlloc<PraxisEffect>(name);
if (!node) node = checkAndAlloc<RadarEffect>(name);
if (!node) node = checkAndAlloc<RandomEffect>(name);
if (!node) node = checkAndAlloc<RingRandomFlowEffect>(name);
if (!node) node = checkAndAlloc<RipplesEffect>(name);
if (!node) node = checkAndAlloc<RubiksCubeEffect>(name);
if (!node) node = checkAndAlloc<ScrollingTextEffect>(name);
if (!node) node = checkAndAlloc<SinusEffect>(name);
if (!node) node = checkAndAlloc<SphereMoveEffect>(name);
if (!node) node = checkAndAlloc<StarFieldEffect>(name);
if (!node) node = checkAndAlloc<WaveEffect>(name);
if (!node) node = checkAndAlloc<SpiralFireEffect>(name);
if (!node) node = checkAndAlloc<StarFieldEffect>(name);
if (!node) node = checkAndAlloc<StarSkyEffect>(name);
if (!node) node = checkAndAlloc<VUMeterEffect>(name);
if (!node) node = checkAndAlloc<WaveEffect>(name);

// MoonModules effects, alphabetically
if (!node) node = checkAndAlloc<GameOfLifeEffect>(name);
Expand All @@ -215,33 +240,55 @@ class ModuleEffects : public NodeManager {

// WLED effects, alphabetically
if (!node) node = checkAndAlloc<BlackholeEffect>(name);
if (!node) node = checkAndAlloc<BouncingBallsEffect>(name);
if (!node) node = checkAndAlloc<BlinkRainbowEffect>(name);
if (!node) node = checkAndAlloc<BlurzEffect>(name);
if (!node) node = checkAndAlloc<BouncingBallsEffect>(name);
if (!node) node = checkAndAlloc<ColorTwinkleEffect>(name);
if (!node) node = checkAndAlloc<DistortionWavesEffect>(name);
if (!node) node = checkAndAlloc<DJLightEffect>(name);
if (!node) node = checkAndAlloc<DNAEffect>(name);
if (!node) node = checkAndAlloc<DripEffect>(name);
if (!node) node = checkAndAlloc<FireworksEffect>(name);
if (!node) node = checkAndAlloc<FlowEffect>(name);
if (!node) node = checkAndAlloc<FreqMatrixEffect>(name);
if (!node) node = checkAndAlloc<FrizzlesEffect>(name);
if (!node) node = checkAndAlloc<FunkyPlankEffect>(name);
if (!node) node = checkAndAlloc<GEQEffect>(name);
if (!node) node = checkAndAlloc<HeartBeatEffect>(name);
if (!node) node = checkAndAlloc<JuliaEffect>(name);
if (!node) node = checkAndAlloc<LissajousEffect>(name);
if (!node) node = checkAndAlloc<MeteorEffect>(name);
if (!node) node = checkAndAlloc<Noise2DEffect>(name);
if (!node) node = checkAndAlloc<NoiseMeterEffect>(name);
if (!node) node = checkAndAlloc<NoisefireEffect>(name);
if (!node) node = checkAndAlloc<NoisemoveEffect>(name);
if (!node) node = checkAndAlloc<OctopusEffect>(name);
if (!node) node = checkAndAlloc<OscillateEffect>(name);
if (!node) node = checkAndAlloc<PacManEffect>(name);
if (!node) node = checkAndAlloc<PhasedNoiseEffect>(name);
if (!node) node = checkAndAlloc<PlasmaEffect>(name);
if (!node) node = checkAndAlloc<PoliceEffect>(name);
if (!node) node = checkAndAlloc<PopCornEffect>(name);
if (!node) node = checkAndAlloc<RainEffect>(name);
if (!node) node = checkAndAlloc<TetrixEffect>(name);
if (!node) node = checkAndAlloc<WaverlyEffect>(name);

if (!node) node = checkAndAlloc<FreqmapEffect>(name);
if (!node) node = checkAndAlloc<FreqMatrixEffect>(name);
if (!node) node = checkAndAlloc<FreqpixelsEffect>(name);
if (!node) node = checkAndAlloc<FreqwaveEffect>(name);
if (!node) node = checkAndAlloc<GravfreqEffect>(name);
if (!node) node = checkAndAlloc<GravimeterEffect>(name);
if (!node) node = checkAndAlloc<GravcenterEffect>(name);
if (!node) node = checkAndAlloc<GravcentricEffect>(name);
if (!node) node = checkAndAlloc<MidnoiseEffect>(name);
if (!node) node = checkAndAlloc<NoiseMeterEffect>(name);
if (!node) node = checkAndAlloc<PixelwaveEffect>(name);
if (!node) node = checkAndAlloc<PlasmoidEffect>(name);
if (!node) node = checkAndAlloc<PuddlepeakEffect>(name);
if (!node) node = checkAndAlloc<PuddlesEffect>(name);
if (!node) node = checkAndAlloc<RipplepeakEffect>(name);
if (!node) node = checkAndAlloc<RocktavesEffect>(name);
if (!node) node = checkAndAlloc<WaterfallEffect>(name);

// FastLED
if (!node) node = checkAndAlloc<RainbowEffect>(name);

Expand All @@ -261,6 +308,7 @@ class ModuleEffects : public NodeManager {
if (!node) node = checkAndAlloc<MirrorModifier>(name);
if (!node) node = checkAndAlloc<TransposeModifier>(name);
if (!node) node = checkAndAlloc<CircleModifier>(name);
if (!node) node = checkAndAlloc<BlockModifier>(name);
if (!node) node = checkAndAlloc<RotateModifier>(name);
if (!node) node = checkAndAlloc<CheckerboardModifier>(name);
if (!node) node = checkAndAlloc<PinwheelModifier>(name);
Expand Down
Loading