Merge pull request #2427 from Aircoookie/sync-seg
Sync segment options.
This commit is contained in:
commit
0ca7699fe5
@ -240,8 +240,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;
|
||||||
@ -640,6 +641,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;
|
||||||
|
@ -22,11 +22,6 @@ void colorFromUint24(uint32_t in, bool secondary)
|
|||||||
_col[2] = B(in);
|
_col[2] = B(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
//store color components in uint32_t
|
|
||||||
uint32_t colorFromRgbw(byte* rgbw) {
|
|
||||||
return RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//relatively change white brightness, minumum A=5
|
//relatively change white brightness, minumum A=5
|
||||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary)
|
void relativeChangeWhite(int8_t amount, byte lowerBoundary)
|
||||||
{
|
{
|
||||||
@ -259,7 +254,7 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb)
|
|||||||
rgbw[1] = ((uint16_t) correctionRGB[1] * G(rgb)) /255; // correct G
|
rgbw[1] = ((uint16_t) correctionRGB[1] * G(rgb)) /255; // correct G
|
||||||
rgbw[2] = ((uint16_t) correctionRGB[2] * B(rgb)) /255; // correct B
|
rgbw[2] = ((uint16_t) correctionRGB[2] * B(rgb)) /255; // correct B
|
||||||
rgbw[3] = W(rgb);
|
rgbw[3] = W(rgb);
|
||||||
return colorFromRgbw(rgbw);
|
return RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
//approximates a Kelvin color temperature from an RGB color.
|
//approximates a Kelvin color temperature from an RGB color.
|
||||||
@ -299,4 +294,4 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) {
|
|||||||
uint16_t k = 8080 + (225-r) *86;
|
uint16_t k = 8080 + (225-r) *86;
|
||||||
return (k > 10091) ? 10091 : k;
|
return (k > 10091) ? 10091 : k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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"></i>
|
<i class="icons slider-icon" onclick="tglFreeze()"></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>
|
||||||
|
@ -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"></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"></i></button>
|
||||||
|
<button class="btn btn-i btn-xs" id="segd${i}" title="Delete" onclick="delSeg(${i})"><i class="icons btn-icon"></i></button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div><br>`;
|
</div><br>`;
|
||||||
}
|
}
|
||||||
@ -627,10 +630,13 @@ 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";
|
let segr = d.getElementById(`segr${i}`);
|
||||||
|
if (segr) segr.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";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,7 +878,7 @@ function updateLen(s)
|
|||||||
{
|
{
|
||||||
if (!d.getElementById(`seg${s}s`)) return;
|
if (!d.getElementById(`seg${s}s`)) return;
|
||||||
var start = parseInt(d.getElementById(`seg${s}s`).value);
|
var start = parseInt(d.getElementById(`seg${s}s`).value);
|
||||||
var stop = parseInt(d.getElementById(`seg${s}e`).value);
|
var stop = parseInt(d.getElementById(`seg${s}e`).value);
|
||||||
var len = stop - (cfg.comp.seglen?0:start);
|
var len = stop - (cfg.comp.seglen?0:start);
|
||||||
var out = "(delete)";
|
var out = "(delete)";
|
||||||
if (len > 1) {
|
if (len > 1) {
|
||||||
@ -1491,6 +1497,29 @@ function selSeg(s){
|
|||||||
requestJson(obj, false);
|
requestJson(obj, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function rptSeg(s)
|
||||||
|
{
|
||||||
|
var name = d.getElementById(`seg${s}t`).value;
|
||||||
|
var start = parseInt(d.getElementById(`seg${s}s`).value);
|
||||||
|
var stop = parseInt(d.getElementById(`seg${s}e`).value);
|
||||||
|
if (stop == 0) {return;}
|
||||||
|
var rev = d.getElementById(`seg${s}rev`).checked;
|
||||||
|
var mi = d.getElementById(`seg${s}mi`).checked;
|
||||||
|
var sel = d.getElementById(`seg${s}sel`).checked;
|
||||||
|
var obj = {"seg": {"id": s, "n": name, "start": start, "stop": (cfg.comp.seglen?start:0)+stop, "rev": rev, "mi": mi, "on": !powered[s], "bri": parseInt(d.getElementById(`seg${s}bri`).value), "sel": sel}};
|
||||||
|
if (d.getElementById(`seg${s}grp`)) {
|
||||||
|
var grp = parseInt(d.getElementById(`seg${s}grp`).value);
|
||||||
|
var spc = parseInt(d.getElementById(`seg${s}spc`).value);
|
||||||
|
var ofs = parseInt(d.getElementById(`seg${s}of` ).value);
|
||||||
|
obj.seg.grp = grp;
|
||||||
|
obj.seg.spc = spc;
|
||||||
|
obj.seg.of = ofs;
|
||||||
|
}
|
||||||
|
obj.seg.rpt = true;
|
||||||
|
expand(s);
|
||||||
|
requestJson(obj);
|
||||||
|
}
|
||||||
|
|
||||||
function setSeg(s){
|
function setSeg(s){
|
||||||
var name = d.getElementById(`seg${s}t`).value;
|
var name = d.getElementById(`seg${s}t`).value;
|
||||||
var start = parseInt(d.getElementById(`seg${s}s`).value);
|
var start = parseInt(d.getElementById(`seg${s}s`).value);
|
||||||
@ -1542,6 +1571,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);
|
||||||
|
@ -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()
|
||||||
@ -81,7 +82,8 @@ UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required
|
|||||||
<td><input type="checkbox" id="R8" name="R8"></td>
|
<td><input type="checkbox" id="R8" name="R8"></td>
|
||||||
</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>
|
||||||
|
@ -15,9 +15,11 @@ void handleAlexa();
|
|||||||
void onAlexaChange(EspalexaDevice* dev);
|
void onAlexaChange(EspalexaDevice* dev);
|
||||||
|
|
||||||
//blynk.cpp
|
//blynk.cpp
|
||||||
|
#ifndef WLED_DISABLE_BLYNK
|
||||||
void initBlynk(const char* auth, const char* host, uint16_t port);
|
void initBlynk(const char* auth, const char* host, uint16_t port);
|
||||||
void handleBlynk();
|
void handleBlynk();
|
||||||
void updateBlynk();
|
void updateBlynk();
|
||||||
|
#endif
|
||||||
|
|
||||||
//button.cpp
|
//button.cpp
|
||||||
void shortPressAction(uint8_t b=0);
|
void shortPressAction(uint8_t b=0);
|
||||||
@ -56,7 +58,7 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
|
|||||||
//colors.cpp
|
//colors.cpp
|
||||||
void colorFromUint32(uint32_t in, bool secondary = false);
|
void colorFromUint32(uint32_t in, bool secondary = false);
|
||||||
void colorFromUint24(uint32_t in, bool secondary = false);
|
void colorFromUint24(uint32_t in, bool secondary = false);
|
||||||
uint32_t colorFromRgbw(byte* rgbw);
|
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
|
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
|
||||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
||||||
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
||||||
@ -141,7 +143,6 @@ void resetTimebase();
|
|||||||
void toggleOnOff();
|
void toggleOnOff();
|
||||||
void setAllLeds();
|
void setAllLeds();
|
||||||
void setLedsStandard();
|
void setLedsStandard();
|
||||||
bool colorChanged();
|
|
||||||
void colorUpdated(int callMode);
|
void colorUpdated(int callMode);
|
||||||
void updateInterfaces(uint8_t callMode);
|
void updateInterfaces(uint8_t callMode);
|
||||||
void handleTransitions();
|
void handleTransitions();
|
||||||
|
@ -245,7 +245,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()">
|
||||||
@ -269,11 +269,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>
|
||||||
@ -293,43 +294,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
|
||||||
|
4364
wled00/html_ui.h
4364
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
195
wled00/json.cpp
195
wled00/json.cpp
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
bool getVal(JsonVariant elem, byte* val, byte vmin=0, byte vmax=255) {
|
bool getVal(JsonVariant elem, byte* val, byte vmin=0, byte vmax=255) {
|
||||||
if (elem.is<int>()) {
|
if (elem.is<int>()) {
|
||||||
if (elem < 0) return false; //ignore e.g. {"ps":-1}
|
if (elem < 0) return false; //ignore e.g. {"ps":-1}
|
||||||
*val = elem;
|
*val = elem;
|
||||||
return true;
|
return true;
|
||||||
} else if (elem.is<const char*>()) {
|
} else if (elem.is<const char*>()) {
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//repeat, multiplies segment until all LEDs are used, or max segments reached
|
||||||
|
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
|
||||||
@ -64,7 +82,8 @@ 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;
|
||||||
@ -76,7 +95,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
of = offsetAbs;
|
of = offsetAbs;
|
||||||
}
|
}
|
||||||
if (stop > start && of > len -1) of = len -1;
|
if (stop > start && of > len -1) of = len -1;
|
||||||
strip.setSegment(id, start, stop, grp, spc, of);
|
strip.setSegment(id, start, stop, grp, spc, of);
|
||||||
|
|
||||||
byte segbri = 0;
|
byte segbri = 0;
|
||||||
if (getVal(elem["bri"], &segbri)) {
|
if (getVal(elem["bri"], &segbri)) {
|
||||||
@ -87,10 +106,13 @@ 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);
|
||||||
uint8_t cctPrev = seg.cct;
|
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;
|
||||||
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
|
||||||
|
|
||||||
JsonArray colarr = elem["col"];
|
JsonArray colarr = elem["col"];
|
||||||
if (!colarr.isNull())
|
if (!colarr.isNull())
|
||||||
@ -124,14 +146,11 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!colValid) continue;
|
if (!colValid) continue;
|
||||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
|
||||||
{
|
uint32_t color = RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]);
|
||||||
if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
|
colorChanged |= (seg.colors[i] != color);
|
||||||
if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
|
seg.setColor(i, color, id);
|
||||||
} else { //normal case, apply directly to segment
|
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
||||||
seg.setColor(i, ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))), id);
|
|
||||||
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,26 +171,20 @@ 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 ));
|
||||||
|
|
||||||
//temporary, strip object gets updated via colorUpdated()
|
if (!(elem[F("sel")].isNull() && elem["rev"].isNull() && elem["on"].isNull() && elem[F("mi")].isNull())) effectChanged = true; //send UDP
|
||||||
if (id == strip.getMainSegmentId()) {
|
|
||||||
byte effectPrev = effectCurrent;
|
byte fx = seg.mode;
|
||||||
if (getVal(elem["fx"], &effectCurrent, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 0-255 exact value)
|
byte fxPrev = fx;
|
||||||
if (!presetId && effectCurrent != effectPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
|
if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value)
|
||||||
}
|
strip.setMode(id, fx);
|
||||||
effectSpeed = elem[F("sx")] | effectSpeed;
|
if (!presetId && seg.mode != fxPrev) effectChanged = true; //send UDP
|
||||||
effectIntensity = elem[F("ix")] | effectIntensity;
|
|
||||||
getVal(elem["pal"], &effectPalette, 1, strip.getPaletteCount());
|
|
||||||
} else { //permanent
|
|
||||||
byte fx = seg.mode;
|
|
||||||
byte fxPrev = fx;
|
|
||||||
if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 0-255 exact value)
|
|
||||||
strip.setMode(id, fx);
|
|
||||||
if (!presetId && seg.mode != fxPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
|
|
||||||
}
|
|
||||||
seg.speed = elem[F("sx")] | seg.speed;
|
|
||||||
seg.intensity = elem[F("ix")] | seg.intensity;
|
|
||||||
getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount());
|
|
||||||
}
|
}
|
||||||
|
byte prevSpd = seg.speed;
|
||||||
|
byte prevInt = seg.intensity;
|
||||||
|
byte prevPal = seg.palette;
|
||||||
|
if (getVal(elem[F("sx")], &seg.speed, 0, 255) && !presetId && prevSpd != seg.speed) effectChanged = true; //also supports inc/decrementing and random
|
||||||
|
if (getVal(elem[F("ix")], &seg.intensity, 0, 255) && !presetId && prevInt != seg.intensity) effectChanged = true; //also supports inc/decrementing and random
|
||||||
|
if (getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount()) && !presetId && prevPal != seg.palette) effectChanged = true; //also supports inc/decrementing and random
|
||||||
|
|
||||||
JsonArray iarr = elem[F("i")]; //set individual LEDs
|
JsonArray iarr = elem[F("i")]; //set individual LEDs
|
||||||
if (!iarr.isNull()) {
|
if (!iarr.isNull()) {
|
||||||
@ -223,12 +236,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;
|
||||||
@ -264,16 +278,16 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
tr = root[F("tb")] | -1;
|
tr = root[F("tb")] | -1;
|
||||||
if (tr >= 0) strip.timebase = ((uint32_t)tr) - millis();
|
if (tr >= 0) strip.timebase = ((uint32_t)tr) - millis();
|
||||||
|
|
||||||
JsonObject nl = root["nl"];
|
JsonObject nl = root["nl"];
|
||||||
nightlightActive = nl["on"] | nightlightActive;
|
nightlightActive = nl["on"] | nightlightActive;
|
||||||
nightlightDelayMins = nl[F("dur")] | nightlightDelayMins;
|
nightlightDelayMins = nl[F("dur")] | nightlightDelayMins;
|
||||||
nightlightMode = nl[F("mode")] | nightlightMode;
|
nightlightMode = nl[F("mode")] | nightlightMode;
|
||||||
nightlightTargetBri = nl[F("tbri")] | nightlightTargetBri;
|
nightlightTargetBri = nl[F("tbri")] | nightlightTargetBri;
|
||||||
|
|
||||||
JsonObject udpn = root["udpn"];
|
JsonObject udpn = root["udpn"];
|
||||||
notifyDirect = udpn["send"] | notifyDirect;
|
notifyDirect = udpn["send"] | notifyDirect;
|
||||||
receiveNotifications = udpn["recv"] | receiveNotifications;
|
receiveNotifications = udpn["recv"] | receiveNotifications;
|
||||||
bool noNotification = udpn[F("nn")]; //send no notification just for this request
|
if ((bool)udpn[F("nn")]) callMode = CALL_MODE_NO_NOTIFY; //send no notification just for this request
|
||||||
|
|
||||||
unsigned long timein = root[F("time")] | UINT32_MAX; //backup time source if NTP not synced
|
unsigned long timein = root[F("time")] | UINT32_MAX; //backup time source if NTP not synced
|
||||||
if (timein != UINT32_MAX) {
|
if (timein != UINT32_MAX) {
|
||||||
@ -294,22 +308,21 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
|
|
||||||
byte prevMain = strip.getMainSegmentId();
|
byte prevMain = strip.getMainSegmentId();
|
||||||
strip.mainSegment = root[F("mainseg")] | prevMain;
|
strip.mainSegment = root[F("mainseg")] | prevMain;
|
||||||
if (strip.getMainSegmentId() != prevMain) setValuesFromMainSeg();
|
//if (strip.getMainSegmentId() != prevMain) setValuesFromMainSeg();
|
||||||
|
|
||||||
int it = 0;
|
int it = 0;
|
||||||
JsonVariant segVar = root["seg"];
|
JsonVariant segVar = root["seg"];
|
||||||
if (segVar.is<JsonObject>())
|
if (segVar.is<JsonObject>())
|
||||||
{
|
{
|
||||||
int id = segVar["id"] | -1;
|
int id = segVar["id"] | -1;
|
||||||
|
//if "seg" is not an array and ID not specified, apply to all selected/checked segments
|
||||||
if (id < 0) { //set all selected segments
|
if (id < 0) {
|
||||||
|
//apply all selected segments
|
||||||
bool didSet = false;
|
bool didSet = false;
|
||||||
byte lowestActive = 99;
|
byte lowestActive = 99;
|
||||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
for (byte s = 0; s < strip.getMaxSegments(); s++) {
|
||||||
{
|
WS2812FX::Segment &sg = strip.getSegment(s);
|
||||||
WS2812FX::Segment sg = strip.getSegment(s);
|
if (sg.isActive()) {
|
||||||
if (sg.isActive())
|
|
||||||
{
|
|
||||||
if (lowestActive == 99) lowestActive = s;
|
if (lowestActive == 99) lowestActive = s;
|
||||||
if (sg.isSelected()) {
|
if (sg.isSelected()) {
|
||||||
deserializeSegment(segVar, s, presetId);
|
deserializeSegment(segVar, s, presetId);
|
||||||
@ -317,9 +330,10 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//TODO: not sure if it is good idea to change first active but unselected segment
|
||||||
if (!didSet && lowestActive < strip.getMaxSegments()) deserializeSegment(segVar, lowestActive, presetId);
|
if (!didSet && lowestActive < strip.getMaxSegments()) deserializeSegment(segVar, lowestActive, presetId);
|
||||||
} else { //set only the segment with the specified ID
|
} else {
|
||||||
deserializeSegment(segVar, it, presetId);
|
deserializeSegment(segVar, id, presetId); //apply only the segment with the specified ID
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
JsonArray segs = segVar.as<JsonArray>();
|
JsonArray segs = segVar.as<JsonArray>();
|
||||||
@ -329,6 +343,8 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setValuesFromMainSeg(); //to make transition work on main segment
|
||||||
|
if (effectChanged) unloadPlaylist(); //if any of the effect parameter changed unload playlist
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_CRONIXIE
|
#ifndef WLED_DISABLE_CRONIXIE
|
||||||
if (root["nx"].is<const char*>()) {
|
if (root["nx"].is<const char*>()) {
|
||||||
@ -369,63 +385,65 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
|||||||
JsonObject playlist = root[F("playlist")];
|
JsonObject playlist = root[F("playlist")];
|
||||||
if (!playlist.isNull() && loadPlaylist(playlist, presetId)) {
|
if (!playlist.isNull() && loadPlaylist(playlist, presetId)) {
|
||||||
//do not notify here, because the first playlist entry will do
|
//do not notify here, because the first playlist entry will do
|
||||||
noNotification = true;
|
if (root["on"].isNull()) callMode = CALL_MODE_NO_NOTIFY;
|
||||||
|
else callMode = CALL_MODE_DIRECT_CHANGE; // possible bugfix for playlist only containing HTTP API preset FX=~
|
||||||
} else {
|
} else {
|
||||||
interfaceUpdateCallMode = CALL_MODE_WS_SEND;
|
interfaceUpdateCallMode = CALL_MODE_WS_SEND;
|
||||||
}
|
}
|
||||||
|
|
||||||
colorUpdated(noNotification ? CALL_MODE_NO_NOTIFY : callMode);
|
colorUpdated(callMode);
|
||||||
|
|
||||||
return stateResponse;
|
return stateResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset, bool segmentBounds)
|
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset, bool segmentBounds)
|
||||||
{
|
{
|
||||||
root["id"] = id;
|
root["id"] = id;
|
||||||
if (segmentBounds) {
|
if (segmentBounds) {
|
||||||
root["start"] = seg.start;
|
root["start"] = seg.start;
|
||||||
root["stop"] = seg.stop;
|
root["stop"] = seg.stop;
|
||||||
}
|
}
|
||||||
if (!forPreset) root[F("len")] = seg.stop - seg.start;
|
if (!forPreset) root[F("len")] = seg.stop - seg.start;
|
||||||
root["grp"] = seg.grouping;
|
root["grp"] = seg.grouping;
|
||||||
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;
|
||||||
|
|
||||||
if (segmentBounds && seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name); //not good practice, but decreases required JSON buffer
|
if (segmentBounds && seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name); //not good practice, but decreases required JSON buffer
|
||||||
|
|
||||||
char colstr[70]; colstr[0] = '['; colstr[1] = '\0'; //max len 68 (5 chan, all 255)
|
// to conserve RAM we will serialize the col array manually
|
||||||
|
// this will reduce RAM footprint from ~300 bytes to 84 bytes per segment
|
||||||
for (uint8_t i = 0; i < 3; i++)
|
char colstr[70]; colstr[0] = '['; colstr[1] = '\0'; //max len 68 (5 chan, all 255)
|
||||||
{
|
const char *format = strip.isRgbw ? PSTR("[%u,%u,%u,%u]") : PSTR("[%u,%u,%u]");
|
||||||
|
for (uint8_t i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
byte segcol[4]; byte* c = segcol;
|
byte segcol[4]; byte* c = segcol;
|
||||||
|
|
||||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||||
{
|
{
|
||||||
c = (i == 0)? col:colSec;
|
c = (i == 0)? col:colSec;
|
||||||
} else {
|
} else {
|
||||||
segcol[0] = (byte)(seg.colors[i] >> 16); segcol[1] = (byte)(seg.colors[i] >> 8);
|
segcol[0] = R(seg.colors[i]);
|
||||||
segcol[2] = (byte)(seg.colors[i]); segcol[3] = (byte)(seg.colors[i] >> 24);
|
segcol[1] = G(seg.colors[i]);
|
||||||
|
segcol[2] = B(seg.colors[i]);
|
||||||
|
segcol[3] = W(seg.colors[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
char tmpcol[22];
|
char tmpcol[22];
|
||||||
if (strip.isRgbw) sprintf_P(tmpcol, PSTR("[%u,%u,%u,%u]"), c[0], c[1], c[2], c[3]);
|
sprintf_P(tmpcol, format, (unsigned)c[0], (unsigned)c[1], (unsigned)c[2], (unsigned)c[3]);
|
||||||
else sprintf_P(tmpcol, PSTR("[%u,%u,%u]"), c[0], c[1], c[2]);
|
strcat(colstr, i<2 ? strcat_P(tmpcol, PSTR(",")) : tmpcol);
|
||||||
|
}
|
||||||
strcat(colstr, i<2 ? strcat(tmpcol,",") : tmpcol);
|
strcat_P(colstr, PSTR("]"));
|
||||||
}
|
|
||||||
strcat(colstr,"]");
|
|
||||||
root["col"] = serialized(colstr);
|
root["col"] = serialized(colstr);
|
||||||
|
|
||||||
root["fx"] = seg.mode;
|
root["fx"] = seg.mode;
|
||||||
root[F("sx")] = seg.speed;
|
root[F("sx")] = seg.speed;
|
||||||
root[F("ix")] = seg.intensity;
|
root[F("ix")] = seg.intensity;
|
||||||
root["pal"] = seg.palette;
|
root["pal"] = seg.palette;
|
||||||
root[F("sel")] = seg.isSelected();
|
root[F("sel")] = seg.isSelected();
|
||||||
root["rev"] = seg.getOption(SEG_OPTION_REVERSED);
|
root["rev"] = seg.getOption(SEG_OPTION_REVERSED);
|
||||||
root[F("mi")] = seg.getOption(SEG_OPTION_MIRROR);
|
root[F("mi")] = seg.getOption(SEG_OPTION_MIRROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +456,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!forPreset) {
|
if (!forPreset) {
|
||||||
if (errorFlag) root[F("error")] = errorFlag;
|
if (errorFlag) {root[F("error")] = errorFlag; errorFlag = ERR_NONE;} //prevent error message to persist on screen
|
||||||
|
|
||||||
root["ps"] = (currentPreset > 0) ? currentPreset : -1;
|
root["ps"] = (currentPreset > 0) ? currentPreset : -1;
|
||||||
root[F("pl")] = currentPlaylist;
|
root[F("pl")] = currentPlaylist;
|
||||||
@ -466,11 +484,9 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
|||||||
root[F("mainseg")] = strip.getMainSegmentId();
|
root[F("mainseg")] = strip.getMainSegmentId();
|
||||||
|
|
||||||
JsonArray seg = root.createNestedArray("seg");
|
JsonArray seg = root.createNestedArray("seg");
|
||||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
for (byte s = 0; s < strip.getMaxSegments(); s++) {
|
||||||
{
|
WS2812FX::Segment &sg = strip.getSegment(s);
|
||||||
WS2812FX::Segment sg = strip.getSegment(s);
|
if (sg.isActive()) {
|
||||||
if (sg.isActive())
|
|
||||||
{
|
|
||||||
JsonObject seg0 = seg.createNestedObject();
|
JsonObject seg0 = seg.createNestedObject();
|
||||||
serializeSegment(seg0, sg, s, forPreset, segmentBounds);
|
serializeSegment(seg0, sg, s, forPreset, segmentBounds);
|
||||||
} else if (forPreset && segmentBounds) { //disable segments not part of preset
|
} else if (forPreset && segmentBounds) { //disable segments not part of preset
|
||||||
@ -511,12 +527,12 @@ void serializeInfo(JsonObject root)
|
|||||||
leds[F("rgbw")] = strip.isRgbw;
|
leds[F("rgbw")] = strip.isRgbw;
|
||||||
leds[F("wv")] = false;
|
leds[F("wv")] = false;
|
||||||
leds["cct"] = correctWB || strip.hasCCTBus();
|
leds["cct"] = correctWB || strip.hasCCTBus();
|
||||||
switch (Bus::getAutoWhiteMode()) {
|
switch (Bus::getAutoWhiteMode()) {
|
||||||
case RGBW_MODE_MANUAL_ONLY:
|
case RGBW_MODE_MANUAL_ONLY:
|
||||||
case RGBW_MODE_DUAL:
|
case RGBW_MODE_DUAL:
|
||||||
if (strip.isRgbw) leds[F("wv")] = true;
|
if (strip.isRgbw) leds[F("wv")] = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
leds[F("pwr")] = strip.currentMilliamps;
|
leds[F("pwr")] = strip.currentMilliamps;
|
||||||
leds["fps"] = strip.getFps();
|
leds["fps"] = strip.getFps();
|
||||||
@ -596,9 +612,11 @@ void serializeInfo(JsonObject root)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
root[F("freeheap")] = ESP.getFreeHeap();
|
root[F("freeheap")] = ESP.getFreeHeap();
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||||
|
if (psramFound()) root[F("psram")] = ESP.getFreePsram();
|
||||||
|
#endif
|
||||||
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
||||||
|
|
||||||
|
|
||||||
usermods.addToJsonInfo(root);
|
usermods.addToJsonInfo(root);
|
||||||
|
|
||||||
byte os = 0;
|
byte os = 0;
|
||||||
@ -645,7 +663,7 @@ void setPaletteColors(JsonArray json, CRGBPalette16 palette)
|
|||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
JsonArray colors = json.createNestedArray();
|
JsonArray colors = json.createNestedArray();
|
||||||
CRGB color = palette[i];
|
CRGB color = palette[i];
|
||||||
colors.add((((float)i / (float)16) * 255));
|
colors.add(i<<4);
|
||||||
colors.add(color.red);
|
colors.add(color.red);
|
||||||
colors.add(color.green);
|
colors.add(color.green);
|
||||||
colors.add(color.blue);
|
colors.add(color.blue);
|
||||||
@ -707,9 +725,6 @@ void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
for (int i = start; i < end; i++) {
|
for (int i = start; i < end; i++) {
|
||||||
JsonArray curPalette = palettes.createNestedArray(String(i));
|
JsonArray curPalette = palettes.createNestedArray(String(i));
|
||||||
CRGB prim;
|
|
||||||
CRGB sec;
|
|
||||||
CRGB ter;
|
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0: //default palette
|
case 0: //default palette
|
||||||
setPaletteColors(curPalette, PartyColors_p);
|
setPaletteColors(curPalette, PartyColors_p);
|
||||||
@ -877,13 +892,13 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||||
{
|
{
|
||||||
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||||
AsyncWebSocketClient * wsc = nullptr;
|
AsyncWebSocketClient * wsc = nullptr;
|
||||||
if (!request) { //not HTTP, use Websockets
|
if (!request) { //not HTTP, use Websockets
|
||||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
|
||||||
wsc = ws.client(wsClient);
|
wsc = ws.client(wsClient);
|
||||||
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
|
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint16_t used = strip.getLengthTotal();
|
uint16_t used = strip.getLengthTotal();
|
||||||
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
|
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
|
||||||
|
101
wled00/led.cpp
101
wled00/led.cpp
@ -44,8 +44,8 @@ byte scaledBri(byte in)
|
|||||||
|
|
||||||
|
|
||||||
void setAllLeds() {
|
void setAllLeds() {
|
||||||
strip.setColor(0, col[0], col[1], col[2], col[3]);
|
strip.setColor(0, RGBW32(col[0], col[1], col[2], col[3]));
|
||||||
strip.setColor(1, colSec[0], colSec[1], colSec[2], colSec[3]);
|
strip.setColor(1, RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]));
|
||||||
if (!realtimeMode || !arlsForceMaxBri)
|
if (!realtimeMode || !arlsForceMaxBri)
|
||||||
{
|
{
|
||||||
strip.setBrightness(scaledBri(briT));
|
strip.setBrightness(scaledBri(briT));
|
||||||
@ -61,106 +61,67 @@ void setLedsStandard()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool colorChanged()
|
|
||||||
{
|
|
||||||
for (byte i=0; i<4; i++)
|
|
||||||
{
|
|
||||||
if (col[i] != colIT[i]) return true;
|
|
||||||
if (colSec[i] != colSecIT[i]) return true;
|
|
||||||
}
|
|
||||||
if (bri != briIT) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void colorUpdated(int callMode)
|
void colorUpdated(int callMode)
|
||||||
{
|
{
|
||||||
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
||||||
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa 11: ws send only 12: button preset
|
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa 11: ws send only 12: button preset
|
||||||
if (callMode != CALL_MODE_INIT &&
|
|
||||||
callMode != CALL_MODE_DIRECT_CHANGE &&
|
|
||||||
callMode != CALL_MODE_NO_NOTIFY &&
|
|
||||||
callMode != CALL_MODE_BUTTON_PRESET) strip.applyToAllSelected = true; //if not from JSON api, which directly sets segments
|
|
||||||
|
|
||||||
bool someSel = false;
|
if (bri != briOld || effectChanged || colorChanged) {
|
||||||
|
|
||||||
if (callMode == CALL_MODE_NOTIFICATION) {
|
|
||||||
someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Notifier: apply received FX to selected segments only if actually receiving FX
|
|
||||||
if (someSel) strip.applyToAllSelected = receiveNotificationEffects;
|
|
||||||
|
|
||||||
bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette) || effectChanged;
|
|
||||||
bool colChanged = colorChanged();
|
|
||||||
|
|
||||||
//Notifier: apply received color to selected segments only if actually receiving color
|
|
||||||
if (someSel) strip.applyToAllSelected = receiveNotificationColor;
|
|
||||||
|
|
||||||
if (fxChanged || colChanged)
|
|
||||||
{
|
|
||||||
effectChanged = false;
|
|
||||||
if (realtimeTimeout == UINT32_MAX) realtimeTimeout = 0;
|
if (realtimeTimeout == UINT32_MAX) realtimeTimeout = 0;
|
||||||
currentPreset = 0; //something changed, so we are no longer in the preset
|
if (effectChanged) currentPreset = 0; //something changed, so we are no longer in the preset
|
||||||
|
|
||||||
notify(callMode);
|
if (callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) notify(callMode);
|
||||||
|
|
||||||
//set flag to update blynk, ws and mqtt
|
//set flag to update blynk, ws and mqtt
|
||||||
interfaceUpdateCallMode = callMode;
|
interfaceUpdateCallMode = callMode;
|
||||||
|
effectChanged = false;
|
||||||
|
colorChanged = false;
|
||||||
} else {
|
} else {
|
||||||
if (nightlightActive && !nightlightActiveOld &&
|
if (nightlightActive && !nightlightActiveOld && callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) {
|
||||||
callMode != CALL_MODE_NOTIFICATION &&
|
|
||||||
callMode != CALL_MODE_NO_NOTIFY)
|
|
||||||
{
|
|
||||||
notify(CALL_MODE_NIGHTLIGHT);
|
notify(CALL_MODE_NIGHTLIGHT);
|
||||||
interfaceUpdateCallMode = CALL_MODE_NIGHTLIGHT;
|
interfaceUpdateCallMode = CALL_MODE_NIGHTLIGHT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!colChanged) return; //following code is for e.g. initiating transitions
|
if (callMode != CALL_MODE_NO_NOTIFY && nightlightActive && (nightlightMode == NL_MODE_FADE || nightlightMode == NL_MODE_COLORFADE)) {
|
||||||
|
|
||||||
if (callMode != CALL_MODE_NO_NOTIFY && nightlightActive && (nightlightMode == NL_MODE_FADE || nightlightMode == NL_MODE_COLORFADE))
|
|
||||||
{
|
|
||||||
briNlT = bri;
|
briNlT = bri;
|
||||||
nightlightDelayMs -= (millis() - nightlightStartTime);
|
nightlightDelayMs -= (millis() - nightlightStartTime);
|
||||||
nightlightStartTime = millis();
|
nightlightStartTime = millis();
|
||||||
}
|
}
|
||||||
for (byte i=0; i<4; i++)
|
if (briT == 0) {
|
||||||
{
|
|
||||||
colIT[i] = col[i];
|
|
||||||
colSecIT[i] = colSec[i];
|
|
||||||
}
|
|
||||||
if (briT == 0)
|
|
||||||
{
|
|
||||||
if (callMode != CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning
|
if (callMode != CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning
|
||||||
}
|
}
|
||||||
|
|
||||||
briIT = bri;
|
|
||||||
if (bri > 0) briLast = bri;
|
if (bri > 0) briLast = bri;
|
||||||
|
|
||||||
//deactivate nightlight if target brightness is reached
|
//deactivate nightlight if target brightness is reached
|
||||||
if (bri == nightlightTargetBri && callMode != CALL_MODE_NO_NOTIFY && nightlightMode != NL_MODE_SUN) nightlightActive = false;
|
if (bri == nightlightTargetBri && callMode != CALL_MODE_NO_NOTIFY && nightlightMode != NL_MODE_SUN) nightlightActive = false;
|
||||||
|
|
||||||
if (fadeTransition)
|
if (fadeTransition) {
|
||||||
{
|
|
||||||
//set correct delay if not using notification delay
|
//set correct delay if not using notification delay
|
||||||
if (callMode != CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay;
|
if (callMode != CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay;
|
||||||
jsonTransitionOnce = false;
|
jsonTransitionOnce = false;
|
||||||
strip.setTransition(transitionDelayTemp);
|
strip.setTransition(transitionDelayTemp);
|
||||||
if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;}
|
if (transitionDelayTemp == 0) {
|
||||||
|
//setLedsStandard();
|
||||||
if (transitionActive)
|
briOld = briT = bri;
|
||||||
{
|
if (!realtimeMode || !arlsForceMaxBri) strip.setBrightness(scaledBri(briT));
|
||||||
|
strip.trigger();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transitionActive) {
|
||||||
briOld = briT;
|
briOld = briT;
|
||||||
tperLast = 0;
|
tperLast = 0;
|
||||||
}
|
}
|
||||||
strip.setTransitionMode(true);
|
strip.setTransitionMode(true);
|
||||||
transitionActive = true;
|
transitionActive = true;
|
||||||
transitionStartTime = millis();
|
transitionStartTime = millis();
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
strip.setTransition(0);
|
strip.setTransition(0);
|
||||||
setLedsStandard();
|
//setLedsStandard();
|
||||||
|
briOld = briT = bri;
|
||||||
|
if (!realtimeMode || !arlsForceMaxBri) strip.setBrightness(scaledBri(briT));
|
||||||
strip.trigger();
|
strip.trigger();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,10 +130,8 @@ void colorUpdated(int callMode)
|
|||||||
void updateInterfaces(uint8_t callMode)
|
void updateInterfaces(uint8_t callMode)
|
||||||
{
|
{
|
||||||
sendDataWs();
|
sendDataWs();
|
||||||
if (callMode == CALL_MODE_WS_SEND) {
|
lastInterfaceUpdate = millis();
|
||||||
lastInterfaceUpdate = millis();
|
if (callMode == CALL_MODE_WS_SEND) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_ALEXA
|
#ifndef WLED_DISABLE_ALEXA
|
||||||
if (espalexaDevice != nullptr && callMode != CALL_MODE_ALEXA) {
|
if (espalexaDevice != nullptr && callMode != CALL_MODE_ALEXA) {
|
||||||
@ -185,7 +144,6 @@ void updateInterfaces(uint8_t callMode)
|
|||||||
callMode != CALL_MODE_NO_NOTIFY) updateBlynk();
|
callMode != CALL_MODE_NO_NOTIFY) updateBlynk();
|
||||||
#endif
|
#endif
|
||||||
doPublishMqtt = true;
|
doPublishMqtt = true;
|
||||||
lastInterfaceUpdate = millis();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -221,6 +179,13 @@ void handleTransitions()
|
|||||||
|
|
||||||
void handleNightlight()
|
void handleNightlight()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
static unsigned long lastNlUpdate;
|
||||||
|
unsigned long now = millis();
|
||||||
|
if (now < 100 && lastNlUpdate > 0) lastNlUpdate = 0; //take care of millis() rollover
|
||||||
|
if (now - lastNlUpdate < 100) return; //allow only 10 NL updates per second
|
||||||
|
lastNlUpdate = now;
|
||||||
|
*/
|
||||||
if (nightlightActive)
|
if (nightlightActive)
|
||||||
{
|
{
|
||||||
if (!nightlightActiveOld) //init
|
if (!nightlightActiveOld) //init
|
||||||
|
136
wled00/set.cpp
136
wled00/set.cpp
@ -218,7 +218,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"));
|
||||||
@ -307,6 +308,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
|
|
||||||
//start ntp if not already connected
|
//start ntp if not already connected
|
||||||
if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
|
if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
|
||||||
|
ntpLastSyncTime = 0; // force new NTP query
|
||||||
|
|
||||||
longitude = request->arg(F("LN")).toFloat();
|
longitude = request->arg(F("LN")).toFloat();
|
||||||
latitude = request->arg(F("LT")).toFloat();
|
latitude = request->arg(F("LT")).toFloat();
|
||||||
@ -592,7 +594,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
DEBUG_PRINT(F("API req: "));
|
DEBUG_PRINT(F("API req: "));
|
||||||
DEBUG_PRINTLN(req);
|
DEBUG_PRINTLN(req);
|
||||||
|
|
||||||
strip.applyToAllSelected = false;
|
strip.applyToAllSelected = true;
|
||||||
|
|
||||||
//segment select (sets main segment)
|
//segment select (sets main segment)
|
||||||
byte prevMain = strip.getMainSegmentId();
|
byte prevMain = strip.getMainSegmentId();
|
||||||
@ -603,22 +605,28 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
byte selectedSeg = strip.getMainSegmentId();
|
byte selectedSeg = strip.getMainSegmentId();
|
||||||
if (selectedSeg != prevMain) setValuesFromMainSeg();
|
if (selectedSeg != prevMain) setValuesFromMainSeg();
|
||||||
|
|
||||||
|
//snapshot to check if request changed values later, temporary.
|
||||||
|
byte prevCol[4] = {col[0], col[1], col[2], col[3]};
|
||||||
|
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
|
||||||
|
byte prevEffect = effectCurrent;
|
||||||
|
byte prevSpeed = effectSpeed;
|
||||||
|
byte prevIntensity = effectIntensity;
|
||||||
|
byte prevPalette = effectPalette;
|
||||||
|
|
||||||
pos = req.indexOf(F("SS="));
|
pos = req.indexOf(F("SS="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
byte t = getNumVal(&req, pos);
|
byte t = getNumVal(&req, pos);
|
||||||
if (t < strip.getMaxSegments()) selectedSeg = t;
|
if (t < strip.getMaxSegments()) {
|
||||||
|
selectedSeg = t;
|
||||||
|
strip.applyToAllSelected = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WS2812FX::Segment& selseg = strip.getSegment(selectedSeg);
|
WS2812FX::Segment& selseg = strip.getSegment(selectedSeg);
|
||||||
pos = req.indexOf(F("SV=")); //segment selected
|
pos = req.indexOf(F("SV=")); //segment selected
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
byte t = getNumVal(&req, pos);
|
byte t = getNumVal(&req, pos);
|
||||||
if (t == 2) {
|
if (t == 2) for (uint8_t i = 0; i < strip.getMaxSegments(); i++) strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0); // unselect other segments
|
||||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++)
|
|
||||||
{
|
|
||||||
strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
selseg.setOption(SEG_OPTION_SELECTED, t);
|
selseg.setOption(SEG_OPTION_SELECTED, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -684,26 +692,21 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
applyPreset(presetCycCurr);
|
applyPreset(presetCycCurr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//snapshot to check if request changed values later, temporary.
|
|
||||||
byte prevCol[4] = {col[0], col[1], col[2], col[3]};
|
|
||||||
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
|
|
||||||
byte prevEffect = effectCurrent;
|
|
||||||
byte prevSpeed = effectSpeed;
|
|
||||||
byte prevIntensity = effectIntensity;
|
|
||||||
byte prevPalette = effectPalette;
|
|
||||||
|
|
||||||
//set brightness
|
//set brightness
|
||||||
updateVal(&req, "&A=", &bri);
|
updateVal(&req, "&A=", &bri);
|
||||||
|
|
||||||
|
bool col0Changed = false, col1Changed = false, col2Changed = false;
|
||||||
//set colors
|
//set colors
|
||||||
updateVal(&req, "&R=", &col[0]);
|
updateVal(&req, "&R=", &col[0]);
|
||||||
updateVal(&req, "&G=", &col[1]);
|
updateVal(&req, "&G=", &col[1]);
|
||||||
updateVal(&req, "&B=", &col[2]);
|
updateVal(&req, "&B=", &col[2]);
|
||||||
updateVal(&req, "&W=", &col[3]);
|
updateVal(&req, "&W=", &col[3]);
|
||||||
|
for (byte i=0; i<4; i++) if (prevCol[i]!=col[i]) col0Changed = colorChanged = true;
|
||||||
updateVal(&req, "R2=", &colSec[0]);
|
updateVal(&req, "R2=", &colSec[0]);
|
||||||
updateVal(&req, "G2=", &colSec[1]);
|
updateVal(&req, "G2=", &colSec[1]);
|
||||||
updateVal(&req, "B2=", &colSec[2]);
|
updateVal(&req, "B2=", &colSec[2]);
|
||||||
updateVal(&req, "W2=", &colSec[3]);
|
updateVal(&req, "W2=", &colSec[3]);
|
||||||
|
for (byte i=0; i<4; i++) if (prevColSec[i]!=colSec[i]) col1Changed = colorChanged = true;
|
||||||
|
|
||||||
#ifdef WLED_ENABLE_LOXONE
|
#ifdef WLED_ENABLE_LOXONE
|
||||||
//lox parser
|
//lox parser
|
||||||
@ -734,52 +737,64 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
tempsat = getNumVal(&req, pos);
|
tempsat = getNumVal(&req, pos);
|
||||||
}
|
}
|
||||||
colorHStoRGB(temphue,tempsat,(req.indexOf(F("H2"))>0)? colSec:col);
|
byte sec = req.indexOf(F("H2"));
|
||||||
|
colorHStoRGB(temphue, tempsat, (sec>0) ? colSec : col);
|
||||||
|
if (sec>0) col1Changed = true;
|
||||||
|
else col0Changed = true;
|
||||||
|
colorChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//set white spectrum (kelvin)
|
//set white spectrum (kelvin)
|
||||||
pos = req.indexOf(F("&K="));
|
pos = req.indexOf(F("&K="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
colorKtoRGB(getNumVal(&req, pos),(req.indexOf(F("K2"))>0)? colSec:col);
|
byte sec = req.indexOf(F("K2"));
|
||||||
|
colorKtoRGB(getNumVal(&req, pos), (sec>0) ? colSec : col);
|
||||||
|
if (sec>0) col1Changed = true;
|
||||||
|
else col0Changed = true;
|
||||||
|
colorChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//set color from HEX or 32bit DEC
|
//set color from HEX or 32bit DEC
|
||||||
|
byte tmpCol[4];
|
||||||
pos = req.indexOf(F("CL="));
|
pos = req.indexOf(F("CL="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
colorFromDecOrHexString(col, (char*)req.substring(pos + 3).c_str());
|
colorFromDecOrHexString(col, (char*)req.substring(pos + 3).c_str());
|
||||||
|
selseg.setColor(0, RGBW32(col[0], col[1], col[2], col[3]), selectedSeg); // defined above (SS= or main)
|
||||||
|
col0Changed = colorChanged = true;
|
||||||
}
|
}
|
||||||
pos = req.indexOf(F("C2="));
|
pos = req.indexOf(F("C2="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
colorFromDecOrHexString(colSec, (char*)req.substring(pos + 3).c_str());
|
colorFromDecOrHexString(colSec, (char*)req.substring(pos + 3).c_str());
|
||||||
|
selseg.setColor(1, RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]), selectedSeg); // defined above (SS= or main)
|
||||||
|
col1Changed = colorChanged = true;
|
||||||
}
|
}
|
||||||
pos = req.indexOf(F("C3="));
|
pos = req.indexOf(F("C3="));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
byte t[4];
|
colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
|
||||||
colorFromDecOrHexString(t, (char*)req.substring(pos + 3).c_str());
|
selseg.setColor(2, RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]), selectedSeg); // defined above (SS= or main)
|
||||||
if (selectedSeg != strip.getMainSegmentId()) {
|
col2Changed = colorChanged = true;
|
||||||
strip.applyToAllSelected = true;
|
|
||||||
strip.setColor(2, t[0], t[1], t[2], t[3]);
|
|
||||||
} else {
|
|
||||||
selseg.setColor(2, RGBW32(t[0], t[1], t[2], t[3]), selectedSeg); // defined above (SS=)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//set to random hue SR=0->1st SR=1->2nd
|
//set to random hue SR=0->1st SR=1->2nd
|
||||||
pos = req.indexOf(F("SR"));
|
pos = req.indexOf(F("SR"));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
_setRandomColor(getNumVal(&req, pos));
|
byte sec = getNumVal(&req, pos);
|
||||||
|
_setRandomColor(sec);
|
||||||
|
if (sec>0) col1Changed = true;
|
||||||
|
else col0Changed = true;
|
||||||
|
colorChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//swap 2nd & 1st
|
//swap 2nd & 1st
|
||||||
pos = req.indexOf(F("SC"));
|
pos = req.indexOf(F("SC"));
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
byte temp;
|
byte temp;
|
||||||
for (uint8_t i=0; i<4; i++)
|
for (uint8_t i=0; i<4; i++) {
|
||||||
{
|
temp = col[i];
|
||||||
temp = col[i];
|
col[i] = colSec[i];
|
||||||
col[i] = colSec[i];
|
|
||||||
colSec[i] = temp;
|
colSec[i] = temp;
|
||||||
}
|
}
|
||||||
|
col0Changed = col1Changed = colorChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//set effect parameters
|
//set effect parameters
|
||||||
@ -787,6 +802,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
updateVal(&req, "SX=", &effectSpeed);
|
updateVal(&req, "SX=", &effectSpeed);
|
||||||
updateVal(&req, "IX=", &effectIntensity);
|
updateVal(&req, "IX=", &effectIntensity);
|
||||||
updateVal(&req, "FP=", &effectPalette, 0, strip.getPaletteCount()-1);
|
updateVal(&req, "FP=", &effectPalette, 0, strip.getPaletteCount()-1);
|
||||||
|
strip.setMode(selectedSeg, effectCurrent);
|
||||||
|
selseg.speed = effectSpeed;
|
||||||
|
selseg.intensity = effectIntensity;
|
||||||
|
selseg.palette = effectPalette;
|
||||||
|
if (effectCurrent != prevEffect || effectSpeed != prevSpeed || effectIntensity != prevIntensity || effectPalette != prevPalette) effectChanged = true;
|
||||||
|
|
||||||
//set advanced overlay
|
//set advanced overlay
|
||||||
pos = req.indexOf(F("OL="));
|
pos = req.indexOf(F("OL="));
|
||||||
@ -917,45 +937,21 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
//you can add more if you need
|
//you can add more if you need
|
||||||
|
|
||||||
//apply to all selected manually to prevent #1618. Temporary
|
//apply to all selected manually to prevent #1618. Temporary
|
||||||
bool col0Changed = false, col1Changed = false;
|
if (strip.applyToAllSelected) {
|
||||||
for (uint8_t i = 0; i < 4; i++) {
|
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||||
if (col[i] != prevCol[i]) col0Changed = true;
|
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||||
if (colSec[i] != prevColSec[i]) col1Changed = true;
|
if (!seg.isActive() || !seg.isSelected() || i == selectedSeg) continue;
|
||||||
}
|
if (effectCurrent != prevEffect) strip.setMode(i, effectCurrent);
|
||||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++)
|
if (effectSpeed != prevSpeed) seg.speed = effectSpeed;
|
||||||
{
|
if (effectIntensity != prevIntensity) seg.intensity = effectIntensity;
|
||||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
if (effectPalette != prevPalette) seg.palette = effectPalette;
|
||||||
if (!seg.isSelected()) continue;
|
if (col0Changed) seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||||
if (effectCurrent != prevEffect) {
|
if (col1Changed) seg.colors[1] = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||||
strip.setMode(i, effectCurrent);
|
if (col2Changed) seg.colors[2] = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
|
||||||
effectChanged = true;
|
|
||||||
}
|
|
||||||
if (effectSpeed != prevSpeed) {
|
|
||||||
seg.speed = effectSpeed;
|
|
||||||
effectChanged = true;
|
|
||||||
}
|
|
||||||
if (effectIntensity != prevIntensity) {
|
|
||||||
seg.intensity = effectIntensity;
|
|
||||||
effectChanged = true;
|
|
||||||
}
|
|
||||||
if (effectPalette != prevPalette) {
|
|
||||||
seg.palette = effectPalette;
|
|
||||||
effectChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (col0Changed) {
|
|
||||||
if (selectedSeg == strip.getMainSegmentId()) {
|
|
||||||
strip.applyToAllSelected = true;
|
|
||||||
strip.setColor(0, colorFromRgbw(col));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (col1Changed) {
|
|
||||||
if (selectedSeg == strip.getMainSegmentId()) {
|
|
||||||
strip.applyToAllSelected = true;
|
|
||||||
strip.setColor(1, colorFromRgbw(colSec));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
strip.applyToAllSelected = false;
|
||||||
|
setValuesFromMainSeg();
|
||||||
//end of temporary fix code
|
//end of temporary fix code
|
||||||
|
|
||||||
if (!apply) return true; //when called by JSON API, do not call colorUpdated() here
|
if (!apply) return true; //when called by JSON API, do not call colorUpdated() here
|
||||||
@ -964,8 +960,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
pos = req.indexOf(F("IN"));
|
pos = req.indexOf(F("IN"));
|
||||||
if (pos < 1) XML_response(request);
|
if (pos < 1) XML_response(request);
|
||||||
|
|
||||||
strip.applyToAllSelected = false;
|
|
||||||
|
|
||||||
pos = req.indexOf(F("&NN")); //do not send UDP notifications this time
|
pos = req.indexOf(F("&NN")); //do not send UDP notifications this time
|
||||||
colorUpdated((pos > 0) ? CALL_MODE_NO_NOTIFY : CALL_MODE_DIRECT_CHANGE);
|
colorUpdated((pos > 0) ? CALL_MODE_NO_NOTIFY : CALL_MODE_DIRECT_CHANGE);
|
||||||
|
|
||||||
|
139
wled00/udp.cpp
139
wled00/udp.cpp
@ -4,7 +4,9 @@
|
|||||||
* UDP sync notifier / Realtime / Hyperion / TPM2.NET
|
* UDP sync notifier / Realtime / Hyperion / TPM2.NET
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define WLEDPACKETSIZE 39
|
#define UDP_SEG_SIZE 28
|
||||||
|
#define SEG_OFFSET (41+(MAX_NUM_SEGMENTS*UDP_SEG_SIZE))
|
||||||
|
#define WLEDPACKETSIZE (41+(MAX_NUM_SEGMENTS*UDP_SEG_SIZE)+0)
|
||||||
#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
|
||||||
|
|
||||||
@ -17,7 +19,7 @@ void notify(byte callMode, bool followUp)
|
|||||||
case CALL_MODE_INIT: return;
|
case CALL_MODE_INIT: return;
|
||||||
case CALL_MODE_DIRECT_CHANGE: if (!notifyDirect) return; break;
|
case CALL_MODE_DIRECT_CHANGE: if (!notifyDirect) return; break;
|
||||||
case CALL_MODE_BUTTON: if (!notifyButton) return; break;
|
case CALL_MODE_BUTTON: if (!notifyButton) return; break;
|
||||||
case CALL_MODE_BUTTON_PRESET: if (!notifyButton) return; break;
|
case CALL_MODE_BUTTON_PRESET: if (!notifyButton) return; break;
|
||||||
case CALL_MODE_NIGHTLIGHT: if (!notifyDirect) return; break;
|
case CALL_MODE_NIGHTLIGHT: if (!notifyDirect) return; break;
|
||||||
case CALL_MODE_HUE: if (!notifyHue) return; break;
|
case CALL_MODE_HUE: if (!notifyHue) return; break;
|
||||||
case CALL_MODE_PRESET_CYCLE: if (!notifyDirect) return; break;
|
case CALL_MODE_PRESET_CYCLE: if (!notifyDirect) return; break;
|
||||||
@ -26,7 +28,7 @@ void notify(byte callMode, bool followUp)
|
|||||||
default: return;
|
default: return;
|
||||||
}
|
}
|
||||||
byte udpOut[WLEDPACKETSIZE];
|
byte udpOut[WLEDPACKETSIZE];
|
||||||
WS2812FX::Segment& mainseg = strip.getSegment(strip.getMainSegmentId());
|
WS2812FX::Segment& mainseg = strip.getSegment(strip.getMainSegmentId());
|
||||||
udpOut[0] = 0; //0: wled notifier protocol 1: WARLS protocol
|
udpOut[0] = 0; //0: wled notifier protocol 1: WARLS protocol
|
||||||
udpOut[1] = callMode;
|
udpOut[1] = callMode;
|
||||||
udpOut[2] = bri;
|
udpOut[2] = bri;
|
||||||
@ -42,8 +44,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];
|
||||||
@ -79,12 +81,50 @@ void notify(byte callMode, bool followUp)
|
|||||||
|
|
||||||
//sync groups
|
//sync groups
|
||||||
udpOut[36] = syncGroups;
|
udpOut[36] = syncGroups;
|
||||||
|
|
||||||
//Might be changed to Kelvin in the future, receiver code should handle that case
|
//Might be changed to Kelvin in the future, receiver code should handle that case
|
||||||
//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();
|
||||||
|
udpOut[40] = UDP_SEG_SIZE; //size of each loop iteration (one segment)
|
||||||
|
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||||
|
WS2812FX::Segment &selseg = strip.getSegment(i);
|
||||||
|
uint16_t ofs = 41 + i*UDP_SEG_SIZE; //start of segment offset byte
|
||||||
|
udpOut[0 +ofs] = i;
|
||||||
|
udpOut[1 +ofs] = selseg.start >> 8;
|
||||||
|
udpOut[2 +ofs] = selseg.start & 0xFF;
|
||||||
|
udpOut[3 +ofs] = selseg.stop >> 8;
|
||||||
|
udpOut[4 +ofs] = selseg.stop & 0xFF;
|
||||||
|
udpOut[5 +ofs] = selseg.grouping;
|
||||||
|
udpOut[6 +ofs] = selseg.spacing;
|
||||||
|
udpOut[7 +ofs] = selseg.offset >> 8;
|
||||||
|
udpOut[8 +ofs] = selseg.offset & 0xFF;
|
||||||
|
udpOut[9 +ofs] = selseg.options & 0x0F; //only take into account mirrored, selected, on, reversed
|
||||||
|
udpOut[10+ofs] = selseg.opacity;
|
||||||
|
udpOut[11+ofs] = selseg.mode;
|
||||||
|
udpOut[12+ofs] = selseg.speed;
|
||||||
|
udpOut[13+ofs] = selseg.intensity;
|
||||||
|
udpOut[14+ofs] = selseg.palette;
|
||||||
|
udpOut[15+ofs] = R(selseg.colors[0]);
|
||||||
|
udpOut[16+ofs] = G(selseg.colors[0]);
|
||||||
|
udpOut[17+ofs] = B(selseg.colors[0]);
|
||||||
|
udpOut[18+ofs] = W(selseg.colors[0]);
|
||||||
|
udpOut[19+ofs] = R(selseg.colors[1]);
|
||||||
|
udpOut[20+ofs] = G(selseg.colors[1]);
|
||||||
|
udpOut[21+ofs] = B(selseg.colors[1]);
|
||||||
|
udpOut[22+ofs] = W(selseg.colors[1]);
|
||||||
|
udpOut[23+ofs] = R(selseg.colors[2]);
|
||||||
|
udpOut[24+ofs] = G(selseg.colors[2]);
|
||||||
|
udpOut[25+ofs] = B(selseg.colors[2]);
|
||||||
|
udpOut[26+ofs] = W(selseg.colors[2]);
|
||||||
|
udpOut[27+ofs] = selseg.cct;
|
||||||
|
}
|
||||||
|
|
||||||
|
//uint16_t offs = SEG_OFFSET;
|
||||||
|
//next value to be added has index: udpOut[offs + 0]
|
||||||
|
|
||||||
IPAddress broadcastIp;
|
IPAddress broadcastIp;
|
||||||
broadcastIp = ~uint32_t(Network.subnetMask()) | uint32_t(Network.gatewayIP());
|
broadcastIp = ~uint32_t(Network.subnetMask()) | uint32_t(Network.gatewayIP());
|
||||||
|
|
||||||
@ -247,47 +287,78 @@ void handleNotifications()
|
|||||||
} else if (!(receiveGroups & udpIn[36])) return;
|
} else if (!(receiveGroups & udpIn[36])) return;
|
||||||
|
|
||||||
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
||||||
//apply colors from notification
|
|
||||||
if (receiveNotificationColor || !someSel)
|
//apply colors from notification to main segment, only if not syncing full segments
|
||||||
{
|
if ((receiveNotificationColor || !someSel) && (version < 11 || !receiveSegmentOptions)) {
|
||||||
col[0] = udpIn[3];
|
col[0] = udpIn[3];
|
||||||
col[1] = udpIn[4];
|
col[1] = udpIn[4];
|
||||||
col[2] = udpIn[5];
|
col[2] = udpIn[5];
|
||||||
if (version > 0) //sending module's white val is intended
|
if (version > 0) //sending module's white val is intended
|
||||||
{
|
{
|
||||||
col[3] = udpIn[10];
|
col[3] = udpIn[10];
|
||||||
if (version > 1)
|
if (version > 1) {
|
||||||
{
|
|
||||||
colSec[0] = udpIn[12];
|
colSec[0] = udpIn[12];
|
||||||
colSec[1] = udpIn[13];
|
colSec[1] = udpIn[13];
|
||||||
colSec[2] = udpIn[14];
|
colSec[2] = udpIn[14];
|
||||||
colSec[3] = udpIn[15];
|
colSec[3] = udpIn[15];
|
||||||
}
|
}
|
||||||
if (version > 6)
|
if (version > 6) {
|
||||||
{
|
strip.setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); //tertiary color
|
||||||
strip.setColor(2, udpIn[20], udpIn[21], udpIn[22], udpIn[23]); //tertiary color
|
if (version > 9 && version < 200 && udpIn[37] < 255) { //valid CCT/Kelvin value
|
||||||
|
uint8_t cct = udpIn[38];
|
||||||
|
if (udpIn[37] > 0) { //Kelvin
|
||||||
|
cct = (((udpIn[37] << 8) + udpIn[38]) - 1900) >> 5;
|
||||||
|
}
|
||||||
|
uint8_t segid = strip.getMainSegmentId();
|
||||||
|
strip.getSegment(segid).setCCT(cct, segid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (version > 9 && version < 200 && udpIn[37] < 255) { //valid CCT/Kelvin value
|
|
||||||
uint8_t cct = udpIn[38];
|
|
||||||
if (udpIn[37] > 0) { //Kelvin
|
|
||||||
cct = (((udpIn[37] << 8) + udpIn[38]) - 1900) >> 5;
|
|
||||||
}
|
|
||||||
uint8_t segid = strip.getMainSegmentId();
|
|
||||||
strip.getSegment(segid).setCCT(cct, segid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool timebaseUpdated = false;
|
bool timebaseUpdated = false;
|
||||||
//apply effects from notification
|
//apply effects from notification
|
||||||
if (version < 200 && (receiveNotificationEffects || !someSel))
|
bool applyEffects = (receiveNotificationEffects || !someSel);
|
||||||
|
if (version < 200)
|
||||||
{
|
{
|
||||||
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
|
if (applyEffects && currentPlaylist >= 0) unloadPlaylist();
|
||||||
effectSpeed = udpIn[9];
|
if (version > 10 && receiveSegmentOptions) {
|
||||||
if (version > 2) effectIntensity = udpIn[16];
|
//does not sync start & stop
|
||||||
if (version > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19];
|
uint8_t srcSegs = udpIn[39];
|
||||||
if (version > 5)
|
//if (srcSegs > strip.getMaxSegments()) srcSegs = strip.getMaxSegments();
|
||||||
{
|
for (uint8_t i = 0; i < srcSegs; i++) {
|
||||||
|
uint16_t ofs = 41 + i*udpIn[40]; //start of segment offset byte
|
||||||
|
uint8_t id = udpIn[0 +ofs];
|
||||||
|
if (id > strip.getMaxSegments()) continue;
|
||||||
|
WS2812FX::Segment& selseg = strip.getSegment(id);
|
||||||
|
//bytes 1+2 contain start, 3+4 stop, unused at this time
|
||||||
|
for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01); //only take into account mirrored, selected, on, reversed
|
||||||
|
selseg.setOpacity(udpIn[10+ofs], id);
|
||||||
|
if (applyEffects) {
|
||||||
|
strip.setMode(id, udpIn[11+ofs]);
|
||||||
|
selseg.speed = udpIn[12+ofs];
|
||||||
|
selseg.intensity = udpIn[13+ofs];
|
||||||
|
selseg.palette = udpIn[14+ofs];
|
||||||
|
}
|
||||||
|
if (receiveNotificationColor || !someSel) {
|
||||||
|
selseg.setColor(0, RGBW32(udpIn[15+ofs],udpIn[16+ofs],udpIn[17+ofs],udpIn[18+ofs]), id);
|
||||||
|
selseg.setColor(1, RGBW32(udpIn[19+ofs],udpIn[20+ofs],udpIn[21+ofs],udpIn[22+ofs]), id);
|
||||||
|
selseg.setColor(2, RGBW32(udpIn[23+ofs],udpIn[24+ofs],udpIn[25+ofs],udpIn[26+ofs]), id);
|
||||||
|
selseg.setCCT(udpIn[27+ofs], id);
|
||||||
|
}
|
||||||
|
strip.setSegment(id, selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], (udpIn[7+ofs]<<8 | udpIn[8+ofs])); //also properly resets segments
|
||||||
|
}
|
||||||
|
setValuesFromMainSeg();
|
||||||
|
effectChanged = true;
|
||||||
|
colorChanged = true;
|
||||||
|
} else if (applyEffects) { //simple effect sync, applies to all selected
|
||||||
|
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
|
||||||
|
effectSpeed = udpIn[9];
|
||||||
|
if (version > 2) effectIntensity = udpIn[16];
|
||||||
|
if (version > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (applyEffects && version > 5) {
|
||||||
uint32_t t = (udpIn[25] << 24) | (udpIn[26] << 16) | (udpIn[27] << 8) | (udpIn[28]);
|
uint32_t t = (udpIn[25] << 24) | (udpIn[26] << 16) | (udpIn[27] << 8) | (udpIn[28]);
|
||||||
t += PRESUMED_NETWORK_DELAY; //adjust trivially for network delay
|
t += PRESUMED_NETWORK_DELAY; //adjust trivially for network delay
|
||||||
t -= millis();
|
t -= millis();
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
// ESP8266-01 (blue) got too little storage space to work with WLED. 0.10.2 is the last release supporting this unit.
|
// ESP8266-01 (blue) got too little storage space to work with WLED. 0.10.2 is the last release supporting this unit.
|
||||||
|
|
||||||
// ESP8266-01 (black) has 1MB flash and can thus fit the whole program, although OTA update is not possible. Use 1M(128K SPIFFS).
|
// ESP8266-01 (black) has 1MB flash and can thus fit the whole program, although OTA update is not possible. Use 1M(128K SPIFFS).
|
||||||
|
// 2-step OTA may still be possible: https://github.com/Aircoookie/WLED/issues/2040#issuecomment-981111096
|
||||||
// Uncomment some of the following lines to disable features:
|
// Uncomment some of the following lines to disable features:
|
||||||
// Alternatively, with platformio pass your chosen flags to your custom build target in platformio_override.ini
|
// Alternatively, with platformio pass your chosen flags to your custom build target in platformio_override.ini
|
||||||
|
|
||||||
@ -313,6 +314,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
|
||||||
@ -424,9 +426,6 @@ WLED_GLOBAL bool interfacesInited _INIT(false);
|
|||||||
WLED_GLOBAL bool wasConnected _INIT(false);
|
WLED_GLOBAL bool wasConnected _INIT(false);
|
||||||
|
|
||||||
// color
|
// color
|
||||||
WLED_GLOBAL byte colIT[] _INIT_N(({ 0, 0, 0, 0 })); // color that was last sent to LEDs
|
|
||||||
WLED_GLOBAL byte colSecIT[] _INIT_N(({ 0, 0, 0, 0 }));
|
|
||||||
|
|
||||||
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same
|
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same
|
||||||
|
|
||||||
// transitions
|
// transitions
|
||||||
@ -477,6 +476,7 @@ WLED_GLOBAL byte effectSpeed _INIT(128);
|
|||||||
WLED_GLOBAL byte effectIntensity _INIT(128);
|
WLED_GLOBAL byte effectIntensity _INIT(128);
|
||||||
WLED_GLOBAL byte effectPalette _INIT(0);
|
WLED_GLOBAL byte effectPalette _INIT(0);
|
||||||
WLED_GLOBAL bool effectChanged _INIT(false);
|
WLED_GLOBAL bool effectChanged _INIT(false);
|
||||||
|
WLED_GLOBAL bool colorChanged _INIT(false);
|
||||||
|
|
||||||
// network
|
// network
|
||||||
WLED_GLOBAL bool udpConnected _INIT(false), udp2Connected _INIT(false), udpRgbConnected _INIT(false);
|
WLED_GLOBAL bool udpConnected _INIT(false), udp2Connected _INIT(false), udpRgbConnected _INIT(false);
|
||||||
|
@ -466,6 +466,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);
|
||||||
|
Loading…
Reference in New Issue
Block a user