Add Art-Net support (#417)
This commit is contained in:
parent
3006d25406
commit
e12757dbb9
@ -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
|
||||
|
@ -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
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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>
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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_
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user