Add Art-Net support (#417)

This commit is contained in:
cschwinne 2020-04-13 00:42:27 +02:00
parent 3006d25406
commit e12757dbb9
16 changed files with 325 additions and 295 deletions

View File

@ -2,6 +2,10 @@
### Development versions after 0.9.1 release
#### Build 2004120
- Added Art-Net support
- Added OTA platform to platformio.ini
#### Build 2004100
@ -23,7 +27,7 @@
#### Build 2003262
- Fixed compilation for Analog LEDs
- Fixed compilation for Analog LEDs
- Fixed sync settings network port fields too small
#### Build 2003261

View File

@ -30,6 +30,7 @@ default_envs = d1_mini, esp01, esp01_1m_ota, esp32dev
; default_envs = d1_mini
; default_envs = heltec_wifi_kit_8
; default_envs = d1_mini_debug
; default_envs = d1_mini_ota
; default_envs = esp32dev
; default_envs = esp8285_4CH_MagicHome
; default_envs = esp8285_4CH_H801
@ -241,6 +242,15 @@ platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266} ${common.debug_flags}
[env:d1_mini_ota]
board = d1_mini
upload_protocol = espota
# exchange for your WLED IP
upload_port = "10.10.1.27"
platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266}
# ------------------------------------------------------------------------------
# custom board configurations
# ------------------------------------------------------------------------------

View File

@ -43,6 +43,7 @@
#define REALTIME_MODE_HYPERION 3
#define REALTIME_MODE_E131 4
#define REALTIME_MODE_ADALIGHT 5
#define REALTIME_MODE_ARTNET 6
//E1.31 DMX modes
#define DMX_MODE_DISABLED 0 //not used

View File

@ -1,141 +1,105 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=500">
<title>Sync Settings</title>
<script>
function H()
{
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings");
}
function B()
{
window.open("/settings","_self");
}
function GetV()
{
//values injected by server while sending HTML
}
</script>
<style>
:root {
--aCol: #abc;
--bCol: #fff;
--cCol: #ddd;
--dCol: #000;
--sCol: #0004;
}
body {
font-family: Verdana, Helvetica, sans-serif;
text-align: center;
background: var(--cCol);
color: var(--dCol);
line-height: 200%;
margin: 0;
background-attachment: fixed;
}
hr {
border-color: var(--dCol);
filter: drop-shadow( -5px -5px 5px var(--sCol) );
}
button {
background: var(--bCol);
color: var(--dCol);
border: 0.3ch solid var(--bCol);
display: inline-block;
filter: drop-shadow( -5px -5px 5px var(--sCol) );
font-size: 20px;
margin: 8px;
margin-top: 12px;
}
.helpB {
text-align: left;
position: absolute;
width:60px;
}
input {
background: var(--bCol);
color: var(--dCol);
border: 0.5ch solid var(--bCol);
filter: drop-shadow( -5px -5px 5px var(--sCol) );
}
input[type=number] {
width: 3em;
}
</style>
</head>
<body onload="GetV()">
<form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<h2>Sync setup</h2>
<h3>Button setup</h3>
On/Off button enabled: <input type="checkbox" name="BT"><br>
Infrared receiver enabled: <input type="checkbox" name="IR"><br>
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a>
<h3>WLED Sync UDP Broadcast</h3>
UDP Port: <input name="UP" type="number" min="1" max="65535" required><br>
Receive <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br>
Send notifications on direct change: <input type="checkbox" name="SD"><br>
Send notifications on button press: <input type="checkbox" name="SB"><br>
Send Alexa notifications: <input type="checkbox" name="SA"><br>
Send Philips Hue change notifications: <input type="checkbox" name="SH"><br>
Send Macro notifications: <input type="checkbox" name="SM"><br>
Send notifications twice: <input type="checkbox" name="S2">
<h3>Realtime</h3>
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
E1.31 (sACN)<br>
Skip out-of-sequence packets (freeze instead of flicker): <input type="checkbox" name="ES"><br>
Multicast mode: <input type="checkbox" name="EM"><br>
E1.31 start universe: <input name="EU" type="number" min="1" max="63999" required><br>
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx" target="_blank">LedFx</a>!<br><br>
DMX start address: <input name="DA" type="number" min="1" max="510" value="1" required><br>
DMX mode: <input name="DM" type="radio" value="0"> disabled<br>
<input name="DM" type="radio" value="1"> Single RGB (3 Channels for all LEDs: Red Green Blue)<br>
<input name="DM" type="radio" value="2"> Single DRGB (4 Channels for all LEDs: Dimmer Red Green Blue)<br>
<input name="DM" type="radio" value="3"> Effect (11 Channels parametrizing Effects: Dimmer Effect Speed Intensity Palette PriRed PriGreen PriBlue SecRed SecGreen SecBlue)<br>
<input name="DM" type="radio" value="4"> Multiple RGB (3 Channels for each LED: Red Green Blue)<br>
<input name="DM" type="radio" value="5"> Multiple DRGB (1+3 Channels for each LED: Dimmer Red1 Green1 Blue1 Red2 Green2 Blue2...)<br>
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx" target="_blank">LedFx</a>!<br><br>
Timeout: <input name="ET" type="number" min="100" max="65000" required> ms<br>
Force max brightness: <input type="checkbox" name="FB"><br>
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required>
<h3>Alexa Voice Assistant</h3>
Emulate Alexa device: <input type="checkbox" name="AL"><br>
Alexa invocation name: <input name="AI" maxlength="32">
<h3>Blynk</h3>
<b>Blynk, MQTT and Hue sync all connect to external hosts!<br>
This may impact the responsiveness of the ESP8266.</b><br>
For best results, only use one of these services at a time.<br>
(alternatively, connect a second ESP to them and use the UDP sync)<br><br>
Device Auth token: <input name="BK" maxlength="33"><br>
<i>Clear the token field to disable. </i><a href="https://github.com/Aircoookie/WLED/wiki/Blynk" target="_blank">Setup info</a>
<h3>MQTT</h3>
Enable MQTT: <input type="checkbox" name="MQ"><br>
Broker: <input name="MS" maxlength="32"><br>
Port: <input name="MQPORT" type="number" min="1" max="65535"><br>
<b>The MQTT credentials are sent over an unsecured connection.<br>
Never use the MQTT password for another service!</b><br>
Username: <input name="MQTTUSER" maxlength="32"><br>
Password: <input type="password" input name="MQTTPASS" maxlength="32"><br>
Client ID: <input name="MQTTCID" maxlength="32"><br>
Device Topic: <input name="MD" maxlength="32"><br>
Group Topic: <input name="MG" maxlength="32"><br>
<a href="https://github.com/Aircoookie/WLED/wiki/MQTT" target="_blank">MQTT info</a>
<h3>Philips Hue</h3>
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
Poll Hue light <input name="HL" type="number" min="1" max="99"> every <input name="HI" type="number" min="100" max="65000"> ms: <input type="checkbox" name="HP"><br>
Then, receive <input type="checkbox" name="HO"> On/Off, <input type="checkbox" name="HB"> Brightness, and <input type="checkbox" name="HC"> Color<br>
Hue Bridge IP:<br>
<input name="H0" type="number" min="0" max="255"> .
<input name="H1" type="number" min="0" max="255"> .
<input name="H2" type="number" min="0" max="255"> .
<input name="H3" type="number" min="0" max="255"><br>
<b>Press the pushlink button on the bridge, after that save this page!</b><br>
(when first connecting)<br>
Hue status: <span class="hms"> Internal ESP Error! </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
</form>
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>Sync Settings</title>
<script>var d=document;
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings");}function B(){window.open("/settings","_self");}function GetV(){var d=document;}
function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.DA.value == 1) d.Sf.DA.value = 0; if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;}
else if (d.Sf.DI.value == 5568) {if (d.Sf.DA.value == 0) d.Sf.DA.value = 1; if (d.Sf.EU.value == 0) d.Sf.EU.value = 1;} }
function SP(){var p = d.Sf.DI.value; d.getElementById("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;}
function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; }; SP();}
function S(){GetV();SetVal();}
</script>
<style>body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%;margin:0}hr{border-color:#666}button{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}.helpB{text-align:left;position:absolute;width:60px}input{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}input[type=number]{width:4em}select{background:#333;color:#fff;font-family:Verdana,sans-serif;border:0.5ch solid #333}td{padding:2px;}.d5{width:4.5em !important;}</style></head>
<body onload="S()">
<form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<h2>Sync setup</h2>
<h3>Button setup</h3>
On/Off button enabled: <input type="checkbox" name="BT"><br>
Infrared remote:
<select name=IR>
<option value=0>Disabled</option>
<option value=1>24-key RGB</option>
<option value=2>24-key with CT</option>
<option value=3>40-key blue</option>
<option value=4>44-key RGB</option>
<option value=5>21-key RGB</option>
<option value=6>6-key black</option>
</select><br>
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a>
<h3>WLED Broadcast</h3>
UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br>
Receive <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br>
Send notifications on direct change: <input type="checkbox" name="SD"><br>
Send notifications on button press: <input type="checkbox" name="SB"><br>
Send Alexa notifications: <input type="checkbox" name="SA"><br>
Send Philips Hue change notifications: <input type="checkbox" name="SH"><br>
Send Macro notifications: <input type="checkbox" name="SM"><br>
Send notifications twice: <input type="checkbox" name="S2">
<h3>Realtime</h3>
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
<i>Network DMX input</i><br>
Type:
<select name=DI onchange="SP(); adj();">
<option value=5568>E1.31 (sACN)</option>
<option value=6454>Art-Net</option>
<option value=0 selected>Custom port</option>
</select><br>
<div id=xp>Port: <input name="EP" type="number" min="1" max="65535" value="5568" class="d5" required><br></div>
Multicast: <input type="checkbox" name="EM"><br>
Start universe: <input name="EU" type="number" min="0" max="63999" required><br>
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx" target="_blank">LedFx</a>!<br>
Skip out-of-sequence packets: <input type="checkbox" name="ES"><br>
DMX start address: <input name="DA" type="number" min="0" max="510" required><br>
DMX mode:
<select name=DM>
<option value=0>Disabled</option>
<option value=1>Single RGB</option>
<option value=2>Single DRGB</option>
<option value=3>Effect</option>
<option value=4>Multi RGB</option>
<option value=5>Multi DRGB</option>
</select><br>
<a href="https://github.com/Aircoookie/WLED/wiki/E1.31-DMX" target="_blank">E1.31 info</a><br>
Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
Force max brightness: <input type="checkbox" name="FB"><br>
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required>
<h3>Alexa Voice Assistant</h3>
Emulate Alexa device: <input type="checkbox" name="AL"><br>
Alexa invocation name: <input name="AI" maxlength="32">
<h3>Blynk</h3>
<b>Blynk, MQTT and Hue sync all connect to external hosts!<br>
This may impact the responsiveness of the ESP8266.</b><br>
For best results, only use one of these services at a time.<br>
(alternatively, connect a second ESP to them and use the UDP sync)<br><br>
Device Auth token: <input name="BK" maxlength="33"><br>
<i>Clear the token field to disable. </i><a href="https://github.com/Aircoookie/WLED/wiki/Blynk" target="_blank">Setup info</a>
<h3>MQTT</h3>
Enable MQTT: <input type="checkbox" name="MQ"><br>
Broker: <input name="MS" maxlength="32">
Port: <input name="MQPORT" type="number" min="1" max="65535" class="d5"><br>
<b>The MQTT credentials are sent over an unsecured connection.<br>
Never use the MQTT password for another service!</b><br>
Username: <input name="MQUSER" maxlength="40"><br>
Password: <input type="password" input name="MQPASS" maxlength="40"><br>
Client ID: <input name="MQCID" maxlength="40"><br>
Device Topic: <input name="MD" maxlength="32"><br>
Group Topic: <input name="MG" maxlength="32"><br>
<i>Reboot required to apply changes. </i><a href="https://github.com/Aircoookie/WLED/wiki/MQTT" target="_blank">MQTT info</a>
<h3>Philips Hue</h3>
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
Poll Hue light <input name="HL" type="number" min="1" max="99" > every <input name="HI" type="number" min="100" max="65000"> ms: <input type="checkbox" name="HP"><br>
Then, receive <input type="checkbox" name="HO"> On/Off, <input type="checkbox" name="HB"> Brightness, and <input type="checkbox" name="HC"> Color<br>
Hue Bridge IP:<br>
<input name="H0" type="number" min="0" max="255" > .
<input name="H1" type="number" min="0" max="255" > .
<input name="H2" type="number" min="0" max="255" > .
<input name="H3" type="number" min="0" max="255" ><br>
<b>Press the pushlink button on the bridge, after that save this page!</b><br>
(when first connecting)<br>
Hue status: <span class="hms"> Disabled in this build </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
</form>
</body>
</html>

View File

@ -4,29 +4,45 @@
* E1.31 handler
*/
void handleE131Packet(e131_packet_t* p, IPAddress clientIP){
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
//E1.31 protocol support
uint16_t uni = htons(p->universe);
uint8_t previousUniverses = uni - e131Universe;
uint16_t possibleLEDsInCurrentUniverse;
uint16_t dmxChannels = htons(p->property_value_count) -1;
uint16_t uni = 0, dmxChannels = 0;
uint8_t* e131_data = nullptr;
uint8_t seq = 0, mde = REALTIME_MODE_E131;
if (isArtnet)
{
uni = p->art_universe;
dmxChannels = htons(p->art_length);
e131_data = p->art_data;
seq = p->art_sequence_number;
mde = REALTIME_MODE_ARTNET;
} else {
uni = htons(p->universe);
dmxChannels = htons(p->property_value_count) -1;
e131_data = p->property_values;
seq = p->sequence_number;
}
// only listen for universes we're handling & allocated memory
if (uni >= (e131Universe + E131_MAX_UNIVERSE_COUNT)) return;
uint8_t previousUniverses = uni - e131Universe;
uint16_t possibleLEDsInCurrentUniverse;
if (e131SkipOutOfSequence)
if (p->sequence_number < e131LastSequenceNumber[uni-e131Universe] && p->sequence_number > 20 && e131LastSequenceNumber[uni-e131Universe] < 250){
if (seq < e131LastSequenceNumber[uni-e131Universe] && seq > 20 && e131LastSequenceNumber[uni-e131Universe] < 250){
DEBUG_PRINT("skipping E1.31 frame (last seq=");
DEBUG_PRINT(e131LastSequenceNumber[uni-e131Universe]);
DEBUG_PRINT(", current seq=");
DEBUG_PRINT(p->sequence_number);
DEBUG_PRINT(seq);
DEBUG_PRINT(", universe=");
DEBUG_PRINT(uni);
DEBUG_PRINTLN(")");
return;
}
e131LastSequenceNumber[uni-e131Universe] = p->sequence_number;
e131LastSequenceNumber[uni-e131Universe] = seq;
// update status info
realtimeIP = clientIP;
@ -39,46 +55,46 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP){
case DMX_MODE_SINGLE_RGB:
if (uni != e131Universe) return;
if (dmxChannels-DMXAddress+1 < 3) return;
arlsLock(realtimeTimeoutMs, REALTIME_MODE_E131);
realtimeLock(realtimeTimeoutMs, mde);
for (uint16_t i = 0; i < ledCount; i++)
setRealtimePixel(i, p->property_values[DMXAddress+0], p->property_values[DMXAddress+1], p->property_values[DMXAddress+2], 0);
setRealtimePixel(i, e131_data[DMXAddress+0], e131_data[DMXAddress+1], e131_data[DMXAddress+2], 0);
break;
case DMX_MODE_SINGLE_DRGB:
if (uni != e131Universe) return;
if (dmxChannels-DMXAddress+1 < 4) return;
arlsLock(realtimeTimeoutMs, REALTIME_MODE_E131);
if (DMXOldDimmer != p->property_values[DMXAddress+0]) {
DMXOldDimmer = p->property_values[DMXAddress+0];
bri = p->property_values[DMXAddress+0];
realtimeLock(realtimeTimeoutMs, mde);
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
DMXOldDimmer = e131_data[DMXAddress+0];
bri = e131_data[DMXAddress+0];
strip.setBrightness(bri);
}
for (uint16_t i = 0; i < ledCount; i++)
setRealtimePixel(i, p->property_values[DMXAddress+1], p->property_values[DMXAddress+2], p->property_values[DMXAddress+3], 0);
setRealtimePixel(i, e131_data[DMXAddress+1], e131_data[DMXAddress+2], e131_data[DMXAddress+3], 0);
break;
case DMX_MODE_EFFECT:
if (uni != e131Universe) return;
if (dmxChannels-DMXAddress+1 < 11) return;
if (DMXOldDimmer != p->property_values[DMXAddress+0]) {
DMXOldDimmer = p->property_values[DMXAddress+0];
bri = p->property_values[DMXAddress+0];
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
DMXOldDimmer = e131_data[DMXAddress+0];
bri = e131_data[DMXAddress+0];
}
if (p->property_values[DMXAddress+1] < MODE_COUNT)
effectCurrent = p->property_values[DMXAddress+ 1];
effectSpeed = p->property_values[DMXAddress+ 2]; // flickers
effectIntensity = p->property_values[DMXAddress+ 3];
effectPalette = p->property_values[DMXAddress+ 4];
col[0] = p->property_values[DMXAddress+ 5];
col[1] = p->property_values[DMXAddress+ 6];
col[2] = p->property_values[DMXAddress+ 7];
colSec[0] = p->property_values[DMXAddress+ 8];
colSec[1] = p->property_values[DMXAddress+ 9];
colSec[2] = p->property_values[DMXAddress+10];
if (e131_data[DMXAddress+1] < MODE_COUNT)
effectCurrent = e131_data[DMXAddress+ 1];
effectSpeed = e131_data[DMXAddress+ 2]; // flickers
effectIntensity = e131_data[DMXAddress+ 3];
effectPalette = e131_data[DMXAddress+ 4];
col[0] = e131_data[DMXAddress+ 5];
col[1] = e131_data[DMXAddress+ 6];
col[2] = e131_data[DMXAddress+ 7];
colSec[0] = e131_data[DMXAddress+ 8];
colSec[1] = e131_data[DMXAddress+ 9];
colSec[2] = e131_data[DMXAddress+10];
if (dmxChannels-DMXAddress+1 > 11)
{
col[3] = p->property_values[DMXAddress+11]; //white
colSec[3] = p->property_values[DMXAddress+12];
col[3] = e131_data[DMXAddress+11]; //white
colSec[3] = e131_data[DMXAddress+12];
}
transitionDelayTemp = 0; // act fast
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); // don't send UDP
@ -86,13 +102,13 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP){
break;
case DMX_MODE_MULTIPLE_RGB:
arlsLock(realtimeTimeoutMs, REALTIME_MODE_E131);
realtimeLock(realtimeTimeoutMs, mde);
if (previousUniverses == 0) {
// first universe of this fixture
possibleLEDsInCurrentUniverse = (dmxChannels - DMXAddress + 1) / 3;
for (uint16_t i = 0; i < ledCount; i++) {
if (i >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s)
setRealtimePixel(i, p->property_values[DMXAddress+i*3+0], p->property_values[DMXAddress+i*3+1], p->property_values[DMXAddress+i*3+2], 0);
setRealtimePixel(i, e131_data[DMXAddress+i*3+0], e131_data[DMXAddress+i*3+1], e131_data[DMXAddress+i*3+2], 0);
}
} else if (previousUniverses > 0 && uni < (e131Universe + E131_MAX_UNIVERSE_COUNT)) {
// additional universe(s) of this fixture
@ -102,24 +118,24 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP){
for (uint16_t i = numberOfLEDsInPreviousUniverses; i < ledCount; i++) {
uint8_t j = i - numberOfLEDsInPreviousUniverses;
if (j >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s)
setRealtimePixel(i, p->property_values[j*3+1], p->property_values[j*3+2], p->property_values[j*3+3], 0);
setRealtimePixel(i, e131_data[j*3+1], e131_data[j*3+2], e131_data[j*3+3], 0);
}
}
break;
case DMX_MODE_MULTIPLE_DRGB:
arlsLock(realtimeTimeoutMs, REALTIME_MODE_E131);
realtimeLock(realtimeTimeoutMs, mde);
if (previousUniverses == 0) {
// first universe of this fixture
if (DMXOldDimmer != p->property_values[DMXAddress+0]) {
DMXOldDimmer = p->property_values[DMXAddress+0];
bri = p->property_values[DMXAddress+0];
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
DMXOldDimmer = e131_data[DMXAddress+0];
bri = e131_data[DMXAddress+0];
strip.setBrightness(bri);
}
possibleLEDsInCurrentUniverse = (dmxChannels - DMXAddress) / 3;
for (uint16_t i = 0; i < ledCount; i++) {
if (i >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s)
setRealtimePixel(i, p->property_values[DMXAddress+i*3+1], p->property_values[DMXAddress+i*3+2], p->property_values[DMXAddress+i*3+3], 0);
setRealtimePixel(i, e131_data[DMXAddress+i*3+1], e131_data[DMXAddress+i*3+2], e131_data[DMXAddress+i*3+3], 0);
}
} else if (previousUniverses > 0 && uni < (e131Universe + E131_MAX_UNIVERSE_COUNT)) {
// additional universe(s) of this fixture
@ -129,7 +145,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP){
for (uint16_t i = numberOfLEDsInPreviousUniverses; i < ledCount; i++) {
uint8_t j = i - numberOfLEDsInPreviousUniverses;
if (j >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s)
setRealtimePixel(i, p->property_values[j*3+1], p->property_values[j*3+2], p->property_values[j*3+3], 0);
setRealtimePixel(i, e131_data[j*3+1], e131_data[j*3+2], e131_data[j*3+3], 0);
}
}
break;

View File

@ -42,7 +42,7 @@ void initDMX();
void handleDMX();
//e131.cpp
void handleE131Packet(e131_packet_t* p, IPAddress clientIP);
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet);
//file.cpp
bool handleFileRead(AsyncWebServerRequest*, String path);
@ -103,12 +103,6 @@ void handleNightlight();
bool initMqtt();
void publishMqtt();
//notify.cpp
void notify(byte callMode, bool followUp=false);
void arlsLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
void handleNotifications();
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w);
//ntp.cpp
void handleNetworkTime();
void sendNTPPacket();
@ -140,6 +134,12 @@ bool handleSet(AsyncWebServerRequest *request, const String& req);
int getNumVal(const String* req, uint16_t pos);
bool updateVal(const String* req, const char* key, byte* val, byte minv=0, byte maxv=255);
//udp.cpp
void notify(byte callMode, bool followUp=false);
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
void handleNotifications();
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w);
//usermod.cpp
void userSetup();
void userConnected();

View File

@ -252,16 +252,16 @@ Sync button toggles both send and receive: <input type="checkbox" name="ST"><br>
//sync settings
const char PAGE_settings_sync[] PROGMEM = R"=====(<!DOCTYPE html>
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>Sync Settings</title>
<script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings");}function B(){window.open("/settings","_self");}function GetV(){var d=document;
<html><head><meta name=viewport content="width=500"><meta charset=utf-8><title>Sync Settings</title>
<script>var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings")}function B(){window.open("/settings","_self")}function adj(){if(d.Sf.DI.value==6454){if(d.Sf.DA.value==1){d.Sf.DA.value=0}if(d.Sf.EU.value==1){d.Sf.EU.value=0}}else{if(d.Sf.DI.value==5568){if(d.Sf.DA.value==0){d.Sf.DA.value=1}if(d.Sf.EU.value==0){d.Sf.EU.value=1}}}}function SP(){var a=d.Sf.DI.value;d.getElementById("xp").style.display=(a>0)?"none":"block";if(a>0){d.Sf.EP.value=a}}function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568:d.Sf.DI.value=5568;break;case 6454:d.Sf.DI.value=6454;break}SP()}function S(){GetV();SetVal()};function GetV(){
%CSS%%SCSS%</head>
<body onload="GetV()">
<form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<body onload=S()>
<form id=form_s name=Sf method=post>
<div class=helpB><button type=button onclick=H()>?</button></div>
<button type=button onclick=B()>Back</button><button type=submit>Save</button><hr>
<h2>Sync setup</h2>
<h3>Button setup</h3>
On/Off button enabled: <input type="checkbox" name="BT"><br>
On/Off button enabled: <input type=checkbox name=BT><br>
Infrared remote:
<select name=IR>
<option value=0>Disabled</option>
@ -272,24 +272,31 @@ Infrared remote:
<option value=5>21-key RGB</option>
<option value=6>6-key black</option>
</select><br>
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a>
<a href=https://github.com/Aircoookie/WLED/wiki/Infrared-Control target=_blank>IR info</a>
<h3>WLED Broadcast</h3>
UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br>
Receive <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br>
Send notifications on direct change: <input type="checkbox" name="SD"><br>
Send notifications on button press: <input type="checkbox" name="SB"><br>
Send Alexa notifications: <input type="checkbox" name="SA"><br>
Send Philips Hue change notifications: <input type="checkbox" name="SH"><br>
Send Macro notifications: <input type="checkbox" name="SM"><br>
Send notifications twice: <input type="checkbox" name="S2">
UDP Port: <input name=UP type=number min=1 max=65535 class=d5 required><br>
Receive <input type=checkbox name=RB>Brightness, <input type=checkbox name=RC>Color, and <input type=checkbox name=RX>Effects<br>
Send notifications on direct change: <input type=checkbox name=SD><br>
Send notifications on button press: <input type=checkbox name=SB><br>
Send Alexa notifications: <input type=checkbox name=SA><br>
Send Philips Hue change notifications: <input type=checkbox name=SH><br>
Send Macro notifications: <input type=checkbox name=SM><br>
Send notifications twice: <input type=checkbox name=S2>
<h3>Realtime</h3>
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
<i>E1.31 (sACN)</i><br>
Use E1.31 multicast: <input type="checkbox" name="EM"><br>
E1.31 start universe: <input name="EU" type="number" min="1" max="63999" required><br>
Skip out-of-sequence packets: <input type="checkbox" name="ES"><br>
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx" target="_blank">LedFx</a>!<br>
DMX start address: <input name="DA" type="number" min="1" max="510" value="1" required><br>
Receive UDP realtime: <input type=checkbox name=RD><br><br>
<i>Network DMX input</i><br>
Type:
<select name=DI onchange=SP();adj()>
<option value=5568>E1.31 (sACN)</option>
<option value=6454>Art-Net</option>
<option value=0 selected>Custom port</option>
</select><br>
<div id=xp>Port: <input name=EP type=number min=1 max=65535 value=5568 class=d5 required><br></div>
Multicast: <input type=checkbox name=EM><br>
Start universe: <input name=EU type=number min=0 max=63999 required><br>
<i>Reboot required.</i> Check out <a href=https://github.com/ahodges9/LedFx target=_blank>LedFx</a>!<br>
Skip out-of-sequence packets: <input type=checkbox name=ES><br>
DMX start address: <input name=DA type=number min=0 max=510 required><br>
DMX mode:
<select name=DM>
<option value=0>Disabled</option>
@ -299,49 +306,48 @@ DMX mode:
<option value=4>Multi RGB</option>
<option value=5>Multi DRGB</option>
</select><br>
<a href="https://github.com/Aircoookie/WLED/wiki/E1.31-DMX" target="_blank">E1.31 info</a><br>
Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
Force max brightness: <input type="checkbox" name="FB"><br>
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required>
<a href=https://github.com/Aircoookie/WLED/wiki/E1.31-DMX target=_blank>E1.31 info</a><br>
Timeout: <input name=ET type=number min=1 max=65000 required> ms<br>
Force max brightness: <input type=checkbox name=FB><br>
Disable realtime gamma correction: <input type=checkbox name=RG><br>
Realtime LED offset: <input name=WO type=number min=-255 max=255 required>
<h3>Alexa Voice Assistant</h3>
Emulate Alexa device: <input type="checkbox" name="AL"><br>
Alexa invocation name: <input name="AI" maxlength="32">
Emulate Alexa device: <input type=checkbox name=AL><br>
Alexa invocation name: <input name=AI maxlength=32>
<h3>Blynk</h3>
<b>Blynk, MQTT and Hue sync all connect to external hosts!<br>
This may impact the responsiveness of the ESP8266.</b><br>
For best results, only use one of these services at a time.<br>
(alternatively, connect a second ESP to them and use the UDP sync)<br><br>
Device Auth token: <input name="BK" maxlength="33"><br>
<i>Clear the token field to disable. </i><a href="https://github.com/Aircoookie/WLED/wiki/Blynk" target="_blank">Setup info</a>
Device Auth token: <input name=BK maxlength=33><br>
<i>Clear the token field to disable. </i><a href=https://github.com/Aircoookie/WLED/wiki/Blynk target=_blank>Setup info</a>
<h3>MQTT</h3>
Enable MQTT: <input type="checkbox" name="MQ"><br>
Broker: <input name="MS" maxlength="32">
Port: <input name="MQPORT" type="number" min="1" max="65535" class="d5"><br>
Enable MQTT: <input type=checkbox name=MQ><br>
Broker: <input name=MS maxlength=32>
Port: <input name=MQPORT type=number min=1 max=65535 class=d5><br>
<b>The MQTT credentials are sent over an unsecured connection.<br>
Never use the MQTT password for another service!</b><br>
Username: <input name="MQUSER" maxlength="40"><br>
Password: <input type="password" input name="MQPASS" maxlength="40"><br>
Client ID: <input name="MQCID" maxlength="40"><br>
Device Topic: <input name="MD" maxlength="32"><br>
Group Topic: <input name="MG" maxlength="32"><br>
<i>Reboot required to apply changes. </i><a href="https://github.com/Aircoookie/WLED/wiki/MQTT" target="_blank">MQTT info</a>
Username: <input name=MQUSER maxlength=40><br>
Password: <input type=password input name=MQPASS maxlength=40><br>
Client ID: <input name=MQCID maxlength=40><br>
Device Topic: <input name=MD maxlength=32><br>
Group Topic: <input name=MG maxlength=32><br>
<i>Reboot required to apply changes. </i><a href=https://github.com/Aircoookie/WLED/wiki/MQTT target=_blank>MQTT info</a>
<h3>Philips Hue</h3>
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
Poll Hue light <input name="HL" type="number" min="1" max="99" > every <input name="HI" type="number" min="100" max="65000"> ms: <input type="checkbox" name="HP"><br>
Then, receive <input type="checkbox" name="HO"> On/Off, <input type="checkbox" name="HB"> Brightness, and <input type="checkbox" name="HC"> Color<br>
Poll Hue light <input name=HL type=number min=1 max=99> every <input name=HI type=number min=100 max=65000> ms: <input type=checkbox name=HP><br>
Then, receive <input type=checkbox name=HO> On/Off, <input type=checkbox name=HB> Brightness, and <input type=checkbox name=HC> Color<br>
Hue Bridge IP:<br>
<input name="H0" type="number" min="0" max="255" > .
<input name="H1" type="number" min="0" max="255" > .
<input name="H2" type="number" min="0" max="255" > .
<input name="H3" type="number" min="0" max="255" ><br>
<input name=H0 type=number min=0 max=255> .
<input name=H1 type=number min=0 max=255> .
<input name=H2 type=number min=0 max=255> .
<input name=H3 type=number min=0 max=255><br>
<b>Press the pushlink button on the bridge, after that save this page!</b><br>
(when first connecting)<br>
Hue status: <span class="hms"> Disabled in this build </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
Hue status: <span class=hms> Disabled in this build </span><hr>
<button type=button onclick=B()>Back</button><button type=submit>Save</button>
</form>
</body>
</html>)=====";
</body></html>)=====";
//time and macro settings

View File

@ -142,10 +142,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
receiveDirect = request->hasArg("RD");
e131SkipOutOfSequence = request->hasArg("ES");
e131Multicast = request->hasArg("EM");
t = request->arg("EP").toInt();
if (t > 0) e131Port = t;
t = request->arg("EU").toInt();
if (t > 0 && t <= 63999) e131Universe = t;
if (t >= 0 && t <= 63999) e131Universe = t;
t = request->arg("DA").toInt();
if (t > 0 && t <= 510) DMXAddress = t;
if (t >= 0 && t <= 510) DMXAddress = t;
t = request->arg("DM").toInt();
if (t >= DMX_MODE_DISABLED && t <= DMX_MODE_MULTIPLE_DRGB) DMXMode = t;
t = request->arg("ET").toInt();

View File

@ -23,6 +23,9 @@
// E1.17 ACN Packet Identifier
const byte ESPAsyncE131::ACN_ID[12] = { 0x41, 0x53, 0x43, 0x2d, 0x45, 0x31, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00 };
// Art-Net Packet Identifier
const byte ESPAsyncE131::ART_ID[8] = { 0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00 };
// Constructor
ESPAsyncE131::ESPAsyncE131(e131_packet_callback_function callback) {
_callback = callback;
@ -34,13 +37,14 @@ ESPAsyncE131::ESPAsyncE131(e131_packet_callback_function callback) {
//
/////////////////////////////////////////////////////////
bool ESPAsyncE131::begin(e131_listen_t type, uint16_t universe, uint8_t n) {
bool ESPAsyncE131::begin(bool multicast, uint16_t port, uint16_t universe, uint8_t n) {
bool success = false;
if (type == E131_UNICAST)
success = initUnicast();
if (type == E131_MULTICAST)
success = initMulticast(universe, n);
if (multicast) {
success = initMulticast(port, universe, n);
} else {
success = initUnicast(port);
}
return success;
}
@ -51,10 +55,10 @@ bool ESPAsyncE131::begin(e131_listen_t type, uint16_t universe, uint8_t n) {
//
/////////////////////////////////////////////////////////
bool ESPAsyncE131::initUnicast() {
bool ESPAsyncE131::initUnicast(uint16_t port) {
bool success = false;
if (udp.listen(E131_DEFAULT_PORT)) {
if (udp.listen(port)) {
udp.onPacket(std::bind(&ESPAsyncE131::parsePacket, this,
std::placeholders::_1));
success = true;
@ -62,13 +66,13 @@ bool ESPAsyncE131::initUnicast() {
return success;
}
bool ESPAsyncE131::initMulticast(uint16_t universe, uint8_t n) {
bool ESPAsyncE131::initMulticast(uint16_t port, uint16_t universe, uint8_t n) {
bool success = false;
IPAddress address = IPAddress(239, 255, ((universe >> 8) & 0xff),
((universe >> 0) & 0xff));
if (udp.listenMulticast(address, E131_DEFAULT_PORT)) {
if (udp.listenMulticast(address, port)) {
ip4_addr_t ifaddr;
ip4_addr_t multicast_addr;
@ -95,22 +99,31 @@ bool ESPAsyncE131::initMulticast(uint16_t universe, uint8_t n) {
/////////////////////////////////////////////////////////
void ESPAsyncE131::parsePacket(AsyncUDPPacket _packet) {
e131_error_t error = ERROR_NONE;
bool error = false, isArtnet = false;
sbuff = reinterpret_cast<e131_packet_t *>(_packet.data());
//E1.31 packet identifier ("ACS-E1.17")
if (memcmp(sbuff->acn_id, ESPAsyncE131::ACN_ID, sizeof(sbuff->acn_id)))
error = ERROR_ACN_ID;
if (htonl(sbuff->root_vector) != ESPAsyncE131::VECTOR_ROOT)
error = ERROR_VECTOR_ROOT;
if (htonl(sbuff->frame_vector) != ESPAsyncE131::VECTOR_FRAME)
error = ERROR_VECTOR_FRAME;
if (sbuff->dmp_vector != ESPAsyncE131::VECTOR_DMP)
error = ERROR_VECTOR_DMP;
if (sbuff->property_values[0] != 0)
error = ERROR_IGNORE;
isArtnet = true; //not E1.31
if (isArtnet) {
if (memcmp(sbuff->art_id, ESPAsyncE131::ART_ID, sizeof(sbuff->art_id)))
error = true; //not "Art-Net"
if (sbuff->art_opcode != ARTNET_OPCODE_OPDMX)
error = true; //not a DMX packet
} else { //E1.31 error handling
if (htonl(sbuff->root_vector) != ESPAsyncE131::VECTOR_ROOT)
error = true;
if (htonl(sbuff->frame_vector) != ESPAsyncE131::VECTOR_FRAME)
error = true;
if (sbuff->dmp_vector != ESPAsyncE131::VECTOR_DMP)
error = true;
if (sbuff->property_values[0] != 0)
error = true;
}
if (!error) {
_callback(sbuff, _packet.remoteIP());
_callback(sbuff, _packet.remoteIP(), isArtnet);
}
}
}

View File

@ -14,9 +14,12 @@
* Author shall not be liable in any event for incidental or consequential
* damages in connection with, or arising out of, the furnishing, performance
* or use of these programs.
*
*/
/*
* Inspired by https://github.com/hideakitai/ArtNet for ArtNet support
*/
#ifndef ESPASYNCE131_H_
#define ESPASYNCE131_H_
@ -40,7 +43,10 @@ typedef struct ip_addr ip4_addr_t;
#endif
// Defaults
#define E131_DEFAULT_PORT 5568
#define E131_DEFAULT_PORT 5568
#define ARTNET_DEFAULT_PORT 6454
#define ARTNET_OPCODE_OPDMX 0x5000
// E1.31 Packet Offsets
#define E131_ROOT_PREAMBLE_SIZE 0
@ -69,7 +75,7 @@ typedef struct ip_addr ip4_addr_t;
// E1.31 Packet Structure
typedef union {
struct {
struct { //E1.31 packet
// Root Layer
uint16_t preamble_size;
uint16_t postamble_size;
@ -97,34 +103,30 @@ typedef union {
uint16_t property_value_count;
uint8_t property_values[513];
} __attribute__((packed));
struct { //Art-Net packet
uint8_t art_id[8];
uint16_t art_opcode;
uint16_t art_protocol_ver;
uint8_t art_sequence_number;
uint8_t art_physical;
uint16_t art_universe;
uint16_t art_length;
uint8_t art_data[512];
} __attribute__((packed));
uint8_t raw[638];
} e131_packet_t;
// Error Types
typedef enum {
ERROR_NONE,
ERROR_IGNORE,
ERROR_ACN_ID,
ERROR_PACKET_SIZE,
ERROR_VECTOR_ROOT,
ERROR_VECTOR_FRAME,
ERROR_VECTOR_DMP
} e131_error_t;
// E1.31 Listener Types
typedef enum {
E131_UNICAST,
E131_MULTICAST
} e131_listen_t;
// new packet callback
typedef void (*e131_packet_callback_function) (e131_packet_t* p, IPAddress clientIP);
typedef void (*e131_packet_callback_function) (e131_packet_t* p, IPAddress clientIP, bool isArtnet);
class ESPAsyncE131 {
private:
// Constants for packet validation
static const uint8_t ACN_ID[];
static const uint8_t ART_ID[];
static const uint32_t VECTOR_ROOT = 4;
static const uint32_t VECTOR_FRAME = 2;
static const uint8_t VECTOR_DMP = 2;
@ -133,8 +135,8 @@ class ESPAsyncE131 {
AsyncUDP udp; // AsyncUDP
// Internal Initializers
bool initUnicast();
bool initMulticast(uint16_t universe, uint8_t n = 1);
bool initUnicast(uint16_t port);
bool initMulticast(uint16_t port, uint16_t universe, uint8_t n = 1);
// Packet parser callback
void parsePacket(AsyncUDPPacket _packet);
@ -145,7 +147,7 @@ class ESPAsyncE131 {
ESPAsyncE131(e131_packet_callback_function callback);
// Generic UDP listener, no physical or IP configuration
bool begin(e131_listen_t type, uint16_t universe = 1, uint8_t n = 1);
bool begin(bool multicast, uint16_t port = E131_DEFAULT_PORT, uint16_t universe = 1, uint8_t n = 1);
};
#endif // ESPASYNCE131_H_
#endif // ESPASYNCE131_H_

View File

@ -72,7 +72,7 @@ void notify(byte callMode, bool followUp)
}
void arlsLock(uint32_t timeoutMs, byte md)
void realtimeLock(uint32_t timeoutMs, byte md)
{
if (!realtimeMode){
for (uint16_t i = 0; i < ledCount; i++)
@ -121,7 +121,7 @@ void handleNotifications()
DEBUG_PRINTLN(rgbUdp.remoteIP());
uint8_t lbuf[packetSize];
rgbUdp.read(lbuf, packetSize);
arlsLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION);
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION);
uint16_t id = 0;
for (uint16_t i = 0; i < packetSize -2; i += 3)
{
@ -208,7 +208,7 @@ void handleNotifications()
realtimeTimeout = 0;
return;
} else {
arlsLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
}
if (udpIn[0] == 1) //warls
{

View File

@ -371,7 +371,7 @@ void WLED::initInterfaces()
ntpConnected = ntpUdp.begin(ntpLocalPort);
initBlynk(blynkApiKey);
e131.begin((e131Multicast) ? E131_MULTICAST : E131_UNICAST, e131Universe, E131_MAX_UNIVERSE_COUNT);
e131.begin(e131Multicast, e131Port, e131Universe, E131_MAX_UNIVERSE_COUNT);
reconnectHue();
initMqtt();
interfacesInited = true;

View File

@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2004100
#define VERSION 2004120
// ESP8266-01 (blue) got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.4.2 and the setting 512K(No SPIFFS).
@ -227,6 +227,7 @@ WLED_GLOBAL bool arlsDisableGammaCorrection _INIT(true); // activate if
WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to force max brightness if source has very dark colors that would be black
WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings for E1.31 (sACN) protocol (only DMX_MODE_MULTIPLE_* can span over consequtive universes)
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 byte DMXOldDimmer _INIT(0); // only update brightness on change

View File

@ -7,7 +7,7 @@
*/
//eeprom Version code, enables default settings instead of 0 init on update
#define EEPVER 18
#define EEPVER 19
//0 -> old version, default
//1 -> 0.4p 1711272 and up
//2 -> 0.4p 1711302 and up
@ -27,6 +27,7 @@
//16-> 0.9.1
//17-> 0.9.1-dmx
//18-> 0.9.1-e131
//19-> 0.9.1n
void commit()
{
@ -210,6 +211,9 @@ void saveSettingsToEEPROM()
EEPROM.write(2181, macroNl);
EEPROM.write(2182, macroDoublePress);
EEPROM.write(2187, e131Port & 0xFF);
EEPROM.write(2188, (e131Port >> 8) & 0xFF);
EEPROM.write(2189, e131SkipOutOfSequence);
EEPROM.write(2190, e131Universe & 0xFF);
EEPROM.write(2191, (e131Universe >> 8) & 0xFF);
@ -515,6 +519,11 @@ void loadSettingsFromEEPROM(bool first)
e131SkipOutOfSequence = true;
}
if (lastEEPROMversion > 18)
{
e131Port = EEPROM.read(2187) + ((EEPROM.read(2188) << 8) & 0xFF00);
}
receiveDirect = !EEPROM.read(2200);
notifyMacro = EEPROM.read(2201);

View File

@ -71,7 +71,7 @@ void handleSerial()
if (--count > 0) state = AdaState::Data_Red;
else {
if (!realtimeMode && bri == 0) strip.setBrightness(briLast);
arlsLock(realtimeTimeoutMs, REALTIME_MODE_ADALIGHT);
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_ADALIGHT);
strip.show();
state = AdaState::Header_A;

View File

@ -63,9 +63,10 @@ char* XML_response(AsyncWebServerRequest *request, char* dest)
if (realtimeMode)
{
String mesg = "Live ";
if (realtimeMode == REALTIME_MODE_E131)
if (realtimeMode == REALTIME_MODE_E131 || realtimeMode == REALTIME_MODE_ARTNET)
{
mesg += "E1.31 mode ";
mesg += (realtimeMode == REALTIME_MODE_E131) ? "E1.31" : "Art-Net";
mesg += " mode ";
mesg += DMXMode;
mesg += F(" at DMX Address ");
mesg += DMXAddress;
@ -326,6 +327,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',"SM",notifyMacro);
sappend('c',"S2",notifyTwice);
sappend('c',"RD",receiveDirect);
sappend('v',"EP",e131Port);
sappend('c',"ES",e131SkipOutOfSequence);
sappend('c',"EM",e131Multicast);
sappend('v',"EU",e131Universe);