diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp
index d12176ee..481b9651 100644
--- a/wled00/cfg.cpp
+++ b/wled00/cfg.cpp
@@ -379,6 +379,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(e131SkipOutOfSequence, if_live_dmx[F("seqskip")]);
CJSON(DMXAddress, if_live_dmx[F("addr")]);
if (!DMXAddress || DMXAddress > 510) DMXAddress = 1;
+ CJSON(DMXSegmentSpacing, if_live_dmx[F("dss")]);
+ if (DMXSegmentSpacing > 150) DMXSegmentSpacing = 0;
CJSON(DMXMode, if_live_dmx["mode"]);
tdd = if_live[F("timeout")] | -1;
@@ -837,6 +839,7 @@ void serializeConfig() {
if_live_dmx[F("uni")] = e131Universe;
if_live_dmx[F("seqskip")] = e131SkipOutOfSequence;
if_live_dmx[F("addr")] = DMXAddress;
+ if_live_dmx[F("dss")] = DMXSegmentSpacing;
if_live_dmx["mode"] = DMXMode;
if_live[F("timeout")] = realtimeTimeoutMs / 100;
diff --git a/wled00/const.h b/wled00/const.h
index f092fe63..6f8f269d 100644
--- a/wled00/const.h
+++ b/wled00/const.h
@@ -147,9 +147,13 @@
#define DMX_MODE_SINGLE_RGB 1 //all LEDs same RGB color (3 channels)
#define DMX_MODE_SINGLE_DRGB 2 //all LEDs same RGB color and master dimmer (4 channels)
#define DMX_MODE_EFFECT 3 //trigger standalone effects of WLED (11 channels)
+#define DMX_MODE_EFFECT_W 7 //trigger standalone effects of WLED (13 channels)
#define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels)
#define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels)
#define DMX_MODE_MULTIPLE_RGBW 6 //every LED is addressed with its own RGBW (ledCount * 4 channels)
+#define DMX_MODE_EFFECT_SEGMENT 8 //trigger standalone effects of WLED (11 channels per segement)
+#define DMX_MODE_EFFECT_SEGMENT_W 9 //trigger standalone effects of WLED (13 channels per segement)
+#define DMX_MODE_PRESET 10 //apply presets (1 channel)
//Light capability byte (unused) 0bRCCCTTTT
//bits 0/1/2/3: specifies a type of LED driver. A single "driver" may have different chip models but must have the same protocol/behavior
diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm
index b7f4f2ef..9fc2e16e 100644
--- a/wled00/data/settings_sync.htm
+++ b/wled00/data/settings_sync.htm
@@ -148,15 +148,20 @@ Start universe:
Reboot required. Check out LedFx!
Skip out-of-sequence packets:
DMX start address:
+DMX segment spacing:
DMX mode:
E1.31 info
Timeout: ms
diff --git a/wled00/e131.cpp b/wled00/e131.cpp
index cce5233a..310a3ea7 100644
--- a/wled00/e131.cpp
+++ b/wled00/e131.cpp
@@ -132,7 +132,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
return; // nothing to do
break;
- case DMX_MODE_SINGLE_RGB: // RGB only
+ case DMX_MODE_SINGLE_RGB: // 3 channel: [R,G,B]
if (uni != e131Universe) return;
if (availDMXLen < 3) return;
@@ -145,7 +145,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel);
break;
- case DMX_MODE_SINGLE_DRGB: // Dimmer + RGB
+ case DMX_MODE_SINGLE_DRGB: // 4 channel: [Dimmer,R,G,B]
if (uni != e131Universe) return;
if (availDMXLen < 4) return;
@@ -162,38 +162,67 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel);
break;
- case DMX_MODE_EFFECT: // Length 1: Apply Preset ID, length 11-13: apply effect config
- if (uni != e131Universe) return;
- if (availDMXLen < 11) {
- if (availDMXLen > 1) return;
- applyPreset(e131_data[dataOffset+0], CALL_MODE_NOTIFICATION);
- return;
- }
-
- if (bri != e131_data[dataOffset+0]) {
- bri = e131_data[dataOffset+0];
- }
- if (e131_data[dataOffset+1] < strip.getModeCount())
- effectCurrent = e131_data[dataOffset+ 1];
- effectSpeed = e131_data[dataOffset+ 2]; // flickers
- effectIntensity = e131_data[dataOffset+ 3];
- effectPalette = e131_data[dataOffset+ 4];
- col[0] = e131_data[dataOffset+ 5];
- col[1] = e131_data[dataOffset+ 6];
- col[2] = e131_data[dataOffset+ 7];
- colSec[0] = e131_data[dataOffset+ 8];
- colSec[1] = e131_data[dataOffset+ 9];
- colSec[2] = e131_data[dataOffset+10];
- if (availDMXLen > 11)
- {
- col[3] = e131_data[dataOffset+11]; //white
- colSec[3] = e131_data[dataOffset+12];
- }
- transitionDelayTemp = 0; // act fast
- colorUpdated(CALL_MODE_NOTIFICATION); // don't send UDP
- return; // don't activate realtime live mode
+ case DMX_MODE_PRESET: // 1 channel: WLED Preset number [#]
+ if (uni != e131Universe || availDMXLen < 1) return;
+ applyPreset(e131_data[dataOffset], CALL_MODE_NOTIFICATION);
+ return;
break;
+ case DMX_MODE_EFFECT: // 11 channels [bri,effectCurrent,effectSpeed,effectIntensity,effectPalette,R,G,B,R2,G2,B2]
+ case DMX_MODE_EFFECT_W: // 13 channels, same as above but with extra +2 white channels [..,W,W2]
+ case DMX_MODE_EFFECT_SEGMENT: // 11 channels per segment; max[#] = floor[512/(11+DMXSegmentSpacing)] = 46,42,39, ..
+ case DMX_MODE_EFFECT_SEGMENT_W: // 13 Channels per segment; max[#] = floor[512/(13+DMXSegmentSpacing)] = 39,36,34,32, ..
+ {
+ if (uni != e131Universe) return;
+ bool segmentUpdated = false;
+ bool isSegmentMode = DMXMode == DMX_MODE_EFFECT_SEGMENT || DMXMode == DMX_MODE_EFFECT_SEGMENT_W;
+ uint8_t dmxEffectChannels = (DMXMode == DMX_MODE_EFFECT || DMXMode == DMX_MODE_EFFECT_SEGMENT) ? 11 : 13;
+ for (uint8_t seg = 0; seg < strip.getSegmentsNum(); seg++) {
+ if (isSegmentMode)
+ dataOffset = DMXAddress + seg * (dmxEffectChannels + DMXSegmentSpacing);
+ else
+ dataOffset = DMXAddress;
+ // Modify address for Art-Net data
+ if (protocol == P_ARTNET && dataOffset > 0)
+ dataOffset--;
+ // Skip out of universe addresses
+ if (dataOffset > dmxChannels - dmxEffectChannels)
+ return;
+
+ if (e131_data[dataOffset+1] < strip.getModeCount())
+ effectCurrent = e131_data[dataOffset+ 1];
+ effectSpeed = e131_data[dataOffset+ 2]; // flickers
+ effectIntensity = e131_data[dataOffset+ 3];
+ effectPalette = e131_data[dataOffset+ 4];
+ col[0] = e131_data[dataOffset+ 5];
+ col[1] = e131_data[dataOffset+ 6];
+ col[2] = e131_data[dataOffset+ 7];
+ colSec[0] = e131_data[dataOffset+ 8];
+ colSec[1] = e131_data[dataOffset+ 9];
+ colSec[2] = e131_data[dataOffset+10];
+ if (dmxEffectChannels == 13) {
+ col[3] = e131_data[dataOffset+11]; // white
+ colSec[3] = e131_data[dataOffset+12];
+ }
+ if (isSegmentMode) {
+ opacity = e131_data[dataOffset+ 0];
+ segmentUpdated |= applyValuesToSegment(seg);
+ } else {
+ if (bri != e131_data[dataOffset+0])
+ bri = e131_data[dataOffset+0];
+ transitionDelayTemp = 0; // act fast
+ colorUpdated(CALL_MODE_NOTIFICATION); // don't send UDP
+ return; // don't activate realtime live mode
+ }
+ }
+ if (segmentUpdated) {
+ transitionDelayTemp = 0;
+ stateUpdated(CALL_MODE_NOTIFICATION);
+ return;
+ }
+ break;
+ }
+
case DMX_MODE_MULTIPLE_DRGB:
case DMX_MODE_MULTIPLE_RGB:
case DMX_MODE_MULTIPLE_RGBW:
@@ -279,7 +308,11 @@ void handleArtnetPollReply(IPAddress ipAddress) {
case DMX_MODE_SINGLE_RGB:
case DMX_MODE_SINGLE_DRGB:
+ case DMX_MODE_PRESET:
case DMX_MODE_EFFECT:
+ case DMX_MODE_EFFECT_W:
+ case DMX_MODE_EFFECT_SEGMENT:
+ case DMX_MODE_EFFECT_SEGMENT_W:
break; // 1 universe is enough
case DMX_MODE_MULTIPLE_DRGB:
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h
index 823c7f98..612e8fcb 100644
--- a/wled00/fcn_declare.h
+++ b/wled00/fcn_declare.h
@@ -153,6 +153,7 @@ void toggleOnOff();
void applyBri();
void applyFinalBri();
void applyValuesToSelectedSegs();
+bool applyValuesToSegment(uint8_t i);
void colorUpdated(byte callMode);
void stateUpdated(byte callMode);
void updateInterfaces(uint8_t callMode);
diff --git a/wled00/led.cpp b/wled00/led.cpp
index 34dd85d9..af05c4be 100644
--- a/wled00/led.cpp
+++ b/wled00/led.cpp
@@ -46,6 +46,22 @@ void applyValuesToSelectedSegs()
}
}
+// applies global legacy values to segment i (opacity, col, colSec, effectCurrent...)
+bool applyValuesToSegment(uint8_t i)
+{
+ if (i >= strip.getSegmentsNum()) {return false;}
+ Segment& seg = strip.getSegment(i);
+ if (opacity != seg.opacity) {seg.setOpacity(opacity); stateChanged = true;}
+ if (effectSpeed != seg.speed) {seg.speed = effectSpeed; stateChanged = true;}
+ if (effectIntensity != seg.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
+ if (effectPalette != seg.palette) {seg.palette = effectPalette; stateChanged = true;}
+ if (effectCurrent != seg.mode) {strip.setMode(i, effectCurrent); stateChanged = true;}
+ uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
+ uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
+ if (col0 != seg.colors[0]) {seg.setColor(0, col0); stateChanged = true;}
+ if (col1 != seg.colors[1]) {seg.setColor(1, col1); stateChanged = true;}
+ return stateChanged;
+}
void resetTimebase()
{
diff --git a/wled00/set.cpp b/wled00/set.cpp
index 8caad36c..ca2290f1 100644
--- a/wled00/set.cpp
+++ b/wled00/set.cpp
@@ -266,8 +266,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (t >= 0 && t <= 63999) e131Universe = t;
t = request->arg(F("DA")).toInt();
if (t >= 0 && t <= 510) DMXAddress = t;
+ t = request->arg(F("XX")).toInt();
+ if (t >= 0 && t <= 150) DMXSegmentSpacing = t;
t = request->arg(F("DM")).toInt();
- if (t >= DMX_MODE_DISABLED && t <= DMX_MODE_MULTIPLE_RGBW) DMXMode = t;
+ if (t >= DMX_MODE_DISABLED && t <= DMX_MODE_PRESET) DMXMode = t;
t = request->arg(F("ET")).toInt();
if (t > 99 && t <= 65000) realtimeTimeoutMs = t;
arlsForceMaxBri = request->hasArg(F("FB"));
diff --git a/wled00/wled.h b/wled00/wled.h
index f7dd1703..95d3c1ac 100644
--- a/wled00/wled.h
+++ b/wled00/wled.h
@@ -388,6 +388,7 @@ WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings fo
WLED_GLOBAL uint16_t e131Port _INIT(5568); // DMX in port. E1.31 default is 5568, Art-Net is 6454
WLED_GLOBAL byte DMXMode _INIT(DMX_MODE_MULTIPLE_RGB); // DMX mode (s.a.)
WLED_GLOBAL uint16_t DMXAddress _INIT(1); // DMX start address of fixture, a.k.a. first Channel [for E1.31 (sACN) protocol]
+WLED_GLOBAL uint16_t DMXSegmentSpacing _INIT(0); // Number of void/unused channels between each segments DMX channels
WLED_GLOBAL byte e131LastSequenceNumber[E131_MAX_UNIVERSE_COUNT]; // to detect packet loss
WLED_GLOBAL bool e131Multicast _INIT(false); // multicast or unicast
WLED_GLOBAL bool e131SkipOutOfSequence _INIT(false); // freeze instead of flickering
@@ -496,6 +497,7 @@ WLED_GLOBAL byte briOld _INIT(0); // global brightnes w
WLED_GLOBAL byte briT _INIT(0); // global brightness during transition
WLED_GLOBAL byte briLast _INIT(128); // brightness before turned off. Used for toggle function
WLED_GLOBAL byte whiteLast _INIT(128); // white channel before turned off. Used for toggle function
+WLED_GLOBAL byte opacity _INIT(128); // global segment opacity (set)
// button
WLED_GLOBAL bool buttonPublishMqtt _INIT(false);
diff --git a/wled00/xml.cpp b/wled00/xml.cpp
index 801a5bb1..fdace73f 100644
--- a/wled00/xml.cpp
+++ b/wled00/xml.cpp
@@ -501,6 +501,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',SET_F("EM"),e131Multicast);
sappend('v',SET_F("EU"),e131Universe);
sappend('v',SET_F("DA"),DMXAddress);
+ sappend('v',SET_F("XX"),DMXSegmentSpacing);
sappend('v',SET_F("DM"),DMXMode);
sappend('v',SET_F("ET"),realtimeTimeoutMs);
sappend('c',SET_F("FB"),arlsForceMaxBri);