Sync segment options.

Freeze effect.
Repeat last segment until end.
This commit is contained in:
Blaz Kristan 2021-12-17 20:33:48 +01:00
parent c27117e99e
commit 1270f2d577
13 changed files with 2317 additions and 2240 deletions

View File

@ -239,8 +239,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(receiveNotificationColor, if_sync_recv["col"]); CJSON(receiveNotificationColor, if_sync_recv["col"]);
CJSON(receiveNotificationEffects, if_sync_recv["fx"]); CJSON(receiveNotificationEffects, if_sync_recv["fx"]);
CJSON(receiveGroups, if_sync_recv["grp"]); CJSON(receiveGroups, if_sync_recv["grp"]);
CJSON(receiveSegmentOptions, if_sync_recv["seg"]);
//! following line might be a problem if called after boot //! following line might be a problem if called after boot
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects); receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions);
JsonObject if_sync_send = if_sync["send"]; JsonObject if_sync_send = if_sync["send"];
prev = notifyDirectDefault; prev = notifyDirectDefault;
@ -628,6 +629,7 @@ void serializeConfig() {
if_sync_recv["col"] = receiveNotificationColor; if_sync_recv["col"] = receiveNotificationColor;
if_sync_recv["fx"] = receiveNotificationEffects; if_sync_recv["fx"] = receiveNotificationEffects;
if_sync_recv["grp"] = receiveGroups; if_sync_recv["grp"] = receiveGroups;
if_sync_recv["seg"] = receiveSegmentOptions;
JsonObject if_sync_send = if_sync.createNestedObject("send"); JsonObject if_sync_send = if_sync.createNestedObject("send");
if_sync_send[F("dir")] = notifyDirect; if_sync_send[F("dir")] = notifyDirect;

View File

@ -609,11 +609,12 @@ input[type=range]:active + .sliderbubble {
width: 216px; width: 216px;
} }
.btn-xs { .btn-xs {
width: 39px; width: 42px;
height: 42px;
margin: 2px 0 0 0; margin: 2px 0 0 0;
} }
.btn-pl-add { .btn-pl-add {
margin-left: 9px; margin-left: 5px;
} }
@ -645,7 +646,7 @@ input[type=range]:active + .sliderbubble {
.sel-pl { .sel-pl {
width: 192px; width: 192px;
background-position: 168px 16px; background-position: 168px 16px;
margin: 8px 7px 0 0; margin: 8px 3px 0 0;
} }
.sel-ple { .sel-ple {

View File

@ -141,7 +141,7 @@
<div id="Effects" class="tabcontent"> <div id="Effects" class="tabcontent">
<p class="labels">Effect speed</p> <p class="labels">Effect speed</p>
<div class="staytop"> <div class="staytop">
<i class="icons slider-icon">&#xe325;</i> <i class="icons slider-icon" onclick="tglFreeze()">&#xe325;</i>
<div class="sliderwrap il"> <div class="sliderwrap il">
<input id="sliderSpeed" class="noslide" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" /> <input id="sliderSpeed" class="noslide" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
<output class="sliderbubble hidden"></output> <output class="sliderbubble hidden"></output>

View File

@ -603,7 +603,6 @@ function populateSegments(s)
</tr> </tr>
</table> </table>
<div class="h" id="seg${i}len"></div> <div class="h" id="seg${i}len"></div>
<button class="btn btn-i btn-xs del" id="segd${i}" onclick="delSeg(${i})"><i class="icons btn-icon">&#xe037;</i></button>
<label class="check revchkl"> <label class="check revchkl">
Reverse direction Reverse direction
<input type="checkbox" id="seg${i}rev" onchange="setRev(${i})" ${inst.rev ? "checked":""}> <input type="checkbox" id="seg${i}rev" onchange="setRev(${i})" ${inst.rev ? "checked":""}>
@ -614,6 +613,10 @@ function populateSegments(s)
<input type="checkbox" id="seg${i}mi" onchange="setMi(${i})" ${inst.mi ? "checked":""}> <input type="checkbox" id="seg${i}mi" onchange="setMi(${i})" ${inst.mi ? "checked":""}>
<span class="checkmark schk"></span> <span class="checkmark schk"></span>
</label> </label>
<div class="del">
<button class="btn btn-i btn-xs" id="segr${i}" title="Repeat until end" onclick="rptSeg(${i})"><i class="icons btn-icon">&#xe22d;</i></button>
<button class="btn btn-i btn-xs" id="segd${i}" title="Delete" onclick="delSeg(${i})"><i class="icons btn-icon">&#xe037;</i></button>
</div>
</div> </div>
</div><br>`; </div><br>`;
} }
@ -627,10 +630,12 @@ function populateSegments(s)
noNewSegs = false; noNewSegs = false;
} }
for (var i = 0; i <= lSeg; i++) { for (var i = 0; i <= lSeg; i++) {
updateLen(i); updateLen(i);
updateTrail(d.getElementById(`seg${i}bri`)); updateTrail(d.getElementById(`seg${i}bri`));
if (segCount < 2) d.getElementById(`segd${lSeg}`).style.display = "none"; d.getElementById(`segr${i}`).style.display = "none";
} }
if (segCount < 2) d.getElementById(`segd${lSeg}`).style.display = "none";
if (!noNewSegs && (cfg.comp.seglen?parseInt(d.getElementById(`seg${lSeg}s`).value):0)+parseInt(d.getElementById(`seg${lSeg}e`).value)<ledCount) d.getElementById(`segr${lSeg}`).style.display = "inline";
d.getElementById('rsbtn').style.display = (segCount > 1) ? "inline":"none"; d.getElementById('rsbtn').style.display = (segCount > 1) ? "inline":"none";
} }
@ -1542,6 +1547,13 @@ function setSegBri(s){
requestJson(obj); requestJson(obj);
} }
function tglFreeze(s=null)
{
var obj = {"seg": {"frz": "t"}}; // toggle
if (s!==null) obj.id = s;
requestJson(obj);
}
function setX(ind = null) { function setX(ind = null) {
if (ind === null) { if (ind === null) {
ind = parseInt(d.querySelector('#fxlist input[name="fx"]:checked').value); ind = parseInt(d.querySelector('#fxlist input[name="fx"]:checked').value);

View File

@ -5,7 +5,8 @@ function gId(s)
{ {
return d.getElementById(s); return d.getElementById(s);
} }
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings");}function B(){window.open("/settings","_self");} function H(){window.open("https://kno.wled.ge/interfaces/udp-notifier/");}
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;} 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;} } 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 FC() function FC()
@ -82,6 +83,7 @@ UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required
</tr> </tr>
</table><br> </table><br>
Receive: <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br> Receive: <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br>
<input type="checkbox" name="SO">Segment options<br>
Send notifications on direct change: <input type="checkbox" name="SD"><br> Send notifications on direct change: <input type="checkbox" name="SD"><br>
Send notifications on button press or IR: <input type="checkbox" name="SB"><br> Send notifications on button press or IR: <input type="checkbox" name="SB"><br>
Send Alexa notifications: <input type="checkbox" name="SA"><br> Send Alexa notifications: <input type="checkbox" name="SA"><br>
@ -117,45 +119,45 @@ DMX mode:
<option value=5>Dimmer + Multi RGB</option> <option value=5>Dimmer + Multi RGB</option>
<option value=6>Multi RGBW</option> <option value=6>Multi RGBW</option>
</select><br> </select><br>
<a href="https://github.com/Aircoookie/WLED/wiki/E1.31-DMX" target="_blank">E1.31 info</a><br> <a href="https://kno.wled.ge/interfaces/e1.31-dmx/" target="_blank">E1.31 info</a><br>
Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br> Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
Force max brightness: <input type="checkbox" name="FB"><br> Force max brightness: <input type="checkbox" name="FB"><br>
Disable realtime gamma correction: <input type="checkbox" name="RG"><br> Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required> Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required>
<h3>Alexa Voice Assistant</h3> <h3>Alexa Voice Assistant</h3>
Emulate Alexa device: <input type="checkbox" name="AL"><br> Emulate Alexa device: <input type="checkbox" name="AL"><br>
Alexa invocation name: <input name="AI" maxlength="32"> Alexa invocation name: <input type="text" name="AI" maxlength="32">
<h3>Blynk</h3> <h3>Blynk</h3>
<b>Blynk, MQTT and Hue sync all connect to external hosts!<br> <b>Blynk, MQTT and Hue sync all connect to external hosts!<br>
This may impact the responsiveness of the ESP8266.</b><br> This may impact the responsiveness of the ESP8266.</b><br>
For best results, only use one of these services at a time.<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> (alternatively, connect a second ESP to them and use the UDP sync)<br><br>
Host: <input name="BH" maxlength="32"> Host: <input type="text" name="BH" maxlength="32">
Port: <input name="BP" type="number" min="1" max="65535" value="80" class="d5"><br> Port: <input name="BP" type="number" min="1" max="65535" value="80" class="d5"><br>
Device Auth token: <input name="BK" maxlength="33"><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> <i>Clear the token field to disable. </i><a href="https://kno.wled.ge/interfaces/blynk/" target="_blank">Setup info</a>
<h3>MQTT</h3> <h3>MQTT</h3>
Enable MQTT: <input type="checkbox" name="MQ"><br> Enable MQTT: <input type="checkbox" name="MQ"><br>
Broker: <input name="MS" maxlength="32"> Broker: <input type="text" name="MS" maxlength="32">
Port: <input name="MQPORT" type="number" min="1" max="65535" class="d5"><br> Port: <input name="MQPORT" type="number" min="1" max="65535" class="d5"><br>
<b>The MQTT credentials are sent over an unsecured connection.<br> <b>The MQTT credentials are sent over an unsecured connection.<br>
Never use the MQTT password for another service!</b><br> Never use the MQTT password for another service!</b><br>
Username: <input name="MQUSER" maxlength="40"><br> Username: <input type="text" name="MQUSER" maxlength="40"><br>
Password: <input type="password" name="MQPASS" maxlength="64"><br> Password: <input type="password" name="MQPASS" maxlength="64"><br>
Client ID: <input name="MQCID" maxlength="40"><br> Client ID: <input type="text" name="MQCID" maxlength="40"><br>
Device Topic: <input name="MD" maxlength="32"><br> Device Topic: <input type="text" name="MD" maxlength="32"><br>
Group Topic: <input name="MG" maxlength="32"><br> Group Topic: <input type="text" name="MG" maxlength="32"><br>
Publish on button press: <input type="checkbox" name="BM"><br> Publish on button press: <input type="checkbox" name="BM"><br>
<i>Reboot required to apply changes. </i><a href="https://github.com/Aircoookie/WLED/wiki/MQTT" target="_blank">MQTT info</a> <i>Reboot required to apply changes. </i><a href="https://kno.wled.ge/interfaces/mqtt/" target="_blank">MQTT info</a>
<h3>Philips Hue</h3> <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> <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> 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> 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> Hue Bridge IP:<br>
<input name="H0" type="number" min="0" max="255" > . <input name="H0" type="number" class="s" min="0" max="255" > .
<input name="H1" type="number" min="0" max="255" > . <input name="H1" type="number" class="s" min="0" max="255" > .
<input name="H2" type="number" min="0" max="255" > . <input name="H2" type="number" class="s" min="0" max="255" > .
<input name="H3" type="number" min="0" max="255" ><br> <input name="H3" type="number" class="s" min="0" max="255" ><br>
<b>Press the pushlink button on the bridge, after that save this page!</b><br> <b>Press the pushlink button on the bridge, after that save this page!</b><br>
(when first connecting)<br> (when first connecting)<br>
Hue status: <span class="sip"> Disabled in this build </span><hr> Hue status: <span class="sip"> Disabled in this build </span><hr>

View File

@ -244,7 +244,7 @@ type="button" onclick="Save()">Save</button></form></body></html>)=====";
// Autogenerated from wled00/data/settings_sync.htm, do not edit!! // Autogenerated from wled00/data/settings_sync.htm, do not edit!!
const char PAGE_settings_sync[] PROGMEM = R"=====(<!DOCTYPE html><html lang="en"><head><meta name="viewport" content="width=500"> const char PAGE_settings_sync[] PROGMEM = R"=====(<!DOCTYPE html><html lang="en"><head><meta name="viewport" content="width=500">
<meta charset="utf-8"><title>Sync Settings</title><script> <meta charset="utf-8"><title>Sync Settings</title><script>
var d=document;function gId(e){return d.getElementById(e)}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings")}function B(){window.open("/settings","_self")}function adj(){6454==d.Sf.DI.value?(1==d.Sf.DA.value&&(d.Sf.DA.value=0),1==d.Sf.EU.value&&(d.Sf.EU.value=0)):5568==d.Sf.DI.value&&(0==d.Sf.DA.value&&(d.Sf.DA.value=1),0==d.Sf.EU.value&&(d.Sf.EU.value=1))}function FC(){for(j=0;j<8;j++)gId("G"+(j+1)).checked=gId("GS").value>>j&1,gId("R"+(j+1)).checked=gId("GR").value>>j&1}function GC(){var e=0,d=0,n=1;for(j=0;j<8;j++)e+=gId("G"+(j+1)).checked*n,d+=gId("R"+(j+1)).checked*n,n*=2;gId("GS").value=e,gId("GR").value=d}function SP(){var e=d.Sf.DI.value;gId("xp").style.display=e>0?"none":"block",e>0&&(d.Sf.EP.value=e)}function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568:d.Sf.DI.value=5568;break;case 6454:d.Sf.DI.value=6454;break;case 4048:d.Sf.DI.value=4048}SP(),FC()}function S(){GetV(),SetVal()}function GetV() { var d=document;function gId(e){return d.getElementById(e)}function H(){window.open("https://kno.wled.ge/interfaces/udp-notifier/")}function B(){window.open("/settings","_self")}function adj(){6454==d.Sf.DI.value?(1==d.Sf.DA.value&&(d.Sf.DA.value=0),1==d.Sf.EU.value&&(d.Sf.EU.value=0)):5568==d.Sf.DI.value&&(0==d.Sf.DA.value&&(d.Sf.DA.value=1),0==d.Sf.EU.value&&(d.Sf.EU.value=1))}function FC(){for(j=0;j<8;j++)gId("G"+(j+1)).checked=gId("GS").value>>j&1,gId("R"+(j+1)).checked=gId("GR").value>>j&1}function GC(){var e=0,d=0,n=1;for(j=0;j<8;j++)e+=gId("G"+(j+1)).checked*n,d+=gId("R"+(j+1)).checked*n,n*=2;gId("GS").value=e,gId("GR").value=d}function SP(){var e=d.Sf.DI.value;gId("xp").style.display=e>0?"none":"block",e>0&&(d.Sf.EP.value=e)}function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568:d.Sf.DI.value=5568;break;case 6454:d.Sf.DI.value=6454;break;case 4048:d.Sf.DI.value=4048}SP(),FC()}function S(){GetV(),SetVal()}function GetV() {
%CSS%%SCSS%</head><body onload="S()"><form %CSS%%SCSS%</head><body onload="S()"><form
id="form_s" name="Sf" method="post" onsubmit="GC()"><div class="helpB"><button id="form_s" name="Sf" method="post" onsubmit="GC()"><div class="helpB"><button
type="button" onclick="H()">?</button></div><button type="button" onclick="B()"> type="button" onclick="H()">?</button></div><button type="button" onclick="B()">
@ -268,11 +268,12 @@ name="R5"></td><td><input type="checkbox" id="R6" name="R6"></td><td><input
type="checkbox" id="R7" name="R7"></td><td><input type="checkbox" id="R8" type="checkbox" id="R7" name="R7"></td><td><input type="checkbox" id="R8"
name="R8"></td></tr></table><br>Receive: <input type="checkbox" name="RB"> name="R8"></td></tr></table><br>Receive: <input type="checkbox" name="RB">
Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox"
name="RX">Effects<br>Send notifications on direct change: <input name="RX">Effects<br><input type="checkbox" name="SO">Segment options<br>
type="checkbox" name="SD"><br>Send notifications on button press or IR: <input Send notifications on direct change: <input type="checkbox" name="SD"><br>
type="checkbox" name="SB"><br>Send Alexa notifications: <input type="checkbox" Send notifications on button press or IR: <input type="checkbox" name="SB"><br>
name="SA"><br>Send Philips Hue change notifications: <input type="checkbox" Send Alexa notifications: <input type="checkbox" name="SA"><br>
name="SH"><br>Send Macro notifications: <input type="checkbox" name="SM"><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"><br><i> Send notifications twice: <input type="checkbox" name="S2"><br><i>
Reboot required to apply changes.</i><h3>Instance List</h3> Reboot required to apply changes.</i><h3>Instance List</h3>
Enable instance list: <input type="checkbox" name="NL"><br> Enable instance list: <input type="checkbox" name="NL"><br>
@ -292,43 +293,44 @@ Disabled</option><option value="1">Single RGB</option><option value="2">
Single DRGB</option><option value="3">Effect</option><option value="4">Multi RGB Single DRGB</option><option value="3">Effect</option><option value="4">Multi RGB
</option><option value="5">Dimmer + Multi RGB</option><option value="6"> </option><option value="5">Dimmer + Multi RGB</option><option value="6">
Multi RGBW</option></select><br><a Multi RGBW</option></select><br><a
href="https://github.com/Aircoookie/WLED/wiki/E1.31-DMX" target="_blank"> href="https://kno.wled.ge/interfaces/e1.31-dmx/" target="_blank">E1.31 info</a>
E1.31 info</a><br>Timeout: <input name="ET" type="number" min="1" max="65000" <br>Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
required> ms<br>Force max brightness: <input type="checkbox" name="FB"><br> Force max brightness: <input type="checkbox" name="FB"><br>
Disable realtime gamma correction: <input type="checkbox" name="RG"><br> Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" Realtime LED offset: <input name="WO" type="number" min="-255" max="255"
required><h3>Alexa Voice Assistant</h3>Emulate Alexa device: <input required><h3>Alexa Voice Assistant</h3>Emulate Alexa device: <input
type="checkbox" name="AL"><br>Alexa invocation name: <input name="AI" type="checkbox" name="AL"><br>Alexa invocation name: <input type="text"
maxlength="32"><h3>Blynk</h3><b> name="AI" maxlength="32"><h3>Blynk</h3><b>
Blynk, MQTT and Hue sync all connect to external hosts!<br> Blynk, MQTT and Hue sync all connect to external hosts!<br>
This may impact the responsiveness of the ESP8266.</b><br> This may impact the responsiveness of the ESP8266.</b><br>
For best results, only use one of these services at a time.<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>Host: (alternatively, connect a second ESP to them and use the UDP sync)<br><br>Host:
<input name="BH" maxlength="32"> Port: <input name="BP" type="number" min="1" <input type="text" name="BH" maxlength="32"> Port: <input name="BP"
max="65535" value="80" class="d5"><br>Device Auth token: <input name="BK" type="number" min="1" max="65535" value="80" class="d5"><br>Device Auth token:
maxlength="33"><br><i>Clear the token field to disable. </i><a <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 href="https://kno.wled.ge/interfaces/blynk/" target="_blank">Setup info</a><h3>
</a><h3>MQTT</h3>Enable MQTT: <input type="checkbox" name="MQ"><br>Broker: MQTT</h3>Enable MQTT: <input type="checkbox" name="MQ"><br>Broker: <input
<input name="MS" maxlength="32"> Port: <input name="MQPORT" type="number" type="text" name="MS" maxlength="32"> Port: <input name="MQPORT" type="number"
min="1" max="65535" class="d5"><br><b> min="1" max="65535" class="d5"><br><b>
The MQTT credentials are sent over an unsecured connection.<br> The MQTT credentials are sent over an unsecured connection.<br>
Never use the MQTT password for another service!</b><br>Username: <input Never use the MQTT password for another service!</b><br>Username: <input
name="MQUSER" maxlength="40"><br>Password: <input type="password" name="MQPASS" type="text" name="MQUSER" maxlength="40"><br>Password: <input type="password"
maxlength="64"><br>Client ID: <input name="MQCID" maxlength="40"><br> name="MQPASS" maxlength="64"><br>Client ID: <input type="text" name="MQCID"
Device Topic: <input name="MD" maxlength="32"><br>Group Topic: <input name="MG" maxlength="40"><br>Device Topic: <input type="text" name="MD" maxlength="32">
maxlength="32"><br>Publish on button press: <input type="checkbox" name="BM"> <br>Group Topic: <input type="text" name="MG" maxlength="32"><br>
<br><i>Reboot required to apply changes. </i><a Publish on button press: <input type="checkbox" name="BM"><br><i>
href="https://github.com/Aircoookie/WLED/wiki/MQTT" target="_blank">MQTT info Reboot required to apply changes. </i><a
</a><h3>Philips Hue</h3><i> href="https://kno.wled.ge/interfaces/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. 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 </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 <input name="HI" type="number" min="100" max="65000"> ms: <input
type="checkbox" name="HP"><br>Then, receive <input type="checkbox" name="HO"> type="checkbox" name="HP"><br>Then, receive <input type="checkbox" name="HO">
On/Off, <input type="checkbox" name="HB"> Brightness, and <input On/Off, <input type="checkbox" name="HB"> Brightness, and <input
type="checkbox" name="HC"> Color<br>Hue Bridge IP:<br><input name="H0" 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" type="number" class="s" min="0" max="255"> . <input name="H1" type="number"
max="255"> . <input name="H2" type="number" min="0" max="255"> . <input class="s" min="0" max="255"> . <input name="H2" type="number" class="s" min="0"
name="H3" type="number" min="0" max="255"><br><b> max="255"> . <input name="H3" type="number" class="s" min="0" max="255"><br><b>
Press the pushlink button on the bridge, after that save this page!</b><br> Press the pushlink button on the bridge, after that save this page!</b><br>
(when first connecting)<br>Hue status: <span class="sip">Disabled in this build (when first connecting)<br>Hue status: <span class="sip">Disabled in this build
</span><hr><button type="button" onclick="B()">Back</button><button </span><hr><button type="button" onclick="B()">Back</button><button

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,24 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
stop = (len > 0) ? start + len : seg.stop; stop = (len > 0) ? start + len : seg.stop;
} }
// multiply segment 0 (?) if requested untill all LEDs are used
bool repeat = elem["rpt"] | false;
if (repeat && stop>0) {
elem.remove("id"); // remove for recursive call
elem.remove("rpt"); // remove for recursive call
elem.remove("n"); // remove for recursive call
uint16_t len = stop - start;
for (byte i=id+1; i<strip.getMaxSegments(); i++) {
start = start + len;
if (start >= strip.getLengthTotal()) break;
elem["start"] = start;
elem["stop"] = start + len;
elem["rev"] = !elem["rev"]; // alternate reverse on even/odd segments
deserializeSegment(elem, i, presetId); // recursive call with new id
}
return;
}
if (elem["n"]) { if (elem["n"]) {
// name field exists // name field exists
if (seg.name) { //clear old name if (seg.name) { //clear old name
@ -65,6 +83,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
uint16_t grp = elem["grp"] | seg.grouping; uint16_t grp = elem["grp"] | seg.grouping;
uint16_t spc = elem[F("spc")] | seg.spacing; uint16_t spc = elem[F("spc")] | seg.spacing;
uint16_t of = seg.offset; uint16_t of = seg.offset;
if (!(elem[F("spc")].isNull() && elem["grp"].isNull())) effectChanged = true; //send UDP
uint16_t len = 1; uint16_t len = 1;
if (stop > start) len = stop - start; if (stop > start) len = stop - start;
@ -87,7 +106,10 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
bool on = elem["on"] | seg.getOption(SEG_OPTION_ON); bool on = elem["on"] | seg.getOption(SEG_OPTION_ON);
if (elem["on"].is<const char*>() && elem["on"].as<const char*>()[0] == 't') on = !on; if (elem["on"].is<const char*>() && elem["on"].as<const char*>()[0] == 't') on = !on;
seg.setOption(SEG_OPTION_ON, on, id); seg.setOption(SEG_OPTION_ON, on, id);
bool frz = elem["frz"] | seg.getOption(SEG_OPTION_FREEZE);
if (elem["frz"].is<const char*>() && elem["frz"].as<const char*>()[0] == 't') frz = !seg.getOption(SEG_OPTION_FREEZE);
seg.setOption(SEG_OPTION_FREEZE, frz, id);
uint8_t cctPrev = seg.cct; uint8_t cctPrev = seg.cct;
seg.setCCT(elem["cct"] | seg.cct, id); seg.setCCT(elem["cct"] | seg.cct, id);
if (seg.cct != cctPrev && id == strip.getMainSegmentId()) effectChanged = true; //send UDP if (seg.cct != cctPrev && id == strip.getMainSegmentId()) effectChanged = true; //send UDP
@ -152,10 +174,12 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED)); seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR )); seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR ));
if (!(elem[F("sel")].isNull() && elem["rev"].isNull() && elem["on"].isNull() && elem[F("mi")].isNull())) effectChanged = true; //send UDP
//temporary, strip object gets updated via colorUpdated() //temporary, strip object gets updated via colorUpdated()
if (id == strip.getMainSegmentId()) { if (id == strip.getMainSegmentId()) {
byte effectPrev = effectCurrent; byte effectPrev = effectCurrent;
if (getVal(elem["fx"], &effectCurrent, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 0-255 exact value) if (getVal(elem["fx"], &effectCurrent, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value)
if (!presetId && effectCurrent != effectPrev) unloadPlaylist(); //stop playlist if active and FX changed manually if (!presetId && effectCurrent != effectPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
} }
effectSpeed = elem[F("sx")] | effectSpeed; effectSpeed = elem[F("sx")] | effectSpeed;
@ -164,7 +188,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
} else { //permanent } else { //permanent
byte fx = seg.mode; byte fx = seg.mode;
byte fxPrev = fx; byte fxPrev = fx;
if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 0-255 exact value) if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value)
strip.setMode(id, fx); strip.setMode(id, fx);
if (!presetId && seg.mode != fxPrev) unloadPlaylist(); //stop playlist if active and FX changed manually if (!presetId && seg.mode != fxPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
} }
@ -223,12 +247,13 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
} }
strip.setPixelSegment(255); strip.setPixelSegment(255);
strip.trigger(); strip.trigger();
} else { //return to regular effect } else if (!elem["frz"] && iarr.isNull()) { //return to regular effect
seg.setOption(SEG_OPTION_FREEZE, false); seg.setOption(SEG_OPTION_FREEZE, false);
} }
return; // seg.differs(prev); return; // seg.differs(prev);
} }
// deserializes WLED state (fileDoc points to doc object if called from web server)
bool deserializeState(JsonObject root, byte callMode, byte presetId) bool deserializeState(JsonObject root, byte callMode, byte presetId)
{ {
strip.applyToAllSelected = false; strip.applyToAllSelected = false;
@ -391,6 +416,7 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
root[F("spc")] = seg.spacing; root[F("spc")] = seg.spacing;
root[F("of")] = seg.offset; root[F("of")] = seg.offset;
root["on"] = seg.getOption(SEG_OPTION_ON); root["on"] = seg.getOption(SEG_OPTION_ON);
root["frz"] = seg.getOption(SEG_OPTION_FREEZE);
byte segbri = seg.opacity; byte segbri = seg.opacity;
root["bri"] = (segbri) ? segbri : 255; root["bri"] = (segbri) ? segbri : 255;
root["cct"] = seg.cct; root["cct"] = seg.cct;

View File

@ -85,7 +85,7 @@ void colorUpdated(int callMode)
bool someSel = false; bool someSel = false;
if (callMode == CALL_MODE_NOTIFICATION) { if (callMode == CALL_MODE_NOTIFICATION) {
someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects); someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions);
} }
//Notifier: apply received FX to selected segments only if actually receiving FX //Notifier: apply received FX to selected segments only if actually receiving FX

View File

@ -217,7 +217,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
receiveNotificationBrightness = request->hasArg(F("RB")); receiveNotificationBrightness = request->hasArg(F("RB"));
receiveNotificationColor = request->hasArg(F("RC")); receiveNotificationColor = request->hasArg(F("RC"));
receiveNotificationEffects = request->hasArg(F("RX")); receiveNotificationEffects = request->hasArg(F("RX"));
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects); receiveSegmentOptions = request->hasArg(F("SO"));
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions);
notifyDirectDefault = request->hasArg(F("SD")); notifyDirectDefault = request->hasArg(F("SD"));
notifyDirect = notifyDirectDefault; notifyDirect = notifyDirectDefault;
notifyButton = request->hasArg(F("SB")); notifyButton = request->hasArg(F("SB"));
@ -753,7 +754,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
strip.applyToAllSelected = true; strip.applyToAllSelected = true;
strip.setColor(2, t[0], t[1], t[2], t[3]); strip.setColor(2, t[0], t[1], t[2], t[3]);
} else { } else {
selseg.setColor(2,((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24)), selectedSeg); // defined above (SS=) selseg.setColor(2, RGBW32(t[0], t[1], t[2], t[3]), selectedSeg); // defined above (SS=)
} }
} }

View File

@ -4,7 +4,7 @@
* UDP sync notifier / Realtime / Hyperion / TPM2.NET * UDP sync notifier / Realtime / Hyperion / TPM2.NET
*/ */
#define WLEDPACKETSIZE 39 #define WLEDPACKETSIZE (40+(MAX_NUM_SEGMENTS*3))
#define UDP_IN_MAXSIZE 1472 #define UDP_IN_MAXSIZE 1472
#define PRESUMED_NETWORK_DELAY 3 //how many ms could it take on avg to reach the receiver? This will be added to transmitted times #define PRESUMED_NETWORK_DELAY 3 //how many ms could it take on avg to reach the receiver? This will be added to transmitted times
@ -42,8 +42,8 @@ void notify(byte callMode, bool followUp)
//0: old 1: supports white 2: supports secondary color //0: old 1: supports white 2: supports secondary color
//3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette //3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette
//6: supports timebase syncing, 29 byte packet 7: supports tertiary color 8: supports sys time sync, 36 byte packet //6: supports timebase syncing, 29 byte packet 7: supports tertiary color 8: supports sys time sync, 36 byte packet
//9: supports sync groups, 37 byte packet 10: supports CCT, 39 byte packet //9: supports sync groups, 37 byte packet 10: supports CCT, 39 byte packet 11: per segment options, variable packet length (40+MAX_NUM_SEGMENTS*3)
udpOut[11] = 10; udpOut[11] = 11;
udpOut[12] = colSec[0]; udpOut[12] = colSec[0];
udpOut[13] = colSec[1]; udpOut[13] = colSec[1];
udpOut[14] = colSec[2]; udpOut[14] = colSec[2];
@ -84,7 +84,15 @@ void notify(byte callMode, bool followUp)
//0: byte 38 contains 0-255 value, 255: no valid CCT, 1-254: Kelvin value MSB //0: byte 38 contains 0-255 value, 255: no valid CCT, 1-254: Kelvin value MSB
udpOut[37] = strip.hasCCTBus() ? 0 : 255; //check this is 0 for the next value to be significant udpOut[37] = strip.hasCCTBus() ? 0 : 255; //check this is 0 for the next value to be significant
udpOut[38] = mainseg.cct; udpOut[38] = mainseg.cct;
udpOut[39] = strip.getMaxSegments();
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment &selseg = strip.getSegment(i);
udpOut[40+i*3] = selseg.options & 0x0F; //only take into account mirrored, selected, on, reversed
udpOut[41+i*3] = selseg.spacing;
udpOut[42+i*3] = selseg.grouping;
}
IPAddress broadcastIp; IPAddress broadcastIp;
broadcastIp = ~uint32_t(Network.subnetMask()) | uint32_t(Network.gatewayIP()); broadcastIp = ~uint32_t(Network.subnetMask()) | uint32_t(Network.gatewayIP());
@ -282,6 +290,20 @@ void handleNotifications()
//apply effects from notification //apply effects from notification
if (version < 200 && (receiveNotificationEffects || !someSel)) if (version < 200 && (receiveNotificationEffects || !someSel))
{ {
if (currentPlaylist>=0) unloadPlaylist();
if (version>10) {
if (receiveSegmentOptions) {
// will not sync start & stop
uint8_t srcSegs = udpIn[39];
if (srcSegs > strip.getMaxSegments()) srcSegs = strip.getMaxSegments();
for (uint8_t i = 0; i < srcSegs; i++) {
WS2812FX::Segment& selseg = strip.getSegment(i);
for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[40+i*3] >> j) & 0x01); //only take into account mirrored, selected, on, reversed
selseg.spacing = udpIn[41+i*3];
selseg.grouping = udpIn[42+i*3];
}
}
}
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8]; if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
effectSpeed = udpIn[9]; effectSpeed = udpIn[9];
if (version > 2) effectIntensity = udpIn[16]; if (version > 2) effectIntensity = udpIn[16];

View File

@ -305,6 +305,7 @@ WLED_GLOBAL uint8_t receiveGroups _INIT(0x01); // sync receiv
WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications
WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color
WLED_GLOBAL bool receiveNotificationEffects _INIT(true); // apply effects setup WLED_GLOBAL bool receiveNotificationEffects _INIT(true); // apply effects setup
WLED_GLOBAL bool receiveSegmentOptions _INIT(false); // apply segment options
WLED_GLOBAL bool notifyDirect _INIT(false); // send notification if change via UI or HTTP API WLED_GLOBAL bool notifyDirect _INIT(false); // send notification if change via UI or HTTP API
WLED_GLOBAL bool notifyButton _INIT(false); // send if updated by button or infrared remote WLED_GLOBAL bool notifyButton _INIT(false); // send if updated by button or infrared remote
WLED_GLOBAL bool notifyAlexa _INIT(false); // send notification if updated via Alexa WLED_GLOBAL bool notifyAlexa _INIT(false); // send notification if updated via Alexa

View File

@ -465,6 +465,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',SET_F("RB"),receiveNotificationBrightness); sappend('c',SET_F("RB"),receiveNotificationBrightness);
sappend('c',SET_F("RC"),receiveNotificationColor); sappend('c',SET_F("RC"),receiveNotificationColor);
sappend('c',SET_F("RX"),receiveNotificationEffects); sappend('c',SET_F("RX"),receiveNotificationEffects);
sappend('c',SET_F("SO"),receiveSegmentOptions);
sappend('c',SET_F("SD"),notifyDirectDefault); sappend('c',SET_F("SD"),notifyDirectDefault);
sappend('c',SET_F("SB"),notifyButton); sappend('c',SET_F("SB"),notifyButton);
sappend('c',SET_F("SH"),notifyHue); sappend('c',SET_F("SH"),notifyHue);