Skip to content
Open
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
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
4 changes: 2 additions & 2 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=\"20260219\" ; 🌙

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

Expand Down Expand Up @@ -157,7 +157,7 @@ build_flags =
; -D FASTLED_TESTING ; causes duplicate definition of initSpiHardware(); - workaround: removed implementation in spi_hw_manager_esp32.cpp.hpp
-D FASTLED_BUILD=\"20260217\"
lib_deps =
https://github.com/FastLED/FastLED#99e55a02ebf54ff89aa687972f0589870540cb2a ; master 20260217
https://github.com/FastLED/FastLED#d9ffd095605ee1065aba40d8f89b757be5aad52f ; master 20260219
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, starting at begin and ending at end-1 (not exclusive)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Misleading comment: "not exclusive" contradicts the actual semantics.

The end parameter is exclusive (the character at end is not included in the result). The parenthetical "(not exclusive)" reads as "end is inclusive," which is the opposite of what the code does. Consider:

// returns a substring from index begin (inclusive) to end (exclusive)
✏️ Suggested fix
-  // returns a substring, starting at begin and ending at end-1 (not exclusive)
+  // returns a substring, starting at begin (inclusive) to end (exclusive)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// returns a substring, starting at begin and ending at end-1 (not exclusive)
// returns a substring, starting at begin (inclusive) to end (exclusive)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MoonBase/Char.h` at line 91, Update the misleading comment on the
substring function in Char.h: change the parenthetical "(not exclusive)" to
clearly state that end is exclusive (e.g., "returns a substring from index begin
(inclusive) to end (exclusive)") so the comment for the substring method (the
function that "returns a substring, starting at begin and ending at end-1")
accurately reflects its semantics; locate and edit the comment near the
substring/Char method declaration in Char.h.

Copy link
Collaborator Author

@ewowi ewowi Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai,
I doubt this is true, because of the null terminator, at least in practice it is 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