Merge branch 'master' into dev
This commit is contained in:
commit
9f885407f5
15
CHANGELOG.md
15
CHANGELOG.md
@ -2,6 +2,21 @@
|
|||||||
|
|
||||||
### Builds after release 0.12.0
|
### Builds after release 0.12.0
|
||||||
|
|
||||||
|
#### Build 2106300
|
||||||
|
|
||||||
|
- Version bump to 0.13.0-b0 "Toki"
|
||||||
|
- BREAKING: Removed preset cycle (use playlists)
|
||||||
|
- BREAKING: Removed `nl.fade`, `leds.pin` and `ccnf` from JSON API
|
||||||
|
- Added playlist editor UI
|
||||||
|
- Reordered segment UI and added offset field
|
||||||
|
- Raised maximum MQTT password length to 64 (closes #1373)
|
||||||
|
|
||||||
|
#### Build 2106290
|
||||||
|
|
||||||
|
- Added Offset to segments, allows shifting the LED considered first within a segment
|
||||||
|
- Added `of` property to seg object in JSON API to set offset
|
||||||
|
- Usermod settings improvements (PR #2043, PR #2045)
|
||||||
|
|
||||||
#### Build 2106250
|
#### Build 2106250
|
||||||
|
|
||||||
- Fixed preset only disabling on second effect/color change
|
- Fixed preset only disabling on second effect/color change
|
||||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.12.2-bl4",
|
"version": "0.13.0-bl0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.12.2-bl4",
|
"version": "0.13.0-bl0",
|
||||||
"description": "Tools for WLED project",
|
"description": "Tools for WLED project",
|
||||||
"main": "tools/cdata.js",
|
"main": "tools/cdata.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
|
@ -474,7 +474,7 @@ class Animated_Staircase : public Usermod {
|
|||||||
// first run: reading from cfg.json
|
// first run: reading from cfg.json
|
||||||
DEBUG_PRINTLN(F(" config loaded."));
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
} else {
|
} else {
|
||||||
// changing paramters from settings page
|
// changing parameters from settings page
|
||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
if ((oldUseUSSensorTop != useUSSensorTop) ||
|
if ((oldUseUSSensorTop != useUSSensorTop) ||
|
||||||
|
@ -273,7 +273,7 @@ class UsermodTemperature : public Usermod {
|
|||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return true;
|
return !top[FPSTR(_parasite)].isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getId()
|
uint16_t getId()
|
||||||
|
@ -648,7 +648,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
type = newType;
|
type = newType;
|
||||||
DEBUG_PRINTLN(F(" config loaded."));
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
} else {
|
} else {
|
||||||
// changing paramters from settings page
|
// changing parameters from settings page
|
||||||
if (sclPin!=newScl || sdaPin!=newSda || type!=newType) {
|
if (sclPin!=newScl || sdaPin!=newSda || type!=newType) {
|
||||||
if (type != NONE) delete (static_cast<U8X8*>(u8x8));
|
if (type != NONE) delete (static_cast<U8X8*>(u8x8));
|
||||||
pinManager.deallocatePin(sclPin);
|
pinManager.deallocatePin(sclPin);
|
||||||
|
11
wled00/FX.h
11
wled00/FX.h
@ -59,7 +59,9 @@
|
|||||||
/* How much data bytes all segments combined may allocate */
|
/* How much data bytes all segments combined may allocate */
|
||||||
#define MAX_SEGMENT_DATA 4096
|
#define MAX_SEGMENT_DATA 4096
|
||||||
#else
|
#else
|
||||||
|
#ifndef MAX_NUM_SEGMENTS
|
||||||
#define MAX_NUM_SEGMENTS 32
|
#define MAX_NUM_SEGMENTS 32
|
||||||
|
#endif
|
||||||
#define MAX_NUM_TRANSITIONS 24
|
#define MAX_NUM_TRANSITIONS 24
|
||||||
#define MAX_SEGMENT_DATA 20480
|
#define MAX_SEGMENT_DATA 20480
|
||||||
#endif
|
#endif
|
||||||
@ -241,9 +243,10 @@ class WS2812FX {
|
|||||||
|
|
||||||
// segment parameters
|
// segment parameters
|
||||||
public:
|
public:
|
||||||
typedef struct Segment { // 28 bytes
|
typedef struct Segment { // 25 (28 in memory?) bytes
|
||||||
uint16_t start;
|
uint16_t start;
|
||||||
uint16_t stop; //segment invalid if stop == 0
|
uint16_t stop; //segment invalid if stop == 0
|
||||||
|
uint16_t offset;
|
||||||
uint8_t speed;
|
uint8_t speed;
|
||||||
uint8_t intensity;
|
uint8_t intensity;
|
||||||
uint8_t palette;
|
uint8_t palette;
|
||||||
@ -855,9 +858,9 @@ class WS2812FX {
|
|||||||
|
|
||||||
uint8_t _segment_index = 0;
|
uint8_t _segment_index = 0;
|
||||||
uint8_t _segment_index_palette_last = 99;
|
uint8_t _segment_index_palette_last = 99;
|
||||||
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 28 bytes per element
|
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 24 bytes per element
|
||||||
// start, stop, speed, intensity, palette, mode, options, grouping, spacing, opacity (unused), color[]
|
// start, stop, offset, speed, intensity, palette, mode, options, grouping, spacing, opacity (unused), color[]
|
||||||
{ 0, 7, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}, nullptr }
|
{0, 7, 0, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}}
|
||||||
};
|
};
|
||||||
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
|
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
|
||||||
friend class Segment_runtime;
|
friend class Segment_runtime;
|
||||||
|
@ -224,15 +224,24 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
|||||||
|
|
||||||
/* Set all the pixels in the group */
|
/* Set all the pixels in the group */
|
||||||
uint16_t realIndex = realPixelIndex(i);
|
uint16_t realIndex = realPixelIndex(i);
|
||||||
|
uint16_t len = SEGMENT.length();
|
||||||
|
|
||||||
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
|
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
|
||||||
uint16_t indexSet = realIndex + (IS_REVERSE ? -j : j);
|
uint16_t indexSet = realIndex + (IS_REVERSE ? -j : j);
|
||||||
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) {
|
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) {
|
||||||
if (IS_MIRROR) { //set the corresponding mirrored pixel
|
if (IS_MIRROR) { //set the corresponding mirrored pixel
|
||||||
uint16_t indexMir = SEGMENT.stop + SEGMENT.start - indexSet - 1;
|
uint16_t indexMir = SEGMENT.stop - indexSet + SEGMENT.start - 1;
|
||||||
|
/* offset/phase */
|
||||||
|
indexMir += SEGMENT.offset;
|
||||||
|
if (indexMir >= SEGMENT.stop) indexMir -= len;
|
||||||
|
|
||||||
if (indexMir < customMappingSize) indexMir = customMappingTable[indexMir];
|
if (indexMir < customMappingSize) indexMir = customMappingTable[indexMir];
|
||||||
busses.setPixelColor(indexMir, col);
|
busses.setPixelColor(indexMir, col);
|
||||||
}
|
}
|
||||||
|
/* offset/phase */
|
||||||
|
indexSet += SEGMENT.offset;
|
||||||
|
if (indexSet >= SEGMENT.stop) indexSet -= len;
|
||||||
|
|
||||||
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
|
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
|
||||||
busses.setPixelColor(indexSet, col);
|
busses.setPixelColor(indexSet, col);
|
||||||
}
|
}
|
||||||
@ -512,6 +521,12 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
|
|||||||
{
|
{
|
||||||
i = realPixelIndex(i);
|
i = realPixelIndex(i);
|
||||||
|
|
||||||
|
if (SEGLEN) {
|
||||||
|
/* offset/phase */
|
||||||
|
i += SEGMENT.offset;
|
||||||
|
if (i >= SEGMENT.stop) i -= SEGMENT.length();
|
||||||
|
}
|
||||||
|
|
||||||
if (i < customMappingSize) i = customMappingTable[i];
|
if (i < customMappingSize) i = customMappingTable[i];
|
||||||
if (i >= _length) return 0;
|
if (i >= _length) return 0;
|
||||||
|
|
||||||
|
@ -217,15 +217,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
CJSON(turnOnAtBoot, def["on"]); // true
|
CJSON(turnOnAtBoot, def["on"]); // true
|
||||||
CJSON(briS, def["bri"]); // 128
|
CJSON(briS, def["bri"]); // 128
|
||||||
|
|
||||||
JsonObject def_cy = def[F("cy")];
|
|
||||||
CJSON(presetCyclingEnabled, def_cy["on"]);
|
|
||||||
|
|
||||||
CJSON(presetCycleMin, def_cy[F("range")][0]);
|
|
||||||
CJSON(presetCycleMax, def_cy[F("range")][1]);
|
|
||||||
|
|
||||||
tdd = def_cy["dur"] | -1;
|
|
||||||
if (tdd > 0) presetCycleTime = tdd;
|
|
||||||
|
|
||||||
JsonObject interfaces = doc["if"];
|
JsonObject interfaces = doc["if"];
|
||||||
|
|
||||||
JsonObject if_sync = interfaces[F("sync")];
|
JsonObject if_sync = interfaces[F("sync")];
|
||||||
@ -292,7 +283,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
getStringFromJson(mqttServer, if_mqtt[F("broker")], 33);
|
getStringFromJson(mqttServer, if_mqtt[F("broker")], 33);
|
||||||
CJSON(mqttPort, if_mqtt["port"]); // 1883
|
CJSON(mqttPort, if_mqtt["port"]); // 1883
|
||||||
getStringFromJson(mqttUser, if_mqtt[F("user")], 41);
|
getStringFromJson(mqttUser, if_mqtt[F("user")], 41);
|
||||||
getStringFromJson(mqttPass, if_mqtt["psk"], 41); //normally not present due to security
|
getStringFromJson(mqttPass, if_mqtt["psk"], 65); //normally not present due to security
|
||||||
getStringFromJson(mqttClientID, if_mqtt[F("cid")], 41);
|
getStringFromJson(mqttClientID, if_mqtt[F("cid")], 41);
|
||||||
|
|
||||||
getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test"
|
getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test"
|
||||||
@ -583,17 +574,6 @@ void serializeConfig() {
|
|||||||
def["on"] = turnOnAtBoot;
|
def["on"] = turnOnAtBoot;
|
||||||
def["bri"] = briS;
|
def["bri"] = briS;
|
||||||
|
|
||||||
//to be removed once preset cycles are presets
|
|
||||||
if (saveCurrPresetCycConf) {
|
|
||||||
JsonObject def_cy = def.createNestedObject("cy");
|
|
||||||
def_cy["on"] = presetCyclingEnabled;
|
|
||||||
|
|
||||||
JsonArray def_cy_range = def_cy.createNestedArray(F("range"));
|
|
||||||
def_cy_range.add(presetCycleMin);
|
|
||||||
def_cy_range.add(presetCycleMax);
|
|
||||||
def_cy["dur"] = presetCycleTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonObject interfaces = doc.createNestedObject("if");
|
JsonObject interfaces = doc.createNestedObject("if");
|
||||||
|
|
||||||
JsonObject if_sync = interfaces.createNestedObject("sync");
|
JsonObject if_sync = interfaces.createNestedObject("sync");
|
||||||
@ -768,7 +748,7 @@ bool deserializeConfigSec() {
|
|||||||
|
|
||||||
#ifdef WLED_ENABLE_MQTT
|
#ifdef WLED_ENABLE_MQTT
|
||||||
JsonObject if_mqtt = interfaces["mqtt"];
|
JsonObject if_mqtt = interfaces["mqtt"];
|
||||||
getStringFromJson(mqttPass, if_mqtt["psk"], 41);
|
getStringFromJson(mqttPass, if_mqtt["psk"], 65);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_HUESYNC
|
#ifndef WLED_DISABLE_HUESYNC
|
||||||
|
@ -137,7 +137,7 @@ button {
|
|||||||
|
|
||||||
.segt TD {
|
.segt TD {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-transform: uppercase;
|
/*text-transform: uppercase;*/
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
@ -407,9 +407,8 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#imgw {
|
#imgw {
|
||||||
width: 200px;
|
|
||||||
height: 55px;
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
margin: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#kv, #kn {
|
#kv, #kn {
|
||||||
@ -437,6 +436,12 @@ img {
|
|||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wi {
|
||||||
|
image-rendering: pixelated;
|
||||||
|
image-rendering: crisp-edges;
|
||||||
|
width: 210px;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes fadein {
|
@keyframes fadein {
|
||||||
from {bottom: 0; opacity: 0;}
|
from {bottom: 0; opacity: 0;}
|
||||||
to {bottom: calc(var(--bh) + 22px); opacity: 1;}
|
to {bottom: calc(var(--bh) + 22px); opacity: 1;}
|
||||||
@ -526,6 +531,10 @@ input[type=range]::-moz-range-thumb {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sbs {
|
||||||
|
margin: 0px -20px 5px -6px;
|
||||||
|
}
|
||||||
|
|
||||||
.sws {
|
.sws {
|
||||||
width: 220px;
|
width: 220px;
|
||||||
}
|
}
|
||||||
@ -554,7 +563,7 @@ input[type=range]::-moz-range-thumb {
|
|||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
margin: 10px;
|
margin: 10px 4px;
|
||||||
width: 230px;
|
width: 230px;
|
||||||
font-size: 19px;
|
font-size: 19px;
|
||||||
background-color: var(--c-3);
|
background-color: var(--c-3);
|
||||||
@ -568,12 +577,11 @@ input[type=range]::-moz-range-thumb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-s {
|
.btn-s {
|
||||||
padding: 9px;
|
|
||||||
width: 276px;
|
width: 276px;
|
||||||
background-color: var(--c-2);
|
background-color: var(--c-2);
|
||||||
}
|
}
|
||||||
.btn-i {
|
.btn-i {
|
||||||
padding-bottom: 3px;
|
padding-bottom: 4px;
|
||||||
}
|
}
|
||||||
.btn-icon {
|
.btn-icon {
|
||||||
margin: 0px 8px 4px 0;
|
margin: 0px 8px 4px 0;
|
||||||
@ -584,6 +592,18 @@ input[type=range]::-moz-range-thumb {
|
|||||||
}
|
}
|
||||||
.btn-p {
|
.btn-p {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
.btn-xs, .btn-pl-del, .btn-pl-add {
|
||||||
|
width: 42px;
|
||||||
|
}
|
||||||
|
.btn-pl-del, .btn-pl-add {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.btn-pl-add {
|
||||||
|
position: relative;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 101px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#qcs-w {
|
#qcs-w {
|
||||||
@ -603,6 +623,15 @@ input[type=range]::-moz-range-thumb {
|
|||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.sel-pl {
|
||||||
|
width: 200px;
|
||||||
|
background-position: 176px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sel-ple {
|
||||||
|
width: 216px;
|
||||||
|
background-position: 192px 16px;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
.cl {
|
.cl {
|
||||||
width: 42px;
|
width: 42px;
|
||||||
@ -672,6 +701,11 @@ input[type=text] {
|
|||||||
margin: 6px !important;
|
margin: 6px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.plentry {
|
||||||
|
margin-top: 6px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.stxt {
|
.stxt {
|
||||||
width: 50px !important;
|
width: 50px !important;
|
||||||
}
|
}
|
||||||
@ -751,13 +785,19 @@ input[type=number]::-webkit-outer-spin-button {
|
|||||||
color: var(--c-f);
|
color: var(--c-f);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: var(--c-3);
|
background: var(--c-3);
|
||||||
border-radius: 5px;
|
border-radius: 25px;
|
||||||
padding: 42px 8px;
|
padding: 8px;
|
||||||
margin: -8px 0 0;
|
margin: -8px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cnf-s {
|
.cnf-s {
|
||||||
|
/*
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
position: absolute;
|
||||||
|
top: 173px;
|
||||||
|
right: 23px;
|
||||||
|
padding: 7px 22px;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.pwr {
|
.pwr {
|
||||||
@ -1055,6 +1095,16 @@ input[type="text"].fnd:not(:placeholder-shown) {
|
|||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hrz {
|
||||||
|
width: auto;
|
||||||
|
height: 2px;
|
||||||
|
background-color: var(--c-e);
|
||||||
|
}
|
||||||
|
.hrz-pl {
|
||||||
|
margin: 20px 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 6px;
|
width: 6px;
|
||||||
}
|
}
|
||||||
|
@ -182,15 +182,7 @@
|
|||||||
<div id="pcont">
|
<div id="pcont">
|
||||||
Loading...
|
Loading...
|
||||||
</div><br>
|
</div><br>
|
||||||
<label class="check psvl">
|
Transition <input id="tt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7">s
|
||||||
Preset cycle
|
|
||||||
<input type="checkbox" id="cyToggle" onchange="toggleCY()">
|
|
||||||
<span class="checkmark psv"></span>
|
|
||||||
</label><br>
|
|
||||||
First preset: <input id="cycs" class="noslide" type="number" min="1" max="249" value="1"><br>
|
|
||||||
Last preset: <input id="cyce" class="noslide" type="number" min="2" max="250" value="3"><br>
|
|
||||||
Time per preset: <input id="cyct" class="noslide" type="number" min="0.2" max="6553.5" step="0.1" value="1.2">s<br>
|
|
||||||
Transition: <input id="cyctt" class="noslide" type="number" min="0" max="65.5" step="0.1" value="0.7">s<br><br>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -207,7 +199,7 @@
|
|||||||
<div id="namelabel" onclick="toggleNodes()"></div>
|
<div id="namelabel" onclick="toggleNodes()"></div>
|
||||||
<div id="info" class="modal">
|
<div id="info" class="modal">
|
||||||
<div id="imgw">
|
<div id="imgw">
|
||||||
<img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAggAAACMCAYAAAAZQlGEAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKLSURBVHhe7dgxjtwwEADBpf//5zUDwklnpzFAnKoSTigNFTT0AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGDcOieX+G5nvNLaznil6f1Nv+/tz3c7+3tmen/Tpu/jbe877c85AQD+EQgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAQiAAACEQAIAQCABACAQAINY5+aHvdsYRazvjK9jfM7fvz/0+Y3+/2+336w8CABACAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAADEOudrfLczXmltZ3yF6fuwv2em9+d+n5ne3zT3cZfp+/AHAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAYp3zNb7bGUes7Yz8wO334fmeuf35bmd/z9y+v9ufzx8EACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAgBAIAEAIBAAiBAACEQAAAQiAAACEQAIAQCABACAQAIAQCABACAQCIdc4x3+2MV1rbGfmFpr+/6e/l9ue73fT+pt1+H2/bn+/lGX8QAIAQCABACAQAIAQCABACAQAIgQAAhEAAAEIgAAAhEACAEAgAQAgEACAEAgAQAgEACIEAAIRAAABCIAAAIRAAgBAIAEAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgP/u8/kLYCqAxINTyZkAAAAASUVORK5CYII=">
|
<img class="wi" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAAFCAYAAAC5Fuf5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABbSURBVChTlY9bDoAwDMNW7n9nwCipytQN4Z8tbrTHmDmF4oPzyldwRqp1SSdnV/NuZuzqerAByxXznBw3igkeFEfXyUuhK/yFM0CxJfyqXZEOc6/Sr9/bf7uIC5Nwd7orMvAPAAAAAElFTkSuQmCC" />
|
||||||
</div><br>
|
</div><br>
|
||||||
<div id="kv">Loading...</div><br>
|
<div id="kv">Loading...</div><br>
|
||||||
<button class="btn infobtn" onclick="loadInfo()">Refresh</button>
|
<button class="btn infobtn" onclick="loadInfo()">Refresh</button>
|
||||||
|
@ -15,6 +15,8 @@ var currentPreset = -1;
|
|||||||
var lastUpdate = 0;
|
var lastUpdate = 0;
|
||||||
var segCount = 0, ledCount = 0, lowestUnused = 0, maxSeg = 0, lSeg = 0;
|
var segCount = 0, ledCount = 0, lowestUnused = 0, maxSeg = 0, lSeg = 0;
|
||||||
var pcMode = false, pcModeA = false, lastw = 0;
|
var pcMode = false, pcModeA = false, lastw = 0;
|
||||||
|
var tr = 7;
|
||||||
|
var pNum = 0;
|
||||||
var d = document;
|
var d = document;
|
||||||
const ranges = RangeTouch.setup('input[type="range"]', {});
|
const ranges = RangeTouch.setup('input[type="range"]', {});
|
||||||
var palettesData;
|
var palettesData;
|
||||||
@ -55,6 +57,7 @@ var cpick = new iro.ColorPicker("#picker", {
|
|||||||
function handleVisibilityChange() {if (!d.hidden && new Date () - lastUpdate > 3000) requestJson({'v':true},false);}
|
function handleVisibilityChange() {if (!d.hidden && new Date () - lastUpdate > 3000) requestJson({'v':true},false);}
|
||||||
function sCol(na, col) {d.documentElement.style.setProperty(na, col);}
|
function sCol(na, col) {d.documentElement.style.setProperty(na, col);}
|
||||||
function gId(c) {return d.getElementById(c);}
|
function gId(c) {return d.getElementById(c);}
|
||||||
|
function gEBCN(c) {return d.getElementsByClassName(c);}
|
||||||
|
|
||||||
function applyCfg()
|
function applyCfg()
|
||||||
{
|
{
|
||||||
@ -268,7 +271,7 @@ function onLoad()
|
|||||||
|
|
||||||
function updateTablinks(tabI)
|
function updateTablinks(tabI)
|
||||||
{
|
{
|
||||||
var tablinks = d.getElementsByClassName("tablinks");
|
var tablinks = gEBCN("tablinks");
|
||||||
for (var i of tablinks) i.className = i.className.replace(" active", "");
|
for (var i of tablinks) i.className = i.className.replace(" active", "");
|
||||||
if (pcMode) return;
|
if (pcMode) return;
|
||||||
tablinks[tabI].className += " active";
|
tablinks[tabI].className += " active";
|
||||||
@ -342,6 +345,11 @@ function pName(i)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPlaylist(i)
|
||||||
|
{
|
||||||
|
return pJson[i].playlist && pJson[i].playlist.ps;
|
||||||
|
}
|
||||||
|
|
||||||
function papiVal(i)
|
function papiVal(i)
|
||||||
{
|
{
|
||||||
if (!pJson || !pJson[i]) return "";
|
if (!pJson || !pJson[i]) return "";
|
||||||
@ -500,10 +508,9 @@ function populatePresets(fromls)
|
|||||||
var cn = "";
|
var cn = "";
|
||||||
var arr = Object.entries(pJson);
|
var arr = Object.entries(pJson);
|
||||||
arr.sort(cmpP);
|
arr.sort(cmpP);
|
||||||
var added = false;
|
|
||||||
pQL = [];
|
pQL = [];
|
||||||
var is = [];
|
var is = [];
|
||||||
|
pNum = 0;
|
||||||
for (var key of (arr||[]))
|
for (var key of (arr||[]))
|
||||||
{
|
{
|
||||||
if (!isObject(key[1])) continue;
|
if (!isObject(key[1])) continue;
|
||||||
@ -514,15 +521,15 @@ function populatePresets(fromls)
|
|||||||
|
|
||||||
cn += `<div class="seg pres" id="p${i}o">`;
|
cn += `<div class="seg pres" id="p${i}o">`;
|
||||||
if (cfg.comp.pid) cn += `<div class="pid">${i}</div>`;
|
if (cfg.comp.pid) cn += `<div class="pid">${i}</div>`;
|
||||||
cn += `<div class="pname" onclick="setPreset(${i})">${pName(i)}</div>
|
cn += `<div class="pname" onclick="setPreset(${i})">${isPlaylist(i)?"<i class='icons btn-icon'></i>":""}${pName(i)}</div>
|
||||||
<i class="icons e-icon flr ${expanded[i+100] ? "exp":""}" id="sege${i+100}" onclick="expand(${i+100})"></i>
|
<i class="icons e-icon flr ${expanded[i+100] ? "exp":""}" id="sege${i+100}" onclick="expand(${i+100})"></i>
|
||||||
<div class="segin" id="seg${i+100}"></div>
|
<div class="segin" id="seg${i+100}"></div>
|
||||||
</div><br>`;
|
</div><br>`;
|
||||||
added = true;
|
pNum++;
|
||||||
}
|
}
|
||||||
|
|
||||||
gId('pcont').innerHTML = cn;
|
gId('pcont').innerHTML = cn;
|
||||||
if (added) {
|
if (pNum > 0) {
|
||||||
if (pmtLS != pmt && pmt != 0) {
|
if (pmtLS != pmt && pmt != 0) {
|
||||||
localStorage.setItem("wledPmt", pmt);
|
localStorage.setItem("wledPmt", pmt);
|
||||||
pJson["0"] = {};
|
pJson["0"] = {};
|
||||||
@ -533,6 +540,7 @@ function populatePresets(fromls)
|
|||||||
let i = is[a];
|
let i = is[a];
|
||||||
if (expanded[i+100]) expand(i+100, true);
|
if (expanded[i+100]) expand(i+100, true);
|
||||||
}
|
}
|
||||||
|
makePlSel(arr);
|
||||||
} else { presetError(true); }
|
} else { presetError(true); }
|
||||||
updatePA(true);
|
updatePA(true);
|
||||||
populateQL();
|
populateQL();
|
||||||
@ -591,7 +599,7 @@ function populateInfo(i)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var vcn = "Kuuhaku";
|
var vcn = "Kuuhaku";
|
||||||
if (i.ver.startsWith("0.12.")) vcn = "Hikari";
|
if (i.ver.startsWith("0.13.")) vcn = "Toki";
|
||||||
if (i.ver.includes("-bl")) vcn = "Ryujin";
|
if (i.ver.includes("-bl")) vcn = "Ryujin";
|
||||||
if (i.cn) vcn = i.cn;
|
if (i.cn) vcn = i.cn;
|
||||||
|
|
||||||
@ -645,27 +653,32 @@ function populateSegments(s)
|
|||||||
</div>
|
</div>
|
||||||
<div class="segin ${expanded[i] ? "expanded":""}" id="seg${i}">
|
<div class="segin ${expanded[i] ? "expanded":""}" id="seg${i}">
|
||||||
<input type="text" class="ptxt noslide" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/><br>
|
<input type="text" class="ptxt noslide" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/><br>
|
||||||
<table class="segt">
|
<table class="infot segt">
|
||||||
<tr>
|
<tr>
|
||||||
<td width="38%">Start LED</td>
|
<td>Start LED</td>
|
||||||
<td width="38%">${cfg.comp.seglen?"LED count":"Stop LED"}</td>
|
<td>${cfg.comp.seglen?"LED count":"Stop LED"}</td>
|
||||||
|
<td>Offset</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><input class="noslide segn" id="seg${i}s" type="number" min="0" max="${ledCount-1}" value="${inst.start}" oninput="updateLen(${i})"></td>
|
<td><input class="noslide segn" id="seg${i}s" type="number" min="0" max="${ledCount-1}" value="${inst.start}" oninput="updateLen(${i})"></td>
|
||||||
<td><input class="noslide segn" id="seg${i}e" type="number" min="0" max="${ledCount-(cfg.comp.seglen?inst.start:0)}" value="${inst.stop-(cfg.comp.seglen?inst.start:0)}" oninput="updateLen(${i})"></td>
|
<td><input class="noslide segn" id="seg${i}e" type="number" min="0" max="${ledCount-(cfg.comp.seglen?inst.start:0)}" value="${inst.stop-(cfg.comp.seglen?inst.start:0)}" oninput="updateLen(${i})"></td>
|
||||||
<td rowspan="3"><i class="icons e-icon cnf" id="segc${i}" onclick="setSeg(${i})"></i></td>
|
<td><input class="noslide segn" id="seg${i}of" type="number" min="0" max="${ledCount-1}" value="${inst.of}" oninput="updateLen(${i})"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table class="infot segt">
|
||||||
<tr>
|
<tr>
|
||||||
<td>Grouping</td>
|
<td>Grouping</td>
|
||||||
<td>Spacing</td>
|
<td>Spacing</td>
|
||||||
|
<td>Apply</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><input class="noslide segn" id="seg${i}grp" type="number" min="1" max="255" value="${inst.grp}" oninput="updateLen(${i})"></td>
|
<td><input class="noslide segn" id="seg${i}grp" type="number" min="1" max="255" value="${inst.grp}" oninput="updateLen(${i})"></td>
|
||||||
<td><input class="noslide segn" id="seg${i}spc" type="number" min="0" max="255" value="${inst.spc}" oninput="updateLen(${i})"></td>
|
<td><input class="noslide segn" id="seg${i}spc" type="number" min="0" max="255" value="${inst.spc}" oninput="updateLen(${i})"></td>
|
||||||
|
<td><i class="icons e-icon cnf cnf-s" id="segc${i}" onclick="setSeg(${i})"></i></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="h bp" id="seg${i}len"></div>
|
<div class="h bp" id="seg${i}len"></div>
|
||||||
<i class="icons e-icon del" id="segd${i}" onclick="delSeg(${i})"></i>
|
<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":""}>
|
||||||
@ -953,11 +966,11 @@ function updateLen(s)
|
|||||||
|
|
||||||
function updatePA(scrollto=false)
|
function updatePA(scrollto=false)
|
||||||
{
|
{
|
||||||
var ps = d.getElementsByClassName("seg");
|
var ps = gEBCN("seg");
|
||||||
for (let i = 0; i < ps.length; i++) {
|
for (let i = 0; i < ps.length; i++) {
|
||||||
ps[i].style.backgroundColor = "var(--c-2)";
|
ps[i].style.backgroundColor = "var(--c-2)";
|
||||||
}
|
}
|
||||||
ps = d.getElementsByClassName("psts");
|
ps = gEBCN("psts");
|
||||||
for (let i = 0; i < ps.length; i++) {
|
for (let i = 0; i < ps.length; i++) {
|
||||||
ps[i].style.backgroundColor = "var(--c-2)";
|
ps[i].style.backgroundColor = "var(--c-2)";
|
||||||
}
|
}
|
||||||
@ -1175,7 +1188,7 @@ function togglePower()
|
|||||||
{
|
{
|
||||||
isOn = !isOn;
|
isOn = !isOn;
|
||||||
var obj = {"on": isOn};
|
var obj = {"on": isOn};
|
||||||
obj.transition = parseInt(gId('cyctt').value*10);
|
obj.transition = parseInt(gId('tt').value*10);
|
||||||
requestJson(obj, false, noWS);
|
requestJson(obj, false, noWS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1259,22 +1272,115 @@ function resetUtil()
|
|||||||
gId('segutil').innerHTML = '<button class="btn btn-s btn-i" onclick="makeSeg()"><i class="icons btn-icon"></i>Add segment</button><br>';
|
gId('segutil').innerHTML = '<button class="btn btn-s btn-i" onclick="makeSeg()"><i class="icons btn-icon"></i>Add segment</button><br>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeP(i)
|
var plJson = {"0":{
|
||||||
{
|
"ps": [0],
|
||||||
return `<input type="text" class="ptxt noslide" id="p${i}txt" autocomplete="off" maxlength=32 value="${(i>0)?pName(i):""}" placeholder="Enter name..."/><br>
|
"dur": [100],
|
||||||
<div class="c">Quick load label: <input type="text" class="stxt noslide" maxlength=2 value="${qlName(i)}" id="p${i}ql" autocomplete="off"/></div>
|
"transition": [-1], //to be inited to default transition dur
|
||||||
<div class="h">(leave empty for no Quick load button)</div>
|
"repeat": 0,
|
||||||
<label class="check revchkl">
|
"r": false,
|
||||||
${(i>0)?"Overwrite with state":"Use current state"}
|
"end": 0
|
||||||
<input type="checkbox" id="p${i}cstgl" onchange="tglCs(${i})" ${(i>0)?"":"checked"}>
|
}};
|
||||||
|
|
||||||
|
var plSelContent = "";
|
||||||
|
function makePlSel(arr) {
|
||||||
|
plSelContent = "";
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
var n = arr[i][1].n ? arr[i][1].n : "Preset " + arr[i][0];
|
||||||
|
if (arr[i][1].playlist && arr[i][1].playlist.ps) continue; //remove playlists, sub-playlists not yet supported
|
||||||
|
plSelContent += `<option value=${arr[i][0]}>${n}</option>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshPlE(p) {
|
||||||
|
var plEDiv = gId(`ple${p}`);
|
||||||
|
if (!plEDiv) return;
|
||||||
|
var content = "";
|
||||||
|
for (var i = 0; i < plJson[p].ps.length; i++) {
|
||||||
|
content += makePlEntry(p,i);
|
||||||
|
}
|
||||||
|
content += `<div class="hrz hrz-pl"><button class="btn btn-i btn-pl-add" onclick="addPl(${p},${i})"><i class="icons btn-icon"></i></button></div>`;
|
||||||
|
plEDiv.innerHTML = content;
|
||||||
|
var dels = plEDiv.getElementsByClassName("btn-pl-del");
|
||||||
|
if (dels.length < 2 && p > 0) dels[0].style.display = "none";
|
||||||
|
|
||||||
|
var sels = gId(`seg${p+100}`).getElementsByClassName("sel");
|
||||||
|
for (var i of sels) {
|
||||||
|
if (i.dataset.val) {
|
||||||
|
if (parseInt(i.dataset.val) > 0) i.value = i.dataset.val;
|
||||||
|
else plJson[p].ps[i.dataset.index] = parseInt(i.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//p: preset ID, i: ps index
|
||||||
|
function addPl(p,i) {
|
||||||
|
plJson[p].ps.splice(i+1,0,0);
|
||||||
|
plJson[p].dur.splice(i+1,0,plJson[p].dur[i]);
|
||||||
|
plJson[p].transition.splice(i+1,0,plJson[p].transition[i]);
|
||||||
|
refreshPlE(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
function delPl(p,i) {
|
||||||
|
if (plJson[p].ps.length < 2) {if (p == 0) resetPUtil(); return;}
|
||||||
|
plJson[p].ps.splice(i,1);
|
||||||
|
plJson[p].dur.splice(i,1);
|
||||||
|
plJson[p].transition.splice(i,1);
|
||||||
|
refreshPlE(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
function plePs(p,i,field) {
|
||||||
|
plJson[p].ps[i] = parseInt(field.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pleDur(p,i,field) {
|
||||||
|
if (field.validity.valid)
|
||||||
|
plJson[p].dur[i] = Math.floor(field.value*10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pleTr(p,i,field) {
|
||||||
|
if (field.validity.valid)
|
||||||
|
plJson[p].transition[i] = Math.floor(field.value*10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function plR(p) {
|
||||||
|
var pl = plJson[p];
|
||||||
|
pl.r = gId(`pl${p}rtgl`).checked;
|
||||||
|
if (gId(`pl${p}rptgl`).checked) { //infinite
|
||||||
|
pl.repeat = 0;
|
||||||
|
delete pl.end;
|
||||||
|
gId(`pl${p}o1`).style.display = "none";
|
||||||
|
} else {
|
||||||
|
pl.repeat = parseInt(gId(`pl${p}rp`).value);
|
||||||
|
pl.end = parseInt(gId(`pl${p}selEnd`).value);
|
||||||
|
gId(`pl${p}o1`).style.display = "block";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeP(i,pl) {
|
||||||
|
var content = "";
|
||||||
|
if (pl) {
|
||||||
|
var rep = plJson[i].repeat ? plJson[i].repeat : 0;
|
||||||
|
content =
|
||||||
|
`<div id="ple${i}"></div><label class="check revchkl">Shuffle
|
||||||
|
<input type="checkbox" id="pl${i}rtgl" onchange="plR(${i})" ${plJson[i].r?"checked":""}>
|
||||||
<span class="checkmark schk"></span>
|
<span class="checkmark schk"></span>
|
||||||
</label><br>
|
</label>
|
||||||
<div class="po2" id="p${i}o2">
|
<label class="check revchkl">Repeat indefinitely
|
||||||
API command<br>
|
<input type="checkbox" id="pl${i}rptgl" onchange="plR(${i})" ${rep?"":"checked"}>
|
||||||
<textarea class="noslide" id="p${i}api"></textarea>
|
<span class="checkmark schk"></span>
|
||||||
|
</label>
|
||||||
|
<div id="pl${i}o1" style="display:${rep?"block":"none"}">
|
||||||
|
<div class="c">Repeat <input class="noslide" type="number" id="pl${i}rp" oninput="plR(${i})" max=127 min=0 value=${rep>0?rep:1}> times</div>
|
||||||
|
End preset:<br>
|
||||||
|
<select class="btn sel sel-ple" id="pl${i}selEnd" onchange="plR(${i})" data-val=${plJson[i].end?plJson[i].end:0}>
|
||||||
|
<option value=0>None</option>
|
||||||
|
${plSelContent}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="po1" id="p${i}o1">
|
<div class="c"><button class="btn btn-i btn-p" onclick="testPl(${i}, this)"><i class='icons btn-icon'></i>Test</button></div>`;
|
||||||
<label class="check revchkl">
|
} else
|
||||||
|
content =
|
||||||
|
`<label class="check revchkl">
|
||||||
Include brightness
|
Include brightness
|
||||||
<input type="checkbox" id="p${i}ibtgl" checked>
|
<input type="checkbox" id="p${i}ibtgl" checked>
|
||||||
<span class="checkmark schk"></span>
|
<span class="checkmark schk"></span>
|
||||||
@ -1283,28 +1389,79 @@ function makeP(i)
|
|||||||
Save segment bounds
|
Save segment bounds
|
||||||
<input type="checkbox" id="p${i}sbtgl" checked>
|
<input type="checkbox" id="p${i}sbtgl" checked>
|
||||||
<span class="checkmark schk"></span>
|
<span class="checkmark schk"></span>
|
||||||
</label>
|
</label>`;
|
||||||
|
|
||||||
|
return `<input type="text" class="ptxt noslide" id="p${i}txt" autocomplete="off" maxlength=32 value="${(i>0)?pName(i):""}" placeholder="Enter name..."/><br>
|
||||||
|
<div class="c">Quick load label: <input type="text" class="stxt noslide" maxlength=2 value="${qlName(i)}" id="p${i}ql" autocomplete="off"/></div>
|
||||||
|
<div class="h">(leave empty for no Quick load button)</div>
|
||||||
|
<div ${pl&&i==0?"style='display:none'":""}>
|
||||||
|
<label class="check revchkl">
|
||||||
|
${pl?"Show playlist editor":(i>0)?"Overwrite with state":"Use current state"}
|
||||||
|
<input type="checkbox" id="p${i}cstgl" onchange="tglCs(${i})" ${(i==0||pl)?"checked":""}>
|
||||||
|
<span class="checkmark schk"></span>
|
||||||
|
</label><br>
|
||||||
|
</div>
|
||||||
|
<div class="po2" id="p${i}o2">
|
||||||
|
API command<br>
|
||||||
|
<textarea class="noslide" id="p${i}api"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="po1" id="p${i}o1">
|
||||||
|
${content}
|
||||||
</div>
|
</div>
|
||||||
<div class="c">Save to ID <input class="noslide" id="p${i}id" type="number" oninput="checkUsed(${i})" max=250 min=1 value=${(i>0)?i:getLowestUnusedP()}></div>
|
<div class="c">Save to ID <input class="noslide" id="p${i}id" type="number" oninput="checkUsed(${i})" max=250 min=1 value=${(i>0)?i:getLowestUnusedP()}></div>
|
||||||
<div class="c">
|
<div class="c">
|
||||||
<button class="btn btn-p" onclick="saveP(${i})"><i class="icons btn-icon"></i>${(i>0)?"Save changes":"Save preset"}</button>
|
<button class="btn btn-i btn-p" onclick="saveP(${i},${pl})"><i class="icons btn-icon"></i>Save ${(pl)?"playlist":(i>0)?"changes":"preset"}</button>
|
||||||
${(i>0)?'<button class="btn btn-p" onclick="delP('+i+')"><i class="icons btn-icon"></i>Delete preset</button>':'<button class="btn btn-p" onclick="resetPUtil()">Cancel</button>'}
|
${(i>0)?'<button class="btn btn-i btn-p" id="p'+i+'del" onclick="delP('+i+')"><i class="icons btn-icon"></i>Delete '+(pl?"playlist":"preset"):'<button class="btn btn-p" onclick="resetPUtil()">Cancel'}</button>
|
||||||
</div>
|
|
||||||
<div class="pwarn ${(i>0)?"bp":""} c" id="p${i}warn">
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="pwarn ${(i>0)?"bp":""} c" id="p${i}warn"></div>
|
||||||
${(i>0)? ('<div class="h">ID ' +i+ '</div>'):""}`;
|
${(i>0)? ('<div class="h">ID ' +i+ '</div>'):""}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function makePUtil()
|
function makePUtil()
|
||||||
{
|
{
|
||||||
gId('putil').innerHTML = `<div class="seg pres"><div class="segin expanded">${makeP(0)}</div></div>`;
|
gId('putil').innerHTML = `<div class="seg pres"><div class="segin expanded">${makeP(0)}</div></div>`;
|
||||||
updateTrail(gId('p0p'));
|
// updateTrail(gId('p0p'));
|
||||||
for (var i=0; i<expanded.length; i++) if (expanded[i]) expand(i);
|
for (var i=0; i<expanded.length; i++) if (expanded[i]) expand(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makePlEntry(p,i) {
|
||||||
|
return `
|
||||||
|
<div class="plentry">
|
||||||
|
${i>0?'<div class="hrz"></div>':''}
|
||||||
|
${i+1}:
|
||||||
|
<select class="btn sel sel-pl" onchange="plePs(${p},${i},this)" data-val="${plJson[p].ps[i]}" data-index="${i}">
|
||||||
|
${plSelContent}
|
||||||
|
</select>
|
||||||
|
<table class="segt">
|
||||||
|
<tr>
|
||||||
|
<td width="35%">Duration (s)</td>
|
||||||
|
<td width="40%">Transition (s)</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input class="noslide segn" type="number" max=6553.0 min=0.2 step=0.1 oninput="pleDur(${p},${i},this)" value="${plJson[p].dur[i]/10.0}"></td>
|
||||||
|
<td><input class="noslide segn" type="number" max=65.0 min=0.0 step=0.1 oninput="pleTr(${p},${i},this)" value="${plJson[p].transition[i]/10.0}"></td>
|
||||||
|
<td><button class="btn btn-i btn-pl-del" onclick="delPl(${p},${i})"><i class="icons btn-icon"></i></button></div></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makePlUtil()
|
||||||
|
{
|
||||||
|
if (pNum < 2) {
|
||||||
|
showToast("You need at least 2 presets to make a playlist!"); //return;
|
||||||
|
}
|
||||||
|
if (plJson[0].transition[0] < 0) plJson[0].transition[0] = tr;
|
||||||
|
gId('putil').innerHTML = `<div class="seg pres"><div class="segin expanded" id="seg100">${makeP(0,true)}</div></div>`;
|
||||||
|
refreshPlE(0);
|
||||||
|
}
|
||||||
|
|
||||||
function resetPUtil()
|
function resetPUtil()
|
||||||
{
|
{
|
||||||
gId('putil').innerHTML = `<button class="btn btn-s btn-i" onclick="makePUtil()"><i class="icons btn-icon"></i>Create preset</button><br>`;
|
var cn = `<button class="btn btn-s btn-i" style="width:226px;" onclick="makePUtil()"><i class="icons btn-icon"></i>New preset</button>`+
|
||||||
|
`<button class="btn btn-i btn-xs" onclick="makePlUtil()"><i class="icons btn-icon"></i></button><br>`;
|
||||||
|
gId('putil').innerHTML = cn;
|
||||||
}
|
}
|
||||||
|
|
||||||
function tglCs(i)
|
function tglCs(i)
|
||||||
@ -1339,8 +1496,10 @@ function setSeg(s)
|
|||||||
{
|
{
|
||||||
var grp = parseInt(gId(`seg${s}grp`).value);
|
var grp = parseInt(gId(`seg${s}grp`).value);
|
||||||
var spc = parseInt(gId(`seg${s}spc`).value);
|
var spc = parseInt(gId(`seg${s}spc`).value);
|
||||||
|
var ofs = parseInt(gId(`seg${s}of` ).value);
|
||||||
obj.seg.grp = grp;
|
obj.seg.grp = grp;
|
||||||
obj.seg.spc = spc;
|
obj.seg.spc = spc;
|
||||||
|
obj.seg.of = ofs;
|
||||||
}
|
}
|
||||||
requestJson(obj, false);
|
requestJson(obj, false);
|
||||||
}
|
}
|
||||||
@ -1417,7 +1576,7 @@ function setPalette(paletteId = null)
|
|||||||
function setBri()
|
function setBri()
|
||||||
{
|
{
|
||||||
var obj = {"bri": parseInt(gId('sliderBri').value)};
|
var obj = {"bri": parseInt(gId('sliderBri').value)};
|
||||||
obj.transition = parseInt(gId('cyctt').value*10);
|
obj.transition = parseInt(gId('tt').value*10);
|
||||||
requestJson(obj, false, noWS);
|
requestJson(obj, false, noWS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1439,18 +1598,6 @@ function setLor(i)
|
|||||||
requestJson(obj, false, noWS);
|
requestJson(obj, false, noWS);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleCY()
|
|
||||||
{
|
|
||||||
var obj = {"pl" : -1};
|
|
||||||
if (gId('cyToggle').checked)
|
|
||||||
{
|
|
||||||
obj = {"pl": 0, "ccnf": {"min": parseInt(gId('cycs').value), "max": parseInt(gId('cyce').value), "time": parseInt(gId('cyct').value*10)}};
|
|
||||||
obj.transition = parseInt(gId('cyctt').value*10);
|
|
||||||
}
|
|
||||||
|
|
||||||
requestJson(obj, false, noWS);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setPreset(i)
|
function setPreset(i)
|
||||||
{
|
{
|
||||||
var obj = {"ps": i};
|
var obj = {"ps": i};
|
||||||
@ -1458,12 +1605,12 @@ function setPreset(i)
|
|||||||
requestJson(obj, false, noWS);
|
requestJson(obj, false, noWS);
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveP(i)
|
function saveP(i,pl)
|
||||||
{
|
{
|
||||||
pI = parseInt(gId(`p${i}id`).value);
|
pI = parseInt(gId(`p${i}id`).value);
|
||||||
if (!pI || pI < 1) pI = (i>0) ? i : getLowestUnusedP();
|
if (!pI || pI < 1) pI = (i>0) ? i : getLowestUnusedP();
|
||||||
pN = gId(`p${i}txt`).value;
|
pN = gId(`p${i}txt`).value;
|
||||||
if (pN == "") pN = "Preset " + pI;
|
if (pN == "") pN = (pl?"Playlist ":"Preset ") + pI;
|
||||||
var obj = {};
|
var obj = {};
|
||||||
if (!gId(`p${i}cstgl`).checked) {
|
if (!gId(`p${i}cstgl`).checked) {
|
||||||
var raw = gId(`p${i}api`).value;
|
var raw = gId(`p${i}api`).value;
|
||||||
@ -1483,10 +1630,16 @@ function saveP(i)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
obj.o = true;
|
obj.o = true;
|
||||||
|
} else {
|
||||||
|
if (pl) {
|
||||||
|
obj.playlist = plJson[i];
|
||||||
|
obj.o = true;
|
||||||
} else {
|
} else {
|
||||||
obj.ib = gId(`p${i}ibtgl`).checked;
|
obj.ib = gId(`p${i}ibtgl`).checked;
|
||||||
obj.sb = gId(`p${i}sbtgl`).checked;
|
obj.sb = gId(`p${i}sbtgl`).checked;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
obj.psave = pI; obj.n = pN;
|
obj.psave = pI; obj.n = pN;
|
||||||
var pQN = gId(`p${i}ql`).value;
|
var pQN = gId(`p${i}ql`).value;
|
||||||
if (pQN.length > 0) obj.ql = pQN;
|
if (pQN.length > 0) obj.ql = pQN;
|
||||||
@ -1508,12 +1661,36 @@ function saveP(i)
|
|||||||
resetPUtil();
|
resetPUtil();
|
||||||
}
|
}
|
||||||
|
|
||||||
function delP(i)
|
function testPl(i,bt) {
|
||||||
{
|
if (bt.dataset.test == 1) {
|
||||||
|
bt.dataset.test = 0;
|
||||||
|
bt.innerHTML = "<i class='icons btn-icon'></i>Test";
|
||||||
|
stopPl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bt.dataset.test = 1;
|
||||||
|
bt.innerHTML = "<i class='icons btn-icon'></i>Stop";
|
||||||
|
var obj = {};
|
||||||
|
obj.playlist = plJson[i];
|
||||||
|
requestJson(obj, false, noWS);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopPl() {
|
||||||
|
requestJson({playlist:{}}, false, noWS)
|
||||||
|
}
|
||||||
|
|
||||||
|
function delP(i) {
|
||||||
|
var bt = gId(`p${i}del`);
|
||||||
|
if (bt.dataset.cnf == 1) {
|
||||||
var obj = {"pdel": i};
|
var obj = {"pdel": i};
|
||||||
requestJson(obj, false, noWS);
|
requestJson(obj, false, noWS);
|
||||||
delete pJson[i];
|
delete pJson[i];
|
||||||
populatePresets();
|
populatePresets();
|
||||||
|
} else {
|
||||||
|
bt.style.color = "#f00";
|
||||||
|
bt.innerHTML = "<i class='icons btn-icon'></i>Confirm delete";
|
||||||
|
bt.dataset.cnf = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectSlot(b)
|
function selectSlot(b)
|
||||||
@ -1615,7 +1792,7 @@ function setColor(sr)
|
|||||||
}
|
}
|
||||||
updateHex();
|
updateHex();
|
||||||
updateRgb();
|
updateRgb();
|
||||||
obj.transition = parseInt(gId('cyctt').value*10);
|
obj.transition = parseInt(gId('tt').value*10);
|
||||||
requestJson(obj, false, noWS);
|
requestJson(obj, false, noWS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1726,24 +1903,66 @@ function clean(c)
|
|||||||
i.dispatchEvent(new Event('input'));
|
i.dispatchEvent(new Event('input'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//make sure "dur" and "transition" are arrays with at least the length of "ps"
|
||||||
|
function formatArr(pl) {
|
||||||
|
var l = pl.ps.length;
|
||||||
|
if (!Array.isArray(pl.dur)) {
|
||||||
|
var v = pl.dur;
|
||||||
|
if (isNaN(v)) v = 100;
|
||||||
|
pl.dur = [v];
|
||||||
|
}
|
||||||
|
var l2 = pl.dur.length;
|
||||||
|
if (l2 < l)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < l - l2; i++)
|
||||||
|
pl.dur.push(pl.dur[l2-1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(pl.transition)) {
|
||||||
|
var v = pl.transition;
|
||||||
|
if (isNaN(v)) v = tr;
|
||||||
|
pl.transition = [v];
|
||||||
|
}
|
||||||
|
var l2 = pl.transition.length;
|
||||||
|
if (l2 < l)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < l - l2; i++)
|
||||||
|
pl.transition.push(pl.transition[l2-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function expand(i,a)
|
function expand(i,a)
|
||||||
{
|
{
|
||||||
var seg = gId('seg' +i);
|
var seg = gId('seg' +i);
|
||||||
if (!a) expanded[i] = !expanded[i];
|
if (!a) expanded[i] = !expanded[i];
|
||||||
seg.style.display = (expanded[i]) ? "block":"none";
|
seg.style.display = (expanded[i]) ? "block":"none";
|
||||||
gId('sege' +i).style.transform = (expanded[i]) ? "rotate(180deg)":"rotate(0deg)";
|
gId('sege' +i).style.transform = (expanded[i]) ? "rotate(180deg)":"rotate(0deg)";
|
||||||
if (i > 100) { //presets
|
if (i < 100) return; //no preset, we are done
|
||||||
|
|
||||||
var p = i-100;
|
var p = i-100;
|
||||||
gId(`p${p}o`).style.background = (expanded[i] || p != currentPreset)?"var(--c-2)":"var(--c-6)";
|
gId(`p${p}o`).style.background = (expanded[i] || p != currentPreset)?"var(--c-2)":"var(--c-6)";
|
||||||
if (seg.innerHTML == "") {
|
if (seg.innerHTML !== "") return;
|
||||||
|
|
||||||
|
if (isPlaylist(p)) {
|
||||||
|
plJson[p] = pJson[p].playlist;
|
||||||
|
//make sure all keys are present in plJson[p]
|
||||||
|
formatArr(plJson[p]);
|
||||||
|
if (isNaN(plJson[p].repeat)) plJson[p].repeat = 0;
|
||||||
|
if (!plJson[p].r) plJson[p].r = false;
|
||||||
|
if (isNaN(plJson[p].end)) plJson[p].end = 0;
|
||||||
|
|
||||||
|
seg.innerHTML = makeP(p,true);
|
||||||
|
refreshPlE(p);
|
||||||
|
} else {
|
||||||
seg.innerHTML = makeP(p);
|
seg.innerHTML = makeP(p);
|
||||||
|
}
|
||||||
|
|
||||||
var papi = papiVal(p);
|
var papi = papiVal(p);
|
||||||
gId(`p${p}api`).value = papi;
|
gId(`p${p}api`).value = papi;
|
||||||
if (papi.indexOf("Please") == 0) gId(`p${p}cstgl`).checked = true;
|
if (papi.indexOf("Please") == 0) gId(`p${p}cstgl`).checked = true;
|
||||||
tglCs(p);
|
tglCs(p);
|
||||||
}
|
|
||||||
seg = seg.parentElement;
|
seg = seg.parentElement;
|
||||||
}
|
|
||||||
if (expanded[i]) seg.scrollIntoView({
|
if (expanded[i]) seg.scrollIntoView({
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
block: 'center',
|
block: 'center',
|
||||||
@ -1782,7 +2001,7 @@ function lock(e)
|
|||||||
if (l.contains('noslide') || hasIroClass(l) || hasIroClass(pl)) return;
|
if (l.contains('noslide') || hasIroClass(l) || hasIroClass(pl)) return;
|
||||||
|
|
||||||
x0 = unify(e).clientX;
|
x0 = unify(e).clientX;
|
||||||
scrollS = d.getElementsByClassName("tabcontent")[iSlide].scrollTop;
|
scrollS = gEBCN("tabcontent")[iSlide].scrollTop;
|
||||||
|
|
||||||
_C.classList.toggle('smooth', !(locked = true));
|
_C.classList.toggle('smooth', !(locked = true));
|
||||||
}
|
}
|
||||||
@ -1798,7 +2017,7 @@ function move(e)
|
|||||||
if((clientX != 0) &&
|
if((clientX != 0) &&
|
||||||
(iSlide > 0 || s < 0) && (iSlide < N - 1 || s > 0) &&
|
(iSlide > 0 || s < 0) && (iSlide < N - 1 || s > 0) &&
|
||||||
f > 0.12 &&
|
f > 0.12 &&
|
||||||
d.getElementsByClassName("tabcontent")[iSlide].scrollTop == scrollS)
|
gEBCN("tabcontent")[iSlide].scrollTop == scrollS)
|
||||||
{
|
{
|
||||||
_C.style.setProperty('--i', iSlide -= s);
|
_C.style.setProperty('--i', iSlide -= s);
|
||||||
f = 1 - f;
|
f = 1 - f;
|
||||||
|
@ -83,7 +83,7 @@ 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 name="MQUSER" maxlength="40"><br>
|
||||||
Password: <input type="password" name="MQPASS" maxlength="40"><br>
|
Password: <input type="password" name="MQPASS" maxlength="64"><br>
|
||||||
Client ID: <input name="MQCID" maxlength="40"><br>
|
Client ID: <input name="MQCID" maxlength="40"><br>
|
||||||
Device Topic: <input name="MD" maxlength="32"><br>
|
Device Topic: <input name="MD" maxlength="32"><br>
|
||||||
Group Topic: <input name="MG" maxlength="32"><br>
|
Group Topic: <input name="MG" maxlength="32"><br>
|
||||||
|
@ -64,11 +64,6 @@ select {
|
|||||||
font-size: medium;
|
font-size: medium;
|
||||||
}
|
}
|
||||||
input[type="checkbox"] {
|
input[type="checkbox"] {
|
||||||
/* Double-sized Checkboxes */
|
|
||||||
-ms-transform: scale(2); /* IE */
|
|
||||||
-moz-transform: scale(2); /* FF */
|
|
||||||
-webkit-transform: scale(2); /* Safari and Chrome */
|
|
||||||
-o-transform: scale(2); /* Opera */
|
|
||||||
transform: scale(2);
|
transform: scale(2);
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ function B(){window.history.back()}function U(){document.getElementById("uf").st
|
|||||||
.bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%}#msg{display:none}
|
.bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%}#msg{display:none}
|
||||||
</style></head><body><h2>WLED Software Update</h2><form method="POST"
|
</style></head><body><h2>WLED Software Update</h2><form method="POST"
|
||||||
action="/update" id="uf" enctype="multipart/form-data" onsubmit="U()">
|
action="/update" id="uf" enctype="multipart/form-data" onsubmit="U()">
|
||||||
Installed version: 0.12.2-bl4<br>Download the latest binary: <a
|
Installed version: 0.13.0-bl0<br>Download the latest binary: <a
|
||||||
href="https://github.com/Aircoookie/WLED/releases" target="_blank"><img
|
href="https://github.com/Aircoookie/WLED/releases" target="_blank"><img
|
||||||
src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square">
|
src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square">
|
||||||
</a><br><input type="file" class="bt" name="update" required><br><input
|
</a><br><input type="file" class="bt" name="update" required><br><input
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Autogenerated from wled00/data/style.css, do not edit!!
|
// Autogenerated from wled00/data/style.css, do not edit!!
|
||||||
const char PAGE_settingsCss[] PROGMEM = R"=====(<style>body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}hr{border-color:#666}button{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;border-radius:24px;display:inline-block;font-size:20px;margin:12px 8px 8px;padding:8px 12px;min-width:48px;cursor:pointer}.toprow{top:0;position:sticky;background-color:#222;z-index:1}.helpB{text-align:left;position:absolute;width:60px}input{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}input[type=text]{font-size:medium}input[type=number]{width:4em;font-size:medium;margin:2px}input[type=number].xxl{width:100px}input[type=number].big{width:85px}input[type=number].med{width:55px}input[type=number].sml{width:40px}select{margin:2px;font-size:medium}input[type=checkbox]{-ms-transform:scale(2);-moz-transform:scale(2);-webkit-transform:scale(2);-o-transform:scale(2);transform:scale(2);margin-right:10px}select{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}td{padding:2px}.d5{width:4.5em!important}#toast{opacity:0;background-color:#444;border-radius:5px;bottom:64px;color:#fff;font-size:17px;padding:16px;pointer-events:none;position:fixed;text-align:center;z-index:5;transform:translateX(-50%%);max-width:90%%;left:50%%}#toast.show{opacity:1;background-color:#264;animation:fadein .5s,fadein .5s 2.5s reverse}#toast.error{opacity:1;background-color:#b21;animation:fadein .5s}</style>)=====";
|
const char PAGE_settingsCss[] PROGMEM = R"=====(<style>body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}hr{border-color:#666}button{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;border-radius:24px;display:inline-block;font-size:20px;margin:12px 8px 8px;padding:8px 12px;min-width:48px;cursor:pointer}.toprow{top:0;position:sticky;background-color:#222;z-index:1}.helpB{text-align:left;position:absolute;width:60px}input{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}input[type=text]{font-size:medium}input[type=number]{width:4em;font-size:medium;margin:2px}input[type=number].xxl{width:100px}input[type=number].big{width:85px}input[type=number].med{width:55px}input[type=number].sml{width:40px}select{margin:2px;font-size:medium}input[type=checkbox]{transform:scale(2);margin-right:10px}select{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}td{padding:2px}.d5{width:4.5em!important}#toast{opacity:0;background-color:#444;border-radius:5px;bottom:64px;color:#fff;font-size:17px;padding:16px;pointer-events:none;position:fixed;text-align:center;z-index:5;transform:translateX(-50%%);max-width:90%%;left:50%%}#toast.show{opacity:1;background-color:#264;animation:fadein .5s,fadein .5s 2.5s reverse}#toast.error{opacity:1;background-color:#b21;animation:fadein .5s}</style>)=====";
|
||||||
|
|
||||||
|
|
||||||
// Autogenerated from wled00/data/settings.htm, do not edit!!
|
// Autogenerated from wled00/data/settings.htm, do not edit!!
|
||||||
@ -289,7 +289,7 @@ 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"
|
name="MQUSER" maxlength="40"><br>Password: <input type="password" name="MQPASS"
|
||||||
maxlength="40"><br>Client ID: <input name="MQCID" maxlength="40"><br>
|
maxlength="64"><br>Client ID: <input name="MQCID" maxlength="40"><br>
|
||||||
Device Topic: <input name="MD" maxlength="32"><br>Group Topic: <input name="MG"
|
Device Topic: <input name="MD" maxlength="32"><br>Group Topic: <input name="MG"
|
||||||
maxlength="32"><br><i>Reboot required to apply changes. </i><a
|
maxlength="32"><br><i>Reboot required to apply changes. </i><a
|
||||||
href="https://github.com/Aircoookie/WLED/wiki/MQTT" target="_blank">MQTT info
|
href="https://github.com/Aircoookie/WLED/wiki/MQTT" target="_blank">MQTT info
|
||||||
@ -394,7 +394,7 @@ HTTP traffic is unencrypted. An attacker in the same network can intercept form
|
|||||||
<h3>Software Update</h3><button type="button" onclick="U()">Manual OTA Update
|
<h3>Software Update</h3><button type="button" onclick="U()">Manual OTA Update
|
||||||
</button><br>Enable ArduinoOTA: <input type="checkbox" name="AO"><br><h3>About
|
</button><br>Enable ArduinoOTA: <input type="checkbox" name="AO"><br><h3>About
|
||||||
</h3><a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a>
|
</h3><a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a>
|
||||||
version 0.12.2-bl4<br><br><a
|
version 0.13.0-bl0<br><br><a
|
||||||
href="https://github.com/Aircoookie/WLED/wiki/Contributors-and-credits"
|
href="https://github.com/Aircoookie/WLED/wiki/Contributors-and-credits"
|
||||||
target="_blank">Contributors, dependencies and special thanks</a><br>
|
target="_blank">Contributors, dependencies and special thanks</a><br>
|
||||||
A huge thank you to everyone who helped me create WLED!<br><br>
|
A huge thank you to everyone who helped me create WLED!<br><br>
|
||||||
|
4331
wled00/html_ui.h
4331
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -45,6 +45,8 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
uint16_t grp = elem[F("grp")] | seg.grouping;
|
uint16_t grp = elem[F("grp")] | seg.grouping;
|
||||||
uint16_t spc = elem[F("spc")] | seg.spacing;
|
uint16_t spc = elem[F("spc")] | seg.spacing;
|
||||||
strip.setSegment(id, start, stop, grp, spc);
|
strip.setSegment(id, start, stop, grp, spc);
|
||||||
|
seg.offset = elem[F("of")] | seg.offset;
|
||||||
|
if (stop > start && seg.offset > stop - start -1) seg.offset = stop - start -1;
|
||||||
|
|
||||||
int segbri = elem["bri"] | -1;
|
int segbri = elem["bri"] | -1;
|
||||||
if (segbri == 0) {
|
if (segbri == 0) {
|
||||||
@ -228,18 +230,9 @@ bool deserializeState(JsonObject root, 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();
|
||||||
|
|
||||||
int cy = root[F("pl")] | -2;
|
|
||||||
if (cy > -2) presetCyclingEnabled = (cy >= 0);
|
|
||||||
JsonObject ccnf = root["ccnf"];
|
|
||||||
presetCycleMin = ccnf["min"] | presetCycleMin;
|
|
||||||
presetCycleMax = ccnf[F("max")] | presetCycleMax;
|
|
||||||
tr = ccnf[F("time")] | -1;
|
|
||||||
if (tr >= 2) presetCycleTime = tr;
|
|
||||||
|
|
||||||
JsonObject nl = root["nl"];
|
JsonObject nl = root["nl"];
|
||||||
nightlightActive = nl["on"] | nightlightActive;
|
nightlightActive = nl["on"] | nightlightActive;
|
||||||
nightlightDelayMins = nl["dur"] | nightlightDelayMins;
|
nightlightDelayMins = nl[F("dur")] | nightlightDelayMins;
|
||||||
nightlightMode = nl[F("fade")] | nightlightMode; //deprecated, remove for v0.13.0
|
|
||||||
nightlightMode = nl[F("mode")] | nightlightMode;
|
nightlightMode = nl[F("mode")] | nightlightMode;
|
||||||
nightlightTargetBri = nl[F("tbri")] | nightlightTargetBri;
|
nightlightTargetBri = nl[F("tbri")] | nightlightTargetBri;
|
||||||
|
|
||||||
@ -361,6 +354,7 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
|
|||||||
if (!forPreset) root[F("len")] = seg.stop - seg.start;
|
if (!forPreset) root[F("len")] = seg.stop - seg.start;
|
||||||
root[F("grp")] = seg.grouping;
|
root[F("grp")] = seg.grouping;
|
||||||
root[F("spc")] = seg.spacing;
|
root[F("spc")] = seg.spacing;
|
||||||
|
root[F("of")] = seg.offset;
|
||||||
root["on"] = seg.getOption(SEG_OPTION_ON);
|
root["on"] = seg.getOption(SEG_OPTION_ON);
|
||||||
byte segbri = seg.opacity;
|
byte segbri = seg.opacity;
|
||||||
root["bri"] = (segbri) ? segbri : 255;
|
root["bri"] = (segbri) ? segbri : 255;
|
||||||
@ -409,20 +403,13 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
|||||||
if (errorFlag) root[F("error")] = errorFlag;
|
if (errorFlag) root[F("error")] = errorFlag;
|
||||||
|
|
||||||
root[F("ps")] = currentPreset;
|
root[F("ps")] = currentPreset;
|
||||||
root[F("pl")] = (presetCyclingEnabled) ? 0: -1;
|
root[F("pl")] = currentPlaylist;
|
||||||
|
|
||||||
usermods.addToJsonState(root);
|
usermods.addToJsonState(root);
|
||||||
|
|
||||||
//temporary for preset cycle
|
|
||||||
JsonObject ccnf = root.createNestedObject("ccnf");
|
|
||||||
ccnf["min"] = presetCycleMin;
|
|
||||||
ccnf[F("max")] = presetCycleMax;
|
|
||||||
ccnf[F("time")] = presetCycleTime;
|
|
||||||
|
|
||||||
JsonObject nl = root.createNestedObject("nl");
|
JsonObject nl = root.createNestedObject("nl");
|
||||||
nl["on"] = nightlightActive;
|
nl["on"] = nightlightActive;
|
||||||
nl["dur"] = nightlightDelayMins;
|
nl[F("dur")] = nightlightDelayMins;
|
||||||
nl[F("fade")] = (nightlightMode > NL_MODE_SET); //deprecated
|
|
||||||
nl[F("mode")] = nightlightMode;
|
nl[F("mode")] = nightlightMode;
|
||||||
nl[F("tbri")] = nightlightTargetBri;
|
nl[F("tbri")] = nightlightTargetBri;
|
||||||
if (nightlightActive) {
|
if (nightlightActive) {
|
||||||
|
@ -300,19 +300,6 @@ void handleNightlight()
|
|||||||
}
|
}
|
||||||
nightlightActiveOld = false;
|
nightlightActiveOld = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//also handle preset cycle here
|
|
||||||
if (presetCyclingEnabled && (millis() - presetCycledTime > (100*presetCycleTime)))
|
|
||||||
{
|
|
||||||
presetCycledTime = millis();
|
|
||||||
if (bri == 0 || nightlightActive) return;
|
|
||||||
|
|
||||||
if (presetCycCurr < presetCycleMin || presetCycCurr > presetCycleMax) presetCycCurr = presetCycleMin;
|
|
||||||
applyPreset(presetCycCurr); //this handles colorUpdated() for us
|
|
||||||
presetCycCurr++;
|
|
||||||
if (presetCycCurr > 250) presetCycCurr = 1;
|
|
||||||
interfaceUpdateCallMode = 0; //disable updates to MQTT and Blynk
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//utility for FastLED to use our custom timer
|
//utility for FastLED to use our custom timer
|
||||||
|
@ -117,7 +117,7 @@ void loadPlaylist(JsonObject playlistObj, byte presetId) {
|
|||||||
|
|
||||||
|
|
||||||
void handlePlaylist() {
|
void handlePlaylist() {
|
||||||
if (currentPlaylist < 0 || playlistEntries == nullptr || presetCyclingEnabled) return;
|
if (currentPlaylist < 0 || playlistEntries == nullptr) return;
|
||||||
|
|
||||||
if (millis() - presetCycledTime > (100*playlistEntryDur)) {
|
if (millis() - presetCycledTime > (100*playlistEntryDur)) {
|
||||||
presetCycledTime = millis();
|
presetCycledTime = millis();
|
||||||
|
@ -163,7 +163,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
|
|
||||||
briS = request->arg(F("CA")).toInt();
|
briS = request->arg(F("CA")).toInt();
|
||||||
|
|
||||||
saveCurrPresetCycConf = request->hasArg(F("PC"));
|
|
||||||
turnOnAtBoot = request->hasArg(F("BO"));
|
turnOnAtBoot = request->hasArg(F("BO"));
|
||||||
t = request->arg(F("BP")).toInt();
|
t = request->arg(F("BP")).toInt();
|
||||||
if (t <= 250) bootPreset = t;
|
if (t <= 250) bootPreset = t;
|
||||||
@ -255,7 +254,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
t = request->arg(F("MQPORT")).toInt();
|
t = request->arg(F("MQPORT")).toInt();
|
||||||
if (t > 0) mqttPort = t;
|
if (t > 0) mqttPort = t;
|
||||||
strlcpy(mqttUser, request->arg(F("MQUSER")).c_str(), 41);
|
strlcpy(mqttUser, request->arg(F("MQUSER")).c_str(), 41);
|
||||||
if (!isAsterisksOnly(request->arg(F("MQPASS")).c_str(), 41)) strlcpy(mqttPass, request->arg(F("MQPASS")).c_str(), 41);
|
if (!isAsterisksOnly(request->arg(F("MQPASS")).c_str(), 41)) strlcpy(mqttPass, request->arg(F("MQPASS")).c_str(), 65);
|
||||||
strlcpy(mqttClientID, request->arg(F("MQCID")).c_str(), 41);
|
strlcpy(mqttClientID, request->arg(F("MQCID")).c_str(), 41);
|
||||||
strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), 33);
|
strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), 33);
|
||||||
strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), 33);
|
strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), 33);
|
||||||
@ -610,36 +609,12 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
}
|
}
|
||||||
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI);
|
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI);
|
||||||
|
|
||||||
//set presets
|
|
||||||
pos = req.indexOf(F("P1=")); //sets first preset for cycle
|
|
||||||
if (pos > 0) presetCycleMin = getNumVal(&req, pos);
|
|
||||||
|
|
||||||
pos = req.indexOf(F("P2=")); //sets last preset for cycle
|
|
||||||
if (pos > 0) presetCycleMax = getNumVal(&req, pos);
|
|
||||||
|
|
||||||
//preset cycle
|
|
||||||
pos = req.indexOf(F("CY="));
|
|
||||||
if (pos > 0)
|
|
||||||
{
|
|
||||||
char cmd = req.charAt(pos+3);
|
|
||||||
if (cmd == '2') presetCyclingEnabled = !presetCyclingEnabled;
|
|
||||||
else presetCyclingEnabled = (cmd != '0');
|
|
||||||
presetCycCurr = presetCycleMin;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = req.indexOf(F("PT=")); //sets cycle time in ms
|
|
||||||
if (pos > 0) {
|
|
||||||
int v = getNumVal(&req, pos);
|
|
||||||
if (v > 100) presetCycleTime = v/100;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = req.indexOf(F("PS=")); //saves current in preset
|
pos = req.indexOf(F("PS=")); //saves current in preset
|
||||||
if (pos > 0) savePreset(getNumVal(&req, pos));
|
if (pos > 0) savePreset(getNumVal(&req, pos));
|
||||||
|
|
||||||
//apply preset
|
//apply preset
|
||||||
if (updateVal(&req, "PL=", &presetCycCurr, presetCycleMin, presetCycleMax)) {
|
pos = req.indexOf(F("PL="));
|
||||||
applyPreset(presetCycCurr);
|
if (pos > 0) applyPreset(getNumVal(&req, pos));
|
||||||
}
|
|
||||||
|
|
||||||
//set brightness
|
//set brightness
|
||||||
updateVal(&req, "&A=", &bri);
|
updateVal(&req, "&A=", &bri);
|
||||||
@ -732,11 +707,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//set effect parameters
|
//set effect parameters
|
||||||
if (updateVal(&req, "FX=", &effectCurrent, 0, strip.getModeCount()-1)) {
|
if (updateVal(&req, "FX=", &effectCurrent, 0, strip.getModeCount()-1)) unloadPlaylist();
|
||||||
presetCyclingEnabled = false;
|
|
||||||
// it may be a good idea to also stop playlist if effect has changed
|
|
||||||
unloadPlaylist();
|
|
||||||
}
|
|
||||||
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);
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
/*
|
/*
|
||||||
Main sketch, global variable declarations
|
Main sketch, global variable declarations
|
||||||
@title WLED project sketch
|
@title WLED project sketch
|
||||||
@version 0.12.2-bl3
|
@version 0.13.0-bl0
|
||||||
@author Christian Schwinne
|
@author Christian Schwinne
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// version code in format yymmddb (b = daily build)
|
// version code in format yymmddb (b = daily build)
|
||||||
#define VERSION 2106281
|
#define VERSION 2107010
|
||||||
|
|
||||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||||
//#define WLED_USE_MY_CONFIG
|
//#define WLED_USE_MY_CONFIG
|
||||||
@ -200,14 +200,13 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
|
|||||||
|
|
||||||
// Global Variable definitions
|
// Global Variable definitions
|
||||||
WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION));
|
WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION));
|
||||||
#define WLED_CODENAME "Ryujin"
|
#define WLED_CODENAME "Toki"
|
||||||
|
|
||||||
// AP and OTA default passwords (for maximum security change them!)
|
// AP and OTA default passwords (for maximum security change them!)
|
||||||
WLED_GLOBAL char apPass[65] _INIT(DEFAULT_AP_PASS);
|
WLED_GLOBAL char apPass[65] _INIT(DEFAULT_AP_PASS);
|
||||||
WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS);
|
WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS);
|
||||||
|
|
||||||
// Hardware CONFIG (only changeble HERE, not at runtime)
|
// Hardware and pin config
|
||||||
// LED strip pin, button pin and IR pin changeable in NpbWrapper.h!
|
|
||||||
#ifndef BTNPIN
|
#ifndef BTNPIN
|
||||||
WLED_GLOBAL int8_t btnPin[WLED_MAX_BUTTONS] _INIT({0});
|
WLED_GLOBAL int8_t btnPin[WLED_MAX_BUTTONS] _INIT({0});
|
||||||
#else
|
#else
|
||||||
@ -335,7 +334,7 @@ WLED_GLOBAL char mqttDeviceTopic[33] _INIT(""); // main MQTT topic (i
|
|||||||
WLED_GLOBAL char mqttGroupTopic[33] _INIT("wled/all"); // second MQTT topic (for example to group devices)
|
WLED_GLOBAL char mqttGroupTopic[33] _INIT("wled/all"); // second MQTT topic (for example to group devices)
|
||||||
WLED_GLOBAL char mqttServer[33] _INIT(""); // both domains and IPs should work (no SSL)
|
WLED_GLOBAL char mqttServer[33] _INIT(""); // both domains and IPs should work (no SSL)
|
||||||
WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth
|
WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth
|
||||||
WLED_GLOBAL char mqttPass[41] _INIT(""); // optional: password for MQTT auth
|
WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth
|
||||||
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID
|
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID
|
||||||
WLED_GLOBAL uint16_t mqttPort _INIT(1883);
|
WLED_GLOBAL uint16_t mqttPort _INIT(1883);
|
||||||
|
|
||||||
@ -497,14 +496,8 @@ WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, 25
|
|||||||
// blynk
|
// blynk
|
||||||
WLED_GLOBAL bool blynkEnabled _INIT(false);
|
WLED_GLOBAL bool blynkEnabled _INIT(false);
|
||||||
|
|
||||||
// preset cycling
|
//playlists
|
||||||
WLED_GLOBAL bool presetCyclingEnabled _INIT(false);
|
|
||||||
WLED_GLOBAL byte presetCycleMin _INIT(1), presetCycleMax _INIT(5);
|
|
||||||
WLED_GLOBAL uint16_t presetCycleTime _INIT(12);
|
|
||||||
WLED_GLOBAL unsigned long presetCycledTime _INIT(0);
|
WLED_GLOBAL unsigned long presetCycledTime _INIT(0);
|
||||||
WLED_GLOBAL byte presetCycCurr _INIT(presetCycleMin);
|
|
||||||
WLED_GLOBAL bool saveCurrPresetCycConf _INIT(false);
|
|
||||||
|
|
||||||
WLED_GLOBAL int16_t currentPlaylist _INIT(0);
|
WLED_GLOBAL int16_t currentPlaylist _INIT(0);
|
||||||
|
|
||||||
// realtime
|
// realtime
|
||||||
|
@ -323,18 +323,6 @@ void loadSettingsFromEEPROM()
|
|||||||
strip.rgbwMode = EEPROM.read(2203);
|
strip.rgbwMode = EEPROM.read(2203);
|
||||||
//skipFirstLed = EEPROM.read(2204);
|
//skipFirstLed = EEPROM.read(2204);
|
||||||
|
|
||||||
if (EEPROM.read(2210) || EEPROM.read(2211) || EEPROM.read(2212))
|
|
||||||
{
|
|
||||||
presetCyclingEnabled = EEPROM.read(2205);
|
|
||||||
presetCycleTime = EEPROM.read(2206) + ((EEPROM.read(2207) << 8) & 0xFF00);
|
|
||||||
if (lastEEPROMversion < 21) presetCycleTime /= 100; //was stored in ms, now is in tenths of a second
|
|
||||||
presetCycleMin = EEPROM.read(2208);
|
|
||||||
presetCycleMax = EEPROM.read(2209);
|
|
||||||
//was presetApplyBri = EEPROM.read(2210);
|
|
||||||
//was presetApplyCol = EEPROM.read(2211);
|
|
||||||
//was presetApplyFx = EEPROM.read(2212);
|
|
||||||
}
|
|
||||||
|
|
||||||
bootPreset = EEPROM.read(389);
|
bootPreset = EEPROM.read(389);
|
||||||
wifiLock = EEPROM.read(393);
|
wifiLock = EEPROM.read(393);
|
||||||
utcOffsetSecs = EEPROM.read(394) + ((EEPROM.read(395) << 8) & 0xFF00);
|
utcOffsetSecs = EEPROM.read(394) + ((EEPROM.read(395) << 8) & 0xFF00);
|
||||||
|
@ -62,7 +62,7 @@ void XML_response(AsyncWebServerRequest *request, char* dest)
|
|||||||
oappend(SET_F("</ws><ps>"));
|
oappend(SET_F("</ws><ps>"));
|
||||||
oappendi((currentPreset < 1) ? 0:currentPreset);
|
oappendi((currentPreset < 1) ? 0:currentPreset);
|
||||||
oappend(SET_F("</ps><cy>"));
|
oappend(SET_F("</ps><cy>"));
|
||||||
oappendi(presetCyclingEnabled);
|
oappendi(currentPlaylist > 0);
|
||||||
oappend(SET_F("</cy><ds>"));
|
oappend(SET_F("</cy><ds>"));
|
||||||
oappend(serverDescription);
|
oappend(serverDescription);
|
||||||
if (realtimeMode)
|
if (realtimeMode)
|
||||||
|
Loading…
Reference in New Issue
Block a user