Merge branch 'dev' into sensor-info

This commit is contained in:
Blaz Kristan 2022-01-09 22:00:09 +01:00
commit 35779dad8b
30 changed files with 4542 additions and 4051 deletions

View File

@ -187,6 +187,7 @@ build_flags =
-DFP_IN_IROM -DFP_IN_IROM
;-Wno-deprecated-declarations ;-Wno-deprecated-declarations
;-Wno-register ;-Wno-register
-Wno-misleading-indentation
; NONOSDK22x_190703 = 2.2.2-dev(38a443e) ; NONOSDK22x_190703 = 2.2.2-dev(38a443e)
-DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703 -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
; lwIP 2 - Higher Bandwidth no Features ; lwIP 2 - Higher Bandwidth no Features

View File

@ -111,17 +111,17 @@ class Animated_Staircase : public Usermod {
} }
if (i >= onIndex && i < offIndex) { if (i >= onIndex && i < offIndex) {
segments->setOption(SEG_OPTION_ON, 1, 1); segments->setOption(SEG_OPTION_ON, 1, i);
// We may need to copy mode and colors from segment 0 to make sure // We may need to copy mode and colors from segment 0 to make sure
// changes are propagated even when the config is changed during a wipe // changes are propagated even when the config is changed during a wipe
// segments->mode = mainsegment.mode; // segments->mode = mainsegment.mode;
// segments->colors[0] = mainsegment.colors[0]; // segments->colors[0] = mainsegment.colors[0];
} else { } else {
segments->setOption(SEG_OPTION_ON, 0, 1); segments->setOption(SEG_OPTION_ON, 0, i);
} }
// Always mark segments as "transitional", we are animating the staircase // Always mark segments as "transitional", we are animating the staircase
segments->setOption(SEG_OPTION_TRANSITIONAL, 1, 1); segments->setOption(SEG_OPTION_TRANSITIONAL, 1, i);
} }
colorUpdated(CALL_MODE_DIRECT_CHANGE); colorUpdated(CALL_MODE_DIRECT_CHANGE);
} }
@ -296,7 +296,7 @@ class Animated_Staircase : public Usermod {
maxSegmentId = i - 1; maxSegmentId = i - 1;
break; break;
} }
segments->setOption(SEG_OPTION_ON, 1, 1); segments->setOption(SEG_OPTION_ON, 1, i);
} }
colorUpdated(CALL_MODE_DIRECT_CHANGE); colorUpdated(CALL_MODE_DIRECT_CHANGE);
DEBUG_PRINTLN(F("Animated Staircase disabled.")); DEBUG_PRINTLN(F("Animated Staircase disabled."));

View File

@ -58,7 +58,6 @@ private:
byte prevPreset = 0; byte prevPreset = 0;
byte prevPlaylist = 0; byte prevPlaylist = 0;
bool savedState = false;
uint32_t offTimerStart = 0; // off timer start time uint32_t offTimerStart = 0; // off timer start time
byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // notification mode for colorUpdated(): CALL_MODE_NO_NOTIFY or CALL_MODE_DIRECT_CHANGE byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // notification mode for colorUpdated(): CALL_MODE_NO_NOTIFY or CALL_MODE_DIRECT_CHANGE
@ -77,6 +76,7 @@ private:
bool m_mqttOnly = false; // flag to send MQTT message only (assuming it is enabled) bool m_mqttOnly = false; // flag to send MQTT message only (assuming it is enabled)
// flag to enable triggering only if WLED is initially off (LEDs are not on, preventing running effect being overwritten by PIR) // flag to enable triggering only if WLED is initially off (LEDs are not on, preventing running effect being overwritten by PIR)
bool m_offOnly = false; bool m_offOnly = false;
bool m_offMode = offMode;
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
static const char _name[]; static const char _name[];
@ -123,13 +123,15 @@ private:
PIRtriggered = switchOn; PIRtriggered = switchOn;
if (switchOn) { if (switchOn) {
if (m_onPreset) { if (m_onPreset) {
if (currentPlaylist>0) prevPlaylist = currentPlaylist; if (currentPlaylist>0 && !offMode) {
else if (currentPreset>0) prevPreset = currentPreset; prevPlaylist = currentPlaylist;
else { unloadPlaylist();
} else if (currentPreset>0 && !offMode) {
prevPreset = currentPreset;
} else {
saveTemporaryPreset(); saveTemporaryPreset();
savedState = true;
prevPlaylist = 0; prevPlaylist = 0;
prevPreset = 0; prevPreset = 255;
} }
applyPreset(m_onPreset, NotifyUpdateMode); applyPreset(m_onPreset, NotifyUpdateMode);
return; return;
@ -148,13 +150,10 @@ private:
prevPlaylist = 0; prevPlaylist = 0;
return; return;
} else if (prevPreset) { } else if (prevPreset) {
applyPreset(prevPreset, NotifyUpdateMode); if (prevPreset<255) applyPreset(prevPreset, NotifyUpdateMode);
else applyTemporaryPreset();
prevPreset = 0; prevPreset = 0;
return; return;
} else if (savedState) {
applyTemporaryPreset();
savedState = false;
return;
} }
// preset not assigned // preset not assigned
if (bri != 0) { if (bri != 0) {

View File

@ -185,6 +185,7 @@ class UsermodTemperature : public Usermod {
// we were waiting for a conversion to complete, have we waited log enough? // we were waiting for a conversion to complete, have we waited log enough?
if (now - lastTemperaturesRequest >= 750 /* 93.75ms per the datasheet but can be up to 750ms */) { if (now - lastTemperaturesRequest >= 750 /* 93.75ms per the datasheet but can be up to 750ms */) {
readTemperature(); readTemperature();
if (getTemperatureC() < -100.0f) lastMeasurement = now - readingInterval + 300; // force new measurement in 300ms
if (WLED_MQTT_CONNECTED) { if (WLED_MQTT_CONNECTED) {
char subuf[64]; char subuf[64];

View File

@ -65,7 +65,8 @@ private:
{ 1, 0, 1, 1, 1, 1, 1 }, // 6 { 1, 0, 1, 1, 1, 1, 1 }, // 6
{ 1, 1, 1, 0, 0, 0, 0 }, // 7 { 1, 1, 1, 0, 0, 0, 0 }, // 7
{ 1, 1, 1, 1, 1, 1, 1 }, // 8 { 1, 1, 1, 1, 1, 1, 1 }, // 8
{ 1, 1, 1, 1, 0, 1, 1 } // 9 { 1, 1, 1, 1, 0, 1, 1 }, // 9
{ 0, 0, 0, 0, 0, 0, 0 } // blank
}; };
//String to reduce flash memory usage //String to reduce flash memory usage
@ -100,39 +101,39 @@ private:
switch (umSSDRDisplayMask[index]) { switch (umSSDRDisplayMask[index]) {
case 'h': case 'h':
timeVar = hourFormat12(localTime); timeVar = hourFormat12(localTime);
_showElements(&umSSDRHours, timeVar, 0); _showElements(&umSSDRHours, timeVar, 0, 1);
break; break;
case 'H': case 'H':
timeVar = hour(localTime); timeVar = hour(localTime);
_showElements(&umSSDRHours, timeVar, 0); _showElements(&umSSDRHours, timeVar, 0, 1);
break; break;
case 'k': case 'k':
timeVar = hour(localTime) + 1; timeVar = hour(localTime) + 1;
_showElements(&umSSDRHours, timeVar, 0); _showElements(&umSSDRHours, timeVar, 0, 0);
break; break;
case 'm': case 'm':
timeVar = minute(localTime); timeVar = minute(localTime);
_showElements(&umSSDRMinutes, timeVar, 0); _showElements(&umSSDRMinutes, timeVar, 0, 0);
break; break;
case 's': case 's':
timeVar = second(localTime); timeVar = second(localTime);
_showElements(&umSSDRSeconds, timeVar, 0); _showElements(&umSSDRSeconds, timeVar, 0, 0);
break; break;
case 'd': case 'd':
timeVar = day(localTime); timeVar = day(localTime);
_showElements(&umSSDRDays, timeVar, 0); _showElements(&umSSDRDays, timeVar, 0, 0);
break; break;
case 'M': case 'M':
timeVar = month(localTime); timeVar = month(localTime);
_showElements(&umSSDRMonths, timeVar, 0); _showElements(&umSSDRMonths, timeVar, 0, 0);
break; break;
case 'y': case 'y':
timeVar = second(localTime); timeVar = second(localTime);
_showElements(&umSSDRYears, timeVar, 0); _showElements(&umSSDRYears, timeVar, 0, 0);
break; break;
case 'Y': case 'Y':
timeVar = year(localTime); timeVar = year(localTime);
_showElements(&umSSDRYears, timeVar, 0); _showElements(&umSSDRYears, timeVar, 0, 0);
break; break;
case ':': case ':':
if (!colonsDone) { // only call _setColons once as all colons are printed when the first colon is found if (!colonsDone) { // only call _setColons once as all colons are printed when the first colon is found
@ -148,14 +149,16 @@ private:
void _setColons() { void _setColons() {
if ( umSSDRColonblink ) { if ( umSSDRColonblink ) {
if ( second(localTime) % 2 == 0 ) { if ( second(localTime) % 2 == 0 ) {
_showElements(&umSSDRColons, 0, 1); _showElements(&umSSDRColons, 0, 1, 0);
} }
} else { } else {
_showElements(&umSSDRColons, 0, 1); _showElements(&umSSDRColons, 0, 1, 0);
} }
} }
void _showElements(String *map, int timevar, bool isColon) { void _showElements(String *map, int timevar, bool isColon, bool removeZero
) {
if (!(*map).equals("") && !(*map) == NULL) { if (!(*map).equals("") && !(*map) == NULL) {
int length = String(timevar).length(); int length = String(timevar).length();
bool addZero = false; bool addZero = false;
@ -165,8 +168,16 @@ private:
} }
int timeArr[length]; int timeArr[length];
if(addZero) { if(addZero) {
timeArr[1] = 0; if(removeZero)
timeArr[0] = timevar; {
timeArr[1] = 10;
timeArr[0] = timevar;
}
else
{
timeArr[1] = 0;
timeArr[0] = timevar;
}
} else { } else {
int count = 0; int count = 0;
while (timevar) { while (timevar) {

View File

@ -0,0 +1,398 @@
#pragma once
//WLED custom fonts, curtesy of @Benji (https://github.com/Proto-molecule)
/*
Fontname: wled_logo_akemi_4x4
Copyright:
Glyphs: 3/3
BBX Build Mode: 3
* this logo ...WLED/images/wled_logo_akemi.png
* encode map = 1, 2, 3
*/
const uint8_t u8x8_wled_logo_akemi_4x4[388] U8X8_FONT_SECTION("u8x8_wled_logo_akemi_4x4") =
"\1\3\4\4\0\0\0\0\0\0\0\0\0\340\360\10\350\10\350\210\270\210\350\210\270\350\10\360\340\0\0\0"
"\0\0\200\200\0\0@\340\300\340@\0\0\377\377\377\377\377\377\37\37\207\207\371\371\371\377\377\377\0\0\374"
"\374\7\7\371\0\0\6\4\15\34x\340\200\177\177\377\351yy\376\356\357\217\177\177\177o\377\377\0\70\77"
"\277\376~\71\0\0\0\0\0\0\0\1\3\3\3\1\0\0\37\77\353\365\77\37\0\0\0\0\5\7\2\3"
"\7\4\0\0\300\300\300\300\200\200\200\0\0\0\0\0\0\0\200\200\300\300\300\300\200\200\0\0\0\0\0\0"
"\0\200\200\300\371\37\37\371\371\7\7\377\374\0\0\0\374\377\377\37\37\341\341\377\377\377\377\374\0\0\0\374"
"\377\7\7\231\371\376>\371\371>~\377\277\70\0\270\377\177\77\376\376\71\371\371\71\177\377\277\70\0\70\377"
"\177>\376\371\377\377\0\77\77\0\0\4\7\2\7\5\0\0\0\377\377\0\77\77\0\0\0\5\7\2\7\5"
"\0\0\377\377\300\300\300\200\200\0\0\0\0\0\0\0\200\200\300\300\300\300\300\200\200\0\0\0\0\0\0\0"
"\0\0\0\0\231\231\231\371\377\377\374\0\0\0\374\377\347\347\371\1\1\371\371\7\7\377\374\0\0\0@\340"
"\300\340@\0\71\371\371\71\177\377\277\70\0\70\277\377\177\71\371\370\70\371\371~\376\377\77\70\200\340x\34"
"\15\4\6\0\0\77\77\0\0\0\5\7\2\7\5\0\0\0\377\377\0\77\77\0\0\1\3\3\1\1\0\0"
"\0\0\0";
/*
Fontname: wled_logo_akemi_5x5
Copyright: Created with Fony 1.4.7
Glyphs: 3/3
BBX Build Mode: 3
* this logo ...WLED/images/wled_logo_akemi.png
* encoded = 1, 2, 3
*/
/*
const uint8_t u8x8_wled_logo_akemi_5x5[604] U8X8_FONT_SECTION("u8x8_wled_logo_akemi_5x5") =
"\1\3\5\5\0\0\0\0\0\0\0\0\0\0\0\0\340\340\374\14\354\14\354\14|\14\354\14||\14\354"
"\14\374\340\340\0\0\0\0\0\0\0\200\0\0\0\200\200\0\200\200\0\0\0\0\377\377\377\376\377\376\377\377"
"\377\377\77\77\307\307\307\307\306\377\377\377\0\0\0\360\374>\77\307\0\0\61cg\357\347\303\301\200\0\0"
"\377\377\377\317\317\317\317\360\360\360\374\374\377\377\377\377\377\377\377\377\0\0\200\377\377\340\340\37\0\0\0\0"
"\0\0\1\3\17\77\374\360\357\357\177\36\14\17\357\377\376\376>\376\360\357\17\17\14>\177o\340\300\343c"
"{\77\17\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\17\37\37\362\375\37\37\17\0\0"
"\0\0\1\1\1\0\1\1\1\0\0\0\200\300\300\300\300\200\200\0\0\0\0\0\0\0\0\0\0\0\200\200"
"\300\300\300\300\200\200\0\0\0\0\0\0\0\0\0\0\0\0\200\200\307\307\377\377\307\307\307\77>\374\360\0"
"\0\0\360\374\376\377\377\377\7\7\7\377\377\377\377\376\374\360\0\0\0\0\360\374\36\37\37\343\37\37\340\340"
"\37\37\37\340\340\377\377\200\0\200\377\377\377\340\340\340\37\37\37\37\37\37\37\377\377\377\200\0\0\200\377\377"
"\340\340\340\34\377\377\3\3\377\377\3\17\77{\343\303\300\303\343s\77\37\3\377\377\3\3\377\377\3\17\77"
"{\343\303\300\300\343{\37\17\3\377\377\377\377\0\0\37\37\0\0\1\1\1\1\0\1\1\1\1\0\0\377"
"\377\0\0\37\37\0\0\1\1\1\1\0\0\1\1\1\0\0\377\377\300\300\300\200\200\0\0\0\0\0\0\0"
"\0\0\0\0\200\200\300\300\300\300\200\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\343\343\343\343"
"\343\377\376\374\360\0\0\0\360\374\376\77\77\307\307\7\7\307\307\307\77>\374\360\0\0\0\0\0\200\200\0"
"\200\200\0\0\34\34\34\37\37\377\377\377\377\200\0\200\377\377\377\377\37\37\37\0\0\37\37\37\340\340\377\377"
"\200\0\0\0\1\303\347\357gc\61\0\3\3\377\377\3\7\37\177s\343\300\303s{\37\17\7\3\377\377"
"\3\3\377\377\3\37\77scp<\36\17\3\1\0\0\0\0\0\0\0\37\37\0\0\0\1\1\1\0\1"
"\1\1\0\0\0\0\377\377\0\0\37\37\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
*/
/*
Fontname: wled_logo_2x2
Copyright: Created with Fony 1.4.7
Glyphs: 4/4
BBX Build Mode: 3
* this logo https://cdn.discordapp.com/attachments/706623245935444088/927361780613799956/wled_scaled.png
* encode map = 1, 2, 3, 4
*/
const uint8_t u8x8_wled_logo_2x2[133] U8X8_FONT_SECTION("u8x8_wled_logo_2x2") =
"\1\4\2\2\0\0\0\0\0\200\200\360\360\16\16\16\16\0\0\0\340\340\340\340\340\37\37\1\1\0\0\0"
"\0\0\0\0\360\360\16\16\16\200\200\16\16\16\360\360\0\0\0\200\37\37\340\340\340\37\37\340\340\340\37\37"
"\0\0\0\37\200~~\0\0\0\0\0\0\0\360\360\216\216\216\216\37\340\340\340\340\340\340\340\0\0\37\37"
"\343\343\343\343\16\16\0\0ppp\16\16\376\376\16\16\16\360\360\340\340\0\0\0\0\0\340\340\377\377\340"
"\340\340\37\37";
/*
Fontname: wled_logo_4x4
Copyright: Created with Fony 1.4.7
Glyphs: 4/4
BBX Build Mode: 3
* this logo https://cdn.discordapp.com/attachments/706623245935444088/927361780613799956/wled_scaled.png
* encode map = 1, 2, 3, 4
*/
/*
const uint8_t u8x8_wled_logo_4x4[517] U8X8_FONT_SECTION("u8x8_wled_logo_4x4") =
"\1\4\4\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\374\374\374\374\374\374\374\374\374"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\300\300\300\300\300\377\377\377\377\377\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\17\17\17\17\17\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\370\370\370\370\370\370\370\370\370\7\7\7\7\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\374\374\374\374\374\0\0\0\0\0\374\374\374\374\374\0\0\0\0\0\0\0"
"\0\0\0\0\0\377\377\377\377\377\0\0\0\0\0\300\300\300\300\300\0\0\0\0\0\377\377\377\377\377\0\0"
"\0\0\300\300\0\377\377\377\377\377\0\0\0\0\0\377\377\377\377\377\0\0\0\0\0\377\377\377\377\377\0\0"
"\0\0\377\377\0\7\7\7\7\7\370\370\370\370\370\7\7\7\7\7\370\370\370\370\370\7\7\7\7\7\0\0"
"\0\0\7\7\0\0\0\374\374\374\374\374\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\374\374\374"
"\374\374\374\374\300\300\300\77\77\77\77\77\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\300\300\300"
"\300\300\300\300\377\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\37\37\37"
"\37\37\37\37\7\7\7\370\370\370\370\370\370\370\370\370\370\370\370\370\0\0\0\0\7\7\7\7\7\370\370\370"
"\370\370\370\370\374\374\374\374\374\374\0\0\0\0\0\0\0\0\374\374\374\374\374\374\374\374\374\374\374\374\374\374"
"\0\0\0\0\300\300\0\0\0\0\0\0\0\77\77\77\77\77\0\0\0\0\377\377\377\377\377\0\0\0\0\377"
"\377\377\377\377\37\37\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\0\0\0\0\377"
"\377\377\377\377\370\370\370\370\370\370\0\0\0\0\0\0\0\0\370\370\370\370\377\377\377\377\377\370\370\370\370\377"
"\7\7\7\7";
*/
/*
Fontname: 4LineDisplay_WLED_icons_1x
Copyright:
Glyphs: 13/13
BBX Build Mode: 3
* 1 = sun
* 2 = skip forward
* 3 = fire
* 4 = custom palette
* 5 = puzzle piece
* 6 = moon
* 7 = brush
* 8 = contrast
* 9 = power-standby
* 10 = star
* 11 = heart
* 12 = Akemi
*-----------
* 20 = wifi
* 21 = media-play
*/
const uint8_t u8x8_4LineDisplay_WLED_icons_1x1[172] U8X8_FONT_SECTION("u8x8_4LineDisplay_WLED_icons_1x1") =
"\1\25\1\1\0B\30<<\30B\0~<\30\0~<\30\0p\374\77\216\340\370\360\0<n\372\377"
"\275\277\26\34\374\374\77\77\374\374\60\60<~~\360\340``\0\200\340\360p\14\16\6\1<~\377\377"
"\201\201B<\70D\200\217\200D\70\0\0\10x<<x\10\0\14\36>||>\36\14\64 \336\67"
";\336 \64\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\1\11\311"
"\311\1\2\0\0~<<\30\30\0";
/*
Fontname: 4LineDisplay_WLED_icons_2x
Copyright:
Glyphs: 11/11
BBX Build Mode: 3
* 1 = sun
* 2 = skip forward
* 3 = fire
* 4 = custom palette
* 5 = puzzle piece
* 6 = moon
* 7 = brush
* 8 = contrast
* 9 = power-standby
* 10 = star
* 11 = heart
* 12 = Akemi
*/
const uint8_t u8x8_4LineDisplay_WLED_icons_2x2[389] U8X8_FONT_SECTION("u8x8_4LineDisplay_WLED_icons_2x2") =
"\1\14\2\2\200\200\14\14\300\340\360\363\363\360\340\300\14\14\200\200\1\1\60\60\3\7\17\317\317\17\7\3"
"\60\60\1\1\374\370\360\340\340\300\200\0\374\370\360\340\340\300\200\0\77\37\17\7\7\3\1\0\77\37\17\7"
"\7\3\1\0\0\200\340\360\377\376\374\360\0\0\300\200\0\0\0\0\17\77\177\377\17\7\301\340\370\374\377\377"
"\377|\0\0\360\370\234\236\376\363\363\377\377\363\363\376><\370\360\3\17\77yy\377\377\377\377\317\17\17"
"\17\17\7\3\360\360\360\360\366\377\377\366\360\360\360\360\0\0\0\0\377\377\377\377\237\17\17\237\377\377\377\377"
"\6\17\17\6\340\370\374\376\377\340\200\0\0\0\0\0\0\0\0\0\3\17\37\77\177\177\177\377\376|||"
"\70\30\14\0\0\0\0\0\0\0\0``\360\370|<\36\7\2\0\300\360\376\377\177\77\36\0\1\1\0"
"\0\0\0\0\340\370\374\376\376\377\377\377\3\3\7\6\16<\370\340\7\37\77\177\177\377\377\377\300\300\340`"
"p<\37\7\300\340p\30\0\0\377\377\0\0\30p\340\300\0\0\17\37\70`\340\300\300\300\300\340`\70"
"\37\17\0\0\0@\300\300\300\300\340\374\374\340\300\300\300\300@\0\0\0\0\1s\77\37\17\17\37\77s"
"\1\0\0\0\360\370\374\374\374\374\370\360\360\370\374\374\374\374\370\360\0\1\3\7\17\37\77\177\177\77\37\17"
"\7\3\1\0\200\200\0\0\0\360\370\374<\334\330\360\0\0\200\200\2\2\14\30\24\37\6~\7\177\7\37"
"\24\30\16\2";
/*
Fontname: 4LineDisplay_WLED_icons_4x
Copyright:
Glyphs: 11/11
BBX Build Mode: 3
* 1 = sun
* 2 = skip forward
* 3 = fire
* 4 = custom palette
* 5 = puzzle piece
* 6 = moon
* 7 = brush
* 8 = contrast
* 9 = power-standby
* 10 = star
* 11 = heart
* 12 = Akemi
*/
/*
const uint8_t u8x8_4LineDisplay_WLED_icons_4x4[1540] U8X8_FONT_SECTION("u8x8_4LineDisplay_WLED_icons_4x4") =
"\1\14\4\4\0\0\0\0`\360\360`\0\0\0\0\0\0\6\17\17\6\0\0\0\0\0\0`\360\360`"
"\0\0\0\0\200\300\300\200\0\0\0\0\340\370\374\376\376\377\377\377\377\377\377\376\376\374\370\340\0\0\0\0"
"\200\300\300\200\1\3\3\1\0\0\0\0\7\37\77\177\177\377\377\377\377\377\377\177\177\77\37\7\0\0\0\0"
"\1\3\3\1\0\0\0\0\6\17\17\6\0\0\0\0\0\0`\360\360`\0\0\0\0\0\0\6\17\17\6"
"\0\0\0\0\360\340\300\200\200\0\0\0\0\0\0\0\0\0\0\0\360\340\300\200\200\0\0\0\0\0\0\0"
"\0\0\0\0\377\377\377\377\377\377\376\374\374\370\360\340\340\300\200\0\377\377\377\377\377\377\376\374\374\370\360\340"
"\340\300\200\0\377\377\377\377\377\377\177\77\77\37\17\7\7\3\1\0\377\377\377\377\377\377\177\77\77\37\17\7"
"\7\3\1\0\17\7\3\1\1\0\0\0\0\0\0\0\0\0\0\0\17\7\3\1\1\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\200\341\376\374\370\360\340\300\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\200\300\360\370\374\376\377\377\377\377\377\377\377\377~\0\0\0\0\20\340\300\200\0\0\0\0"
"\0\0\0\0~\377\377\377\377\377\377\377\377\177\77\37\17\3\1\0\200\300\340\370\376\377\377\377\377\376\374\340"
"\0\0\0\0\0\3\7\17\37\77\177\207\1\0\0\0\340\370\374\377\377\377\377\377\377\377\377\377\377\177\77\17"
"\0\0\0\0\0\0\0\200\300\360\370\370\374\34\16\16\16\36\377\377\377\377\37\16\16\16\36\374\374\370\370\360"
"\340\300\0\0\340\374\377\377\217\7\7\7\217\377\376\376\376\377\377\377\377\377\377\376\376\376\377\377\217\7\7\7"
"\217\377\377\374\17\177\377\377\377\37\17\17\17\37\377\377\377\377\377\377\377\377\377\377\377\377\177\177\177\177\77\77"
"\77\37\17\7\0\0\0\3\7\17\36>>\177\177\377\377\377\377\377\377\371p\60\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0<\376\377\377\377\377\376<\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0"
"\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377~~\377\377"
"\377\377~<\377\377\377\377\377\377\377\377\303\1\0\0\0\0\1\303\377\377\377\377\377\377\377\377\0\0\0\0"
"\0\0\0\0\0\0\200\340\360\370\374\374\376\376\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\370\377\377\377\377\377\377\377\377\377\376\360\300\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\7\77\377\377\377\377\377\377\377\377\377\377\377\377\377\376\374\370\370\360\360\360\340\340\340\340\340\340"
"\340\340\60\0\0\0\0\1\3\7\17\37\37\77\77\77\177\177\177\177\177\177\177\177\77\77\77\37\37\17\7\3"
"\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\200\300\340\340\360\370\374\374"
"~\77\16\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\30\34>~\377\377\377\377\177\77\37\7\3\0"
"\0\0\0\0\0\0\0\0\0\360\374\376\377\377\377\377\377\376\374\370\0\0\0\3\3\1\0\0\0\0\0\0"
"\0\0\0\0@@\340\370\374\377\377\377\177\177\177\77\37\17\7\1\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\200\300\340\360\370\374\374\376\376\376\377\377\377\377\17\17\17\37\36\36>|\374\370\360\340"
"\300\200\0\0\360\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\1\3\37"
"\377\377\376\360\17\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\200\300\370"
"\377\377\177\17\0\0\1\3\7\17\37\77\77\177\177\177\377\377\377\377\360\360\360\370xx|>\77\37\17\7"
"\3\1\0\0\0\0\0\0\0\200\300\200\0\0\0\0\377\377\377\377\0\0\0\0\200\300\200\0\0\0\0\0"
"\0\0\0\0\300\360\374\376\177\37\7\3\3\0\0\0\377\377\377\377\0\0\0\3\3\7\37\177\376\374\360\300"
"\0\0\0\0\77\377\377\377\340\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\340\377\377\377\77"
"\0\0\0\0\0\0\3\7\17\37><|x\370\360\360\360\360\360\360\370x|<>\37\17\7\3\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\340\374\374\340\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\20\60p\360\360\360\360\360\360\360\360\370\377\377\377\377\377\377\370\360\360\360\360\360\360\360\360"
"p\60\20\0\0\0\0\0\0\0\1\3\7\317\377\377\377\377\377\377\377\377\377\377\377\377\317\7\3\1\0\0"
"\0\0\0\0\0\0\0\0\0\0\0p>\37\17\17\7\3\1\0\0\1\3\7\17\17\37>p\0\0\0"
"\0\0\0\0\0\200\300\340\340\360\360\360\360\360\360\340\340\300\200\0\0\200\300\340\340\360\360\360\360\360\360\340"
"\340\300\200\0~\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\376\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377~\0\1\3\7\17\37\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\37\17"
"\7\3\1\0\0\0\0\0\0\0\0\0\0\1\3\7\17\37\77\177\177\77\37\17\7\3\1\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\300\340\340\360\360\360\360\340\340\300\200\0\0\0\0\0\0"
"\0\0\0\0\0@\340\300\340@\0\0\0\376\377\377\177\177\177\237\207\347\371\371\371\377\376\0\0\0\0@"
"\340\300\340@\2\4\4\35x\340\200\0\30\237\377\177\36\376\376\37\37\377\377\37\177\377\237\30\0\200\340x"
"\34\5\4\2\0\0\0\0\0\1\3\3\3\1\0\0\0\17\17\0\0\17\17\0\0\0\1\3\3\3\1\0"
"\0\0\0";
*/
/*
Fontname: 4LineDisplay_WLED_icons_6x
Copyright:
Glyphs: 11/11
BBX Build Mode: 3
* 1 = sun
* 2 = skip forward
* 3 = fire
* 4 = custom palette
* 5 = puzzle piece
* 6 = moon
* 7 = brush
* 8 = contrast
* 9 = power-standby
* 10 = star
* 11 = heart
* 12 = Akemi
*/
const uint8_t u8x8_4LineDisplay_WLED_icons_6x6[3460] U8X8_FONT_SECTION("u8x8_4LineDisplay_WLED_icons_6x6") =
"\1\14\6\6\0\0\0\0\0\0\200\300\300\300\300\200\0\0\0\0\0\0\0\0\0\36\77\77\77\77\36\0"
"\0\0\0\0\0\0\0\0\200\300\300\300\300\200\0\0\0\0\0\0\0\0\0\0\0\0\7\17\17\17\17\7"
"\0\0\0\0\200\300\340\340\340\360\360\360\360\360\360\340\340\340\300\200\0\0\0\0\7\17\17\17\17\7\0\0"
"\0\0\0\0\300\340\340\340\340\300\0\0\0\0\0\0\340\374\376\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\376\374\340\0\0\0\0\0\0\300\340\340\340\340\300\3\7\7\7\7\3\0\0\0\0\0\0"
"\7\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\7\0\0\0\0\0\0\3\7"
"\7\7\7\3\0\0\0\0\0\0\340\360\360\360\360\340\0\0\0\0\1\3\7\7\7\17\17\17\17\17\17\7"
"\7\7\3\1\0\0\0\0\340\360\360\360\360\340\0\0\0\0\0\0\0\0\0\0\0\0\1\3\3\3\3\1"
"\0\0\0\0\0\0\0\0\0x\374\374\374\374x\0\0\0\0\0\0\0\0\0\1\3\3\3\3\1\0\0"
"\0\0\0\0\300\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\200\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\376\376\374\370\360\360\340\300\200"
"\200\0\0\0\0\0\0\0\0\0\0\0\377\377\377\376\376\374\370\360\360\340\300\200\200\0\0\0\0\0\0\0"
"\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\374\374\370\360\340\340\300\200\0\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\376\374\374\370\360\340\340\300\200\0\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\177\77\77\37\17\7\7\3\1\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\77\37\17\7"
"\7\3\1\0\377\377\377\177\177\77\37\17\17\7\3\1\1\0\0\0\0\0\0\0\0\0\0\0\377\377\377\177"
"\177\77\37\17\17\7\3\1\1\0\0\0\0\0\0\0\0\0\0\0\3\1\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\376\374\374\370\360\340\300\200\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\340\360\374"
"\377\377\377\377\377\377\377\377\377\376\370\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\300\340\360\374\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37\0\0\0\0"
"\0\0\4\370\360\360\340\300\200\0\0\0\0\0\0\0\0\0\0\0\370\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\177\77\37\7\3\0\0\0\0\0\200\300\360\374\377\377\377\377\377\377\377\376\370\340\0\0\0"
"\0\0\0\0\3\37\177\377\377\377\377\377\377\377\377\377\77\17\7\1\0\0\0\0\0\200\300\360\370\374\376\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\1\3\7\17\37\77\77\177\200"
"\0\0\0\0\0\0\340\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\17\1\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\200\300\340\340\360\360\370|<>>>~\377\377\377\377\377\377\377\177"
"\77\36\36\36\36<|\370\370\360\360\340\340\200\0\0\0\0\0\0\0\0\300\360\374\376\377\377\377\377\377\377"
"\377\360\340\300\300\300\300\340\360\377\377\377\377\377\377\370\360\340\340\340\340\360\370\377\377\377\377\377\377\377\377\377"
"\374\360\340\200\360\377\377\377\377\377\207\3\1\1\1\1\3\207\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\207\3\1\1\1\1\3\207\377\377\377\377\377\17\377\377\377\377\377\377\377\376~>>"
"\77\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\376\376\376\377\377\377"
"\177\77\37\7\0\0\3\17\77\177\377\377\360\340\300\300\300\300\340\360\377\377\377\377\377\377\377\377\377\377\77\17"
"\17\7\7\7\7\7\7\7\7\7\3\3\3\3\1\0\0\0\0\0\0\0\0\0\0\0\0\1\3\7\17\37"
"\37\77\77\177\177\177\377\377\377\377\377\377\377\377\377~\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\370\374\376\377\377\377\377\377\377\376\374\360\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\360\360\360\360\360\360\360\360\360\360\360\360"
"\360\363\377\377\377\377\377\377\377\377\363\360\360\360\360\360\360\360\360\360\360\360\360\360\0\0\0\0\0\0\0\0"
"\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\374\376\376\377\377\377\377"
"\377\376\374\360\377\377\377\377\377\377\377\377\377\377\377\377\177\77\37\17\17\17\17\17\17\37\77\177\377\377\377\377"
"\377\377\377\377\377\377\377\377\3\3\7\7\17\17\17\17\7\7\3\0\377\377\377\377\377\377\377\377\377\377\377\377"
"\360\300\0\0\0\0\0\0\0\0\300\360\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\200\300\340\360\360\370\374\374\376\376\7\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\360\374\376\377\377\377\377\377\377\377"
"\377\377\377\340\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\360\300\200\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\17\177\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\376\374\370\360\360\340\340\300\300\300\200\200\200\200\0\0\0\0\0\0\200\200"
"\200\200\0\0\0\0\1\7\37\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\37\7\1\0\0\0\0\0\0\0\0\0\0\1\3\3\7"
"\17\17\37\37\37\77\77\77\77\177\177\177\177\177\177\77\77\77\77\37\37\37\17\17\7\3\3\1\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\200\200\300\340\360\360\370\374\374\376\377~\34\10\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\200\300\300\340\360\360\370\374\376\376\377\377\377\377\377\377\177\77\17\7\3"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\6\17\17\37\77\177\377"
"\377\377\377\377\377\377\77\37\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\370\374\376"
"\376\377\377\377\377\377\377\376\376\374\370\340\0\0\0\0\3\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\200\360\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\17\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`px\374\376\377\377\377\377\377\377"
"\177\177\177\77\77\37\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\200\300\340\360\360\370\374\374\374\376\376\376\377\377\377\377\377\77\77\77\77"
"\177~~\376\374\374\374\370\360\360\340\300\200\0\0\0\0\0\0\0\0\0\340\360\374\376\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\1\1\3\7\17\37\177\377\377\376\374"
"\360\340\0\0\370\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\1\17\377\377\377\377\377\370\37\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\360\377\377"
"\377\377\377\37\0\0\7\17\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0"
"\0\0\0\0\0\200\200\300\340\360\370\376\377\377\177\77\17\7\0\0\0\0\0\0\0\0\0\1\3\7\17\17"
"\37\77\77\77\177\177\177\377\377\377\377\377\374\374\374\374\376~~\177\77\77\77\37\17\17\7\3\1\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\300\340\360\370\374\376\376|"
"x \0\0\0\0\377\377\377\377\377\377\0\0\0\0 x|\376\376\374\370\360\340\300\200\0\0\0\0\0"
"\0\0\0\0\300\370\376\377\377\377\177\17\7\1\0\0\0\0\0\0\0\0\377\377\377\377\377\377\0\0\0\0"
"\0\0\0\0\1\7\37\177\377\377\377\376\370\200\0\0\0\0\0\0\177\377\377\377\377\377\200\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\377\377\377\377\377\177\0\0"
"\0\0\0\0\0\7\37\177\377\377\377\374\370\340\300\200\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\200\200\300\340\370\374\377\377\377\177\37\7\0\0\0\0\0\0\0\0\0\0\0\0\1\3\7\17\37\37\77"
"\77\177~~~\374\374\374\374\374\374\374\374~~~\177\77\77\37\37\17\7\3\1\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\340\374\374\340\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\300\370\377\377\377\377\377\377\370\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\4\14\34<<|\374\374\374\374\374\374\374\374\374\374\374\376\377\377\377\377\377\377\377\377\377"
"\377\376\374\374\374\374\374\374\374\374\374\374\374|<<\34\14\4\0\0\0\0\0\0\0\0\0\1\3\3\7"
"\17\37\77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\77\37\17\7\3\3\1\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\370\377\377\377\377\377\377\177\77\37\17\17\37\77\177"
"\377\377\377\377\377\377\370\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0p>"
"\37\17\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\1\3\7\17\17\37>p\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\200\200\200\300\300\300\300\300\300\200\200\200\0\0\0\0\0\0\0\0\0\0"
"\0\0\200\200\200\300\300\300\300\300\300\200\200\200\0\0\0\0\0\0\200\360\370\374\376\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\376\374\370\360\200\200\360\370\374\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376"
"\374\370\360\200\37\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37\0\0\1\3\7\17\37\77\177\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\37\17\7"
"\3\1\0\0\0\0\0\0\0\0\0\0\0\0\1\3\7\17\37\77\177\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\177\77\37\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\1\3\7\17\37\77\77\37\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\300\300\300\300\300\300"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\340\370\370\376\376\377\377\377\377\377\377\377\377\77\77\77>\376\370\370\340\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0 p\360\340\360p \0\0\0\0\0\0\377\377\377\377\177\177\177\177\177\207\207\340\340\377"
"\377\377\377\377\377\377\377\0\0\0\0\0 p\360\340\360p \0\6\4\14\14\15|x\360\200\200\0\0"
"pp\177\177\377\377\374|\374\374\374\177\177\177\377\377\377\177\377\377\377\377\177pp\0\0\200\200\360x}"
"\14\14\4\6\0\0\0\0\0\0\0\3\37\37|ppp\34\34\37\3\3\0\377\377\377\0\0\0\377\377"
"\377\0\3\3\37\37\34ppp~\37\37\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\7\7\7\0\0\0\7\7\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0";
/*
Fontname: akemi_8x8
Copyright: Created with Fony 1.4.7
Glyphs: 1/1
BBX Build Mode: 3
* 12 = Akemi
*/
/*
const uint8_t u8x8_akemi_8x8[516] U8X8_FONT_SECTION("u8x8_akemi_8x8") =
"\14\14\10\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\200\200\200\200\200\200\200\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\340\340\370\370\376\376\376\376"
"\377\377\377\377\377\377\377\377\376\376\376\376\370\370\340\340\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\376\377\377\377\377\377\377\377\377"
"\377\377\377\377\37\37\37\343\343\343\343\343\343\377\377\377\376\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\30\30~~\370\370~~\30\30\0\0\0\0\0\0\0\377\377\377\377\377\77\77\77\77\77"
"\77\300\300\300\370\370\370\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\30\0f\0\200\0\0"
"\0\0\0\0\6\6\30\30\30\31\371\370\370\340\340\0\0\0\0\0\340\340\377\377\377\377\377\376\376\376\376\376"
"\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\371\346\346\6\6\6\6\6\0\340\340\340\341\0\0"
"\0\0\0\0\0\0\0\0\0\0\1\1\37\37\377\376\376\340\340\200\201\201\341\341\177\177\37\37\1\1\377\377"
"\377\377\1\1\1\1\377\377\377\377\1\1\37\37\177\177\341\341\201\201\200\200\370\370\376\376\37\37\1\1\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\1\7\7\7\7\7\7\1\1\0\0\0\0\0\0\377\377"
"\377\377\0\0\0\0\377\377\377\377\0\0\0\0\0\0\1\1\7\7\7\7\7\7\1\1\0\0\0\0\0\0"
"\0\0\0";
*/

View File

@ -2,6 +2,7 @@
#include "wled.h" #include "wled.h"
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/ #include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
#include "4LD_wled_fonts.c"
// //
// Insired by the usermod_v2_four_line_display // Insired by the usermod_v2_four_line_display
@ -109,133 +110,6 @@ typedef enum {
SSD1306_SPI64 // U8X8_SSD1306_128X64_NONAME_HW_SPI SSD1306_SPI64 // U8X8_SSD1306_128X64_NONAME_HW_SPI
} DisplayType; } DisplayType;
/*
Fontname: benji_custom_icons_1x
Copyright:
Glyphs: 1/1
BBX Build Mode: 3
* 4 = custom palette
*/
const uint8_t u8x8_font_benji_custom_icons_1x1[13] U8X8_FONT_SECTION("u8x8_font_benji_custom_icons_1x1") =
"\4\4\1\1<n\372\377\275\277\26\34";
/*
Fontname: benji_custom_icons_2x
Copyright:
Glyphs: 8/8
BBX Build Mode: 3
// all the icons uses are consolidated into a single library to simplify code
// these are just the required icons stripped from the U8x8 libraries in addition to a few new custom icons
* 1 = sun
* 2 = skip forward
* 3 = fire
* 4 = custom palette
* 5 = puzzle piece
* 6 = moon
* 7 = brush
* 8 = custom saturation
*/
const uint8_t u8x8_font_benji_custom_icons_2x2[261] U8X8_FONT_SECTION("u8x8_font_benji_custom_icons_2x2") =
"\1\10\2\2\200\200\14\14\300\340\360\363\363\360\340\300\14\14\200\200\1\1\60\60\3\7\17\317\317\17\7\3"
"\60\60\1\1\374\370\360\340\340\300\200\0\374\370\360\340\340\300\200\0\77\37\17\7\7\3\1\0\77\37\17\7"
"\7\3\1\0\0\200\340\360\377\376\374\360\0\0\300\200\0\0\0\0\17\77\177\377\17\7\301\340\370\374\377\377"
"\377|\0\0\360\370\234\236\376\363\363\377\377\363\363\376><\370\360\3\17\77yy\377\377\377\377\317\17\17"
"\17\17\7\3\360\360\360\360\366\377\377\366\360\360\360\360\0\0\0\0\377\377\377\377\237\17\17\237\377\377\377\377"
"\6\17\17\6\340\370\374\376\377\340\200\0\0\0\0\0\0\0\0\0\3\17\37\77\177\177\177\377\376|||"
"\70\30\14\0\0\0\0\0\0\0\0``\360\370|<\36\7\2\0\300\360\376\377\177\77\36\0\1\1\0"
"\0\0\0\0\200\200\14\14\300\340\360\363\363\360\340\300\14\14\200\200\1\1\60\60\3\4\10\310\310\10\4\3"
"\60\60\1\1";
/*
Fontname: benji_custom_icons_6x
Copyright:
Glyphs: 8/8
BBX Build Mode: 3
// 6x6 icons libraries take up a lot of memory thus all the icons uses are consolidated into a single library
// these are just the required icons stripped from the U8x8 libraries in addition to a few new custom icons
* 1 = sun
* 2 = skip forward
* 3 = fire
* 4 = custom palette
* 5 = puzzle piece
* 6 = moon
* 7 = brush
* 8 = custom saturation
*/
const uint8_t u8x8_font_benji_custom_icons_6x6[2308] U8X8_FONT_SECTION("u8x8_font_benji_custom_icons_6x6") =
"\1\10\6\6\0\0\0\0\0\0\200\300\300\300\300\200\0\0\0\0\0\0\0\0\0\36\77\77\77\77\36\0"
"\0\0\0\0\0\0\0\0\200\300\300\300\300\200\0\0\0\0\0\0\0\0\0\0\0\0\7\17\17\17\17\7"
"\0\0\0\0\200\300\340\340\340\360\360\360\360\360\360\340\340\340\300\200\0\0\0\0\7\17\17\17\17\7\0\0"
"\0\0\0\0\300\340\340\340\340\300\0\0\0\0\0\0\340\374\376\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\376\374\340\0\0\0\0\0\0\300\340\340\340\340\300\3\7\7\7\7\3\0\0\0\0\0\0"
"\7\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\7\0\0\0\0\0\0\3\7"
"\7\7\7\3\0\0\0\0\0\0\340\360\360\360\360\340\0\0\0\0\1\3\7\7\7\17\17\17\17\17\17\7"
"\7\7\3\1\0\0\0\0\340\360\360\360\360\340\0\0\0\0\0\0\0\0\0\0\0\0\1\3\3\3\3\1"
"\0\0\0\0\0\0\0\0\0x\374\374\374\374x\0\0\0\0\0\0\0\0\0\1\3\3\3\3\1\0\0"
"\0\0\0\0\300\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\200\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\376\376\374\370\360\360\340\300\200"
"\200\0\0\0\0\0\0\0\0\0\0\0\377\377\377\376\376\374\370\360\360\340\300\200\200\0\0\0\0\0\0\0"
"\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\374\374\370\360\340\340\300\200\0\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\376\374\374\370\360\340\340\300\200\0\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\177\77\77\37\17\7\7\3\1\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\77\37\17\7"
"\7\3\1\0\377\377\377\177\177\77\37\17\17\7\3\1\1\0\0\0\0\0\0\0\0\0\0\0\377\377\377\177"
"\177\77\37\17\17\7\3\1\1\0\0\0\0\0\0\0\0\0\0\0\3\1\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\376\374\374\370\360\340\300\200\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\340\360\374"
"\377\377\377\377\377\377\377\377\377\376\370\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\300\340\360\374\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37\0\0\0\0"
"\0\0\4\370\360\360\340\300\200\0\0\0\0\0\0\0\0\0\0\0\370\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\177\77\37\7\3\0\0\0\0\0\200\300\360\374\377\377\377\377\377\377\377\376\370\340\0\0\0"
"\0\0\0\0\3\37\177\377\377\377\377\377\377\377\377\377\77\17\7\1\0\0\0\0\0\200\300\360\370\374\376\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\1\3\7\17\37\77\77\177\200"
"\0\0\0\0\0\0\340\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\17\1\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\200\300\340\340\360\360\370|<>>>~\377\377\377\377\377\377\377\177"
"\77\36\36\36\36<|\370\370\360\360\340\340\200\0\0\0\0\0\0\0\0\300\360\374\376\377\377\377\377\377\377"
"\377\360\340\300\300\300\300\340\360\377\377\377\377\377\377\370\360\340\340\340\340\360\370\377\377\377\377\377\377\377\377\377"
"\374\360\340\200\360\377\377\377\377\377\207\3\1\1\1\1\3\207\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\207\3\1\1\1\1\3\207\377\377\377\377\377\17\377\377\377\377\377\377\377\376~>>"
"\77\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\376\376\376\377\377\377"
"\177\77\37\7\0\0\3\17\77\177\377\377\360\340\300\300\300\300\340\360\377\377\377\377\377\377\377\377\377\377\77\17"
"\17\7\7\7\7\7\7\7\7\7\3\3\3\3\1\0\0\0\0\0\0\0\0\0\0\0\0\1\3\7\17\37"
"\37\77\77\177\177\177\377\377\377\377\377\377\377\377\377~\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\370\374\376\377\377\377\377\377\377\376\374\360\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\360\360\360\360\360\360\360\360\360\360\360\360"
"\360\363\377\377\377\377\377\377\377\377\363\360\360\360\360\360\360\360\360\360\360\360\360\360\0\0\0\0\0\0\0\0"
"\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\374\376\376\377\377\377\377"
"\377\376\374\360\377\377\377\377\377\377\377\377\377\377\377\377\177\77\37\17\17\17\17\17\17\37\77\177\377\377\377\377"
"\377\377\377\377\377\377\377\377\3\3\7\7\17\17\17\17\7\7\3\0\377\377\377\377\377\377\377\377\377\377\377\377"
"\360\300\0\0\0\0\0\0\0\0\300\360\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\200\300\340\360\360\370\374\374\376\376\7\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\360\374\376\377\377\377\377\377\377\377"
"\377\377\377\340\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\360\300\200\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\17\177\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\376\374\370\360\360\340\340\300\300\300\200\200\200\200\0\0\0\0\0\0\200\200"
"\200\200\0\0\0\0\1\7\37\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\37\7\1\0\0\0\0\0\0\0\0\0\0\1\3\3\7"
"\17\17\37\37\37\77\77\77\77\177\177\177\177\177\177\77\77\77\77\37\37\37\17\17\7\3\3\1\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\200\200\300\340\360\360\370\374\374\376\377~\34\10\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\200\300\300\340\360\360\370\374\376\376\377\377\377\377\377\377\177\77\17\7\3"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\6\17\17\37\77\177\377"
"\377\377\377\377\377\377\77\37\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\370\374\376"
"\376\377\377\377\377\377\377\376\376\374\370\340\0\0\0\0\3\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\200\360\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\17\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`px\374\376\377\377\377\377\377\377"
"\177\177\177\77\77\37\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\200\300\300\200\0\0\0\0\0\0\0\0\0\14\36\77\77\36\14\0\0"
"\0\0\0\0\0\0\0\200\300\300\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\7\17\17\7\3"
"\0\200\300\340\360\360\370\370\370\374\374\374\374\370\370\370\360\360\340\300\200\0\3\7\17\17\7\3\0\0\0\0"
"\0\0\0\0\300\340\360\360\340\300\0\0\0\0\340\374\377\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177"
"\177\177\177\177\177\377\374\340\0\0\0\0\300\340\360\360\340\300\0\0\0\1\3\3\1\0\0\0\0\0\1\17"
"\77\177\370\340\300\200\200\0\0\0\0\0\0\0\0\200\200\300\340\370\177\77\17\1\0\0\0\0\0\1\3\3"
"\1\0\0\0\0\0\0\0\0\0\60x\374\374x\60\0\0\0\1\3\3\7\7\7\16\16\16\16\7\7\7"
"\3\3\1\0\0\0\60x\374\374x\60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\14\36\77\77\36\14\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0";
class FourLineDisplayUsermod : public Usermod { class FourLineDisplayUsermod : public Usermod {
@ -256,16 +130,13 @@ class FourLineDisplayUsermod : public Usermod {
bool flip = false; // flip display 180° bool flip = false; // flip display 180°
uint8_t contrast = 10; // screen contrast uint8_t contrast = 10; // screen contrast
uint8_t lineHeight = 1; // 1 row or 2 rows uint8_t lineHeight = 1; // 1 row or 2 rows
uint32_t refreshRate = USER_LOOP_REFRESH_RATE_MS; // in ms uint16_t refreshRate = USER_LOOP_REFRESH_RATE_MS; // in ms
uint32_t screenTimeout = SCREEN_TIMEOUT_MS; // in ms uint32_t screenTimeout = SCREEN_TIMEOUT_MS; // in ms
bool sleepMode = true; // allow screen sleep? bool sleepMode = true; // allow screen sleep?
bool clockMode = false; // display clock bool clockMode = false; // display clock
bool showSeconds = true; // display clock with seconds bool showSeconds = true; // display clock with seconds
bool enabled = true; bool enabled = true;
// needRedraw marks if redraw is required to prevent often redrawing.
bool needRedraw = true;
// Next variables hold the previous known values to determine if redraw is // Next variables hold the previous known values to determine if redraw is
// required. // required.
String knownSsid = ""; String knownSsid = "";
@ -387,7 +258,7 @@ class FourLineDisplayUsermod : public Usermod {
setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255 setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
setPowerSave(0); setPowerSave(0);
//drawString(0, 0, "Loading..."); //drawString(0, 0, "Loading...");
overlay(PSTR("Loading..."),3000,0); overlayLogo(3500);
} }
// gets called every time WiFi is (re-)connected. Initialize own network // gets called every time WiFi is (re-)connected. Initialize own network
@ -405,7 +276,7 @@ class FourLineDisplayUsermod : public Usermod {
if (!enabled || strip.isUpdating()) return; if (!enabled || strip.isUpdating()) return;
unsigned long now = millis(); unsigned long now = millis();
if (now < nextUpdate) return; if (now < nextUpdate) return;
nextUpdate = now + ((clockMode && showSeconds) ? 1000 : refreshRate); nextUpdate = now + ((displayTurnedOff && clockMode && showSeconds) ? 1000 : refreshRate);
redraw(false); redraw(false);
} }
@ -437,6 +308,11 @@ class FourLineDisplayUsermod : public Usermod {
if (!ignoreLH && lineHeight==2) u8x8->draw1x2Glyph(col, row, glyph); if (!ignoreLH && lineHeight==2) u8x8->draw1x2Glyph(col, row, glyph);
else u8x8->drawGlyph(col, row, glyph); else u8x8->drawGlyph(col, row, glyph);
} }
void draw2x2Glyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font) {
if (type == NONE || !enabled) return;
u8x8->setFont(font);
u8x8->draw2x2Glyph(col, row, glyph);
}
uint8_t getCols() { uint8_t getCols() {
if (type==NONE || !enabled) return 0; if (type==NONE || !enabled) return 0;
return u8x8->getCols(); return u8x8->getCols();
@ -466,6 +342,7 @@ class FourLineDisplayUsermod : public Usermod {
* or if forceRedraw). * or if forceRedraw).
*/ */
void redraw(bool forceRedraw) { void redraw(bool forceRedraw) {
bool needRedraw = false;
unsigned long now = millis(); unsigned long now = millis();
if (type == NONE || !enabled) return; if (type == NONE || !enabled) return;
@ -483,49 +360,49 @@ class FourLineDisplayUsermod : public Usermod {
// Check if values which are shown on display changed from the last time. // Check if values which are shown on display changed from the last time.
if (forceRedraw) { if (forceRedraw) {
knownHour = 99; needRedraw = true;
needRedraw = true; clear();
clear();
} else if ((bri == 0 && powerON) || (bri > 0 && !powerON)) { //trigger power icon } else if ((bri == 0 && powerON) || (bri > 0 && !powerON)) { //trigger power icon
powerON = !powerON; powerON = !powerON;
drawStatusIcons(); drawStatusIcons();
lastRedraw = millis(); return;
return;
} else if (knownnightlight != nightlightActive) { //trigger moon icon } else if (knownnightlight != nightlightActive) { //trigger moon icon
knownnightlight = nightlightActive; knownnightlight = nightlightActive;
drawStatusIcons(); drawStatusIcons();
if (knownnightlight) overlay(PSTR(" Timer On"), 3000, 6); if (knownnightlight) {
lastRedraw = millis(); String timer = PSTR("Timer On");
return; center(timer,LINE_BUFFER_SIZE-1);
overlay(timer.c_str(), 2500, 6);
//lastRedraw = millis();
}
return;
} else if (wificonnected != interfacesInited) { //trigger wifi icon } else if (wificonnected != interfacesInited) { //trigger wifi icon
wificonnected = interfacesInited; wificonnected = interfacesInited;
drawStatusIcons(); drawStatusIcons();
lastRedraw = millis(); return;
return;
} else if (knownMode != effectCurrent) { } else if (knownMode != effectCurrent) {
knownMode = effectCurrent; knownMode = effectCurrent;
if (displayTurnedOff) needRedraw = true; if (displayTurnedOff) needRedraw = true;
else showCurrentEffectOrPalette(knownMode, JSON_mode_names, 3); else { showCurrentEffectOrPalette(knownMode, JSON_mode_names, 3); return; }
} else if (knownPalette != effectPalette) { } else if (knownPalette != effectPalette) {
knownPalette = effectPalette; knownPalette = effectPalette;
if (displayTurnedOff) needRedraw = true; if (displayTurnedOff) needRedraw = true;
else showCurrentEffectOrPalette(knownPalette, JSON_palette_names, 2); else { showCurrentEffectOrPalette(knownPalette, JSON_palette_names, 2); return; }
} else if (knownBrightness != bri) { } else if (knownBrightness != bri) {
if (displayTurnedOff && nightlightActive) { needRedraw = false; knownBrightness = bri; } if (displayTurnedOff && nightlightActive) { knownBrightness = bri; }
else if (displayTurnedOff) needRedraw = true; else if (!displayTurnedOff) { updateBrightness(); return; }
else updateBrightness();
} else if (knownEffectSpeed != effectSpeed) { } else if (knownEffectSpeed != effectSpeed) {
if (displayTurnedOff) needRedraw = true; if (displayTurnedOff) needRedraw = true;
else updateSpeed(); else { updateSpeed(); return; }
} else if (knownEffectIntensity != effectIntensity) { } else if (knownEffectIntensity != effectIntensity) {
if (displayTurnedOff) needRedraw = true; if (displayTurnedOff) needRedraw = true;
else updateIntensity(); else { updateIntensity(); return; }
} }
if (!needRedraw) { if (!needRedraw) {
// Nothing to change. // Nothing to change.
// Turn off display after 1 minutes with no change. // Turn off display after 1 minutes with no change.
if (sleepMode && !displayTurnedOff && (now - lastRedraw > screenTimeout)) { if (sleepMode && !displayTurnedOff && (millis() - lastRedraw > screenTimeout)) {
// We will still check if there is a change in redraw() // We will still check if there is a change in redraw()
// and turn it back on if it changed. // and turn it back on if it changed.
clear(); clear();
@ -536,14 +413,10 @@ class FourLineDisplayUsermod : public Usermod {
return; return;
} }
needRedraw = false; lastRedraw = now;
lastRedraw = millis();
if (displayTurnedOff) { // Turn the display back on
// Turn the display back on wakeDisplay();
sleepOrClock(false);
clear();
}
// Update last known values. // Update last known values.
knownBrightness = bri; knownBrightness = bri;
@ -579,7 +452,7 @@ class FourLineDisplayUsermod : public Usermod {
char lineBuffer[4]; char lineBuffer[4];
sprintf_P(lineBuffer, PSTR("%-3d"), brightness100); sprintf_P(lineBuffer, PSTR("%-3d"), brightness100);
drawString(1, lineHeight, lineBuffer); drawString(1, lineHeight, lineBuffer);
lastRedraw = millis(); //lastRedraw = millis();
} }
} }
@ -590,7 +463,7 @@ class FourLineDisplayUsermod : public Usermod {
char lineBuffer[4]; char lineBuffer[4];
sprintf_P(lineBuffer, PSTR("%-3d"), fxspeed100); sprintf_P(lineBuffer, PSTR("%-3d"), fxspeed100);
drawString(5, lineHeight, lineBuffer); drawString(5, lineHeight, lineBuffer);
lastRedraw = millis(); //lastRedraw = millis();
} }
} }
@ -601,30 +474,34 @@ class FourLineDisplayUsermod : public Usermod {
char lineBuffer[4]; char lineBuffer[4];
sprintf_P(lineBuffer, PSTR("%-3d"), fxintensity100); sprintf_P(lineBuffer, PSTR("%-3d"), fxintensity100);
drawString(9, lineHeight, lineBuffer); drawString(9, lineHeight, lineBuffer);
lastRedraw = millis(); //lastRedraw = millis();
} }
} }
void draw2x2GlyphIcons() { void draw2x2GlyphIcons() {
if (lineHeight == 2) { if (lineHeight == 2) {
drawGlyph(1, 0, 1, u8x8_font_benji_custom_icons_2x2, true);//brightness icon drawGlyph( 1, 0, 1, u8x8_4LineDisplay_WLED_icons_2x2, true); //brightness icon
drawGlyph(5, 0, 2, u8x8_font_benji_custom_icons_2x2, true);//speed icon drawGlyph( 5, 0, 2, u8x8_4LineDisplay_WLED_icons_2x2, true); //speed icon
drawGlyph(9, 0, 3, u8x8_font_benji_custom_icons_2x2, true);//intensity icon drawGlyph( 9, 0, 3, u8x8_4LineDisplay_WLED_icons_2x2, true); //intensity icon
drawGlyph(14, 2*lineHeight, 4, u8x8_font_benji_custom_icons_2x2, true);//palette icon drawGlyph(14, 2*lineHeight, 4, u8x8_4LineDisplay_WLED_icons_2x2, true); //palette icon
drawGlyph(14, 3*lineHeight, 5, u8x8_font_benji_custom_icons_2x2, true);//effect icon drawGlyph(14, 3*lineHeight, 5, u8x8_4LineDisplay_WLED_icons_2x2, true); //effect icon
} else { } else {
drawGlyph(2, 0, 69, u8x8_font_open_iconic_weather_1x1); //brightness icon drawGlyph( 2, 0, 1, u8x8_4LineDisplay_WLED_icons_1x1); //brightness icon
drawGlyph(6, 0, 72, u8x8_font_open_iconic_play_1x1); //speed icon drawGlyph( 6, 0, 2, u8x8_4LineDisplay_WLED_icons_1x1); //speed icon
drawGlyph(10, 0, 78, u8x8_font_open_iconic_thing_1x1); //intensity icon drawGlyph(10, 0, 3, u8x8_4LineDisplay_WLED_icons_1x1); //intensity icon
drawGlyph(15, 2*lineHeight, 4, u8x8_font_benji_custom_icons_1x1); //palette icon if (markLineNum!=2) drawGlyph(0, 2, 4, u8x8_4LineDisplay_WLED_icons_1x1); //palette icon
drawGlyph(15, 3*lineHeight, 70, u8x8_font_open_iconic_thing_1x1); //effect icon if (markLineNum!=3) drawGlyph(0, 3, 5, u8x8_4LineDisplay_WLED_icons_1x1); //effect icon
} }
} }
void drawStatusIcons() { void drawStatusIcons() {
drawGlyph(14, 0, 80 + (wificonnected?0:1), u8x8_font_open_iconic_embedded_1x1, true); // wifi icon uint8_t col = 15;
drawGlyph(15, 0, 78 + (bri > 0 ? 0 : 3), u8x8_font_open_iconic_embedded_1x1, true); // power icon uint8_t row = 0;
drawGlyph(13, 0, 66 + (nightlightActive?0:4), u8x8_font_open_iconic_weather_1x1, true); // moon icon for nighlight mode drawGlyph(col, row, (wificonnected ? 20 : 0), u8x8_4LineDisplay_WLED_icons_1x1, true); // wifi icon
if (lineHeight==2) { col--; } else { row++; }
drawGlyph(col, row, (bri > 0 ? 9 : 0), u8x8_4LineDisplay_WLED_icons_1x1, true); // power icon
if (lineHeight==2) { col--; } else { row++; }
drawGlyph(col, row, (nightlightActive ? 6 : 0), u8x8_4LineDisplay_WLED_icons_1x1, true); // moon icon for nighlight mode
} }
/** /**
@ -633,25 +510,24 @@ class FourLineDisplayUsermod : public Usermod {
* pass line and colum info * pass line and colum info
*/ */
void setMarkLine(byte newMarkLineNum, byte newMarkColNum) { void setMarkLine(byte newMarkLineNum, byte newMarkColNum) {
markLineNum = newMarkLineNum; markLineNum = newMarkLineNum;
markColNum = newMarkColNum; markColNum = newMarkColNum;
} }
//Draw the arrow for the current setting beiong changed //Draw the arrow for the current setting beiong changed
void drawArrow() { void drawArrow() {
if (markColNum != 255 && markLineNum !=255) drawGlyph(markColNum, markLineNum*lineHeight, 69, u8x8_font_open_iconic_play_1x1); if (markColNum != 255 && markLineNum !=255) drawGlyph(markColNum, markLineNum*lineHeight, 21, u8x8_4LineDisplay_WLED_icons_1x1);
} }
//Display the current effect or palette (desiredEntry) //Display the current effect or palette (desiredEntry)
// on the appropriate line (row). // on the appropriate line (row).
void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row) { void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row) {
char lineBuffer[LINE_BUFFER_SIZE]; char lineBuffer[MAX_JSON_CHARS];
knownMode = effectCurrent; knownMode = effectCurrent;
knownPalette = effectPalette; knownPalette = effectPalette;
if (overlayUntil == 0) { if (overlayUntil == 0) {
// Find the mode name in JSON // Find the mode name in JSON
uint8_t printedChars = extractModeName(inputEffPal, qstring, lineBuffer, LINE_BUFFER_SIZE-1); uint8_t printedChars = extractModeName(inputEffPal, qstring, lineBuffer, MAX_JSON_CHARS-1);
if (lineHeight == 2) { // use this code for 8 line display if (lineHeight == 2) { // use this code for 8 line display
char smallBuffer1[MAX_MODE_LINE_SPACE]; char smallBuffer1[MAX_MODE_LINE_SPACE];
char smallBuffer2[MAX_MODE_LINE_SPACE]; char smallBuffer2[MAX_MODE_LINE_SPACE];
@ -707,48 +583,119 @@ class FourLineDisplayUsermod : public Usermod {
*/ */
bool wakeDisplay() { bool wakeDisplay() {
if (type == NONE || !enabled) return false; if (type == NONE || !enabled) return false;
knownHour = 99;
if (displayTurnedOff) { if (displayTurnedOff) {
clear(); clear();
// Turn the display back on // Turn the display back on
sleepOrClock(false); sleepOrClock(false);
redraw(true); //lastRedraw = millis();
return true; return true;
} }
return false; return false;
} }
/** /**
* Allows you to show one line and a glyph as overlay for a * Allows you to show one line and a glyph as overlay for a period of time.
* period of time.
* Clears the screen and prints. * Clears the screen and prints.
* Used in Rotary Encoder usermod.
*/ */
void overlay(const char* line1, long showHowLong, byte glyphType) { void overlay(const char* line1, long showHowLong, byte glyphType) {
if (displayTurnedOff) { // Turn the display back on
// Turn the display back on if (!wakeDisplay()) clear();
sleepOrClock(false);
}
// Print the overlay // Print the overlay
clear(); if (glyphType>0 && glyphType<255) {
if (glyphType > 0) { if (lineHeight == 2) drawGlyph(5, 0, glyphType, u8x8_4LineDisplay_WLED_icons_6x6, true);
if (lineHeight == 2) drawGlyph(5, 0, glyphType, u8x8_font_benji_custom_icons_6x6, true); else drawGlyph(7, lineHeight, glyphType, u8x8_4LineDisplay_WLED_icons_2x2, true);
else drawGlyph(7, lineHeight, glyphType, u8x8_font_benji_custom_icons_2x2, true); }
if (line1) drawString(0, 3*lineHeight, line1); if (line1) {
String buf = line1;
center(buf, getCols());
drawString(0, (glyphType<255?3:0)*lineHeight, buf.c_str());
}
overlayUntil = millis() + showHowLong;
}
/**
* Allows you to show Akemi WLED logo overlay for a period of time.
* Clears the screen and prints.
*/
void overlayLogo(long showHowLong) {
// Turn the display back on
if (!wakeDisplay()) clear();
// Print the overlay
if (lineHeight == 2) {
//add a bit of randomness
switch (millis()%3) {
case 0:
//WLED
draw2x2Glyph( 0, 2, 1, u8x8_wled_logo_2x2);
draw2x2Glyph( 4, 2, 2, u8x8_wled_logo_2x2);
draw2x2Glyph( 8, 2, 3, u8x8_wled_logo_2x2);
draw2x2Glyph(12, 2, 4, u8x8_wled_logo_2x2);
break;
case 1:
//WLED Akemi
drawGlyph( 2, 2, 1, u8x8_wled_logo_akemi_4x4, true);
drawGlyph( 6, 2, 2, u8x8_wled_logo_akemi_4x4, true);
drawGlyph(10, 2, 3, u8x8_wled_logo_akemi_4x4, true);
break;
case 2:
//Akemi
//draw2x2Glyph( 4, 0, 12, u8x8_4LineDisplay_WLED_icons_4x4);
drawGlyph( 5, 0, 12, u8x8_4LineDisplay_WLED_icons_6x6, true);
drawString(6, 6, "WLED");
break;
}
} else { } else {
if (line1) drawString(0, 2*(lineHeight-1), line1); switch (millis()%3) {
case 0:
//WLED
draw2x2Glyph( 0, 0, 1, u8x8_wled_logo_2x2);
draw2x2Glyph( 4, 0, 2, u8x8_wled_logo_2x2);
draw2x2Glyph( 8, 0, 3, u8x8_wled_logo_2x2);
draw2x2Glyph(12, 0, 4, u8x8_wled_logo_2x2);
break;
case 1:
//WLED Akemi
drawGlyph( 2, 0, 1, u8x8_wled_logo_akemi_4x4);
drawGlyph( 6, 0, 2, u8x8_wled_logo_akemi_4x4);
drawGlyph(10, 0, 3, u8x8_wled_logo_akemi_4x4);
break;
case 2:
//Akemi
//drawGlyph( 6, 0, 12, u8x8_4LineDisplay_WLED_icons_4x4);
draw2x2Glyph( 6, 0, 12, u8x8_4LineDisplay_WLED_icons_2x2);
break;
}
}
overlayUntil = millis() + showHowLong;
}
/**
* Allows you to show two lines as overlay for a period of time.
* Clears the screen and prints.
* Used in Auto Save usermod
*/
void overlay(const char* line1, const char* line2, long showHowLong) {
// Turn the display back on
if (!wakeDisplay()) clear();
// Print the overlay
if (line1) {
String buf = line1;
center(buf, getCols());
drawString(0, 1*lineHeight, buf.c_str());
}
if (line2) {
String buf = line2;
center(buf, getCols());
drawString(0, 2*lineHeight, buf.c_str());
} }
overlayUntil = millis() + showHowLong; overlayUntil = millis() + showHowLong;
} }
void networkOverlay(const char* line1, long showHowLong) { void networkOverlay(const char* line1, long showHowLong) {
if (displayTurnedOff) { // Turn the display back on
// Turn the display back on if (!wakeDisplay()) clear();
sleepOrClock(false);
}
// Print the overlay // Print the overlay
clear();
// First row string
if (line1) { if (line1) {
String l1 = line1; String l1 = line1;
l1.trim(); l1.trim();
@ -785,15 +732,15 @@ class FourLineDisplayUsermod : public Usermod {
*/ */
void sleepOrClock(bool enabled) { void sleepOrClock(bool enabled) {
if (enabled) { if (enabled) {
displayTurnedOff = true;
if (clockMode) { if (clockMode) {
knownMinute = knownHour = 99; knownMinute = knownHour = 99;
showTime(); showTime();
} else } else
setPowerSave(1); setPowerSave(1);
displayTurnedOff = true;
} else { } else {
setPowerSave(0);
displayTurnedOff = false; displayTurnedOff = false;
setPowerSave(0);
} }
} }
@ -819,29 +766,27 @@ class FourLineDisplayUsermod : public Usermod {
if (AmPmHour > 11) { AmPmHour -= 12; isitAM = false; } if (AmPmHour > 11) { AmPmHour -= 12; isitAM = false; }
if (AmPmHour == 0) { AmPmHour = 12; } if (AmPmHour == 0) { AmPmHour = 12; }
} }
drawStatusIcons(); //icons power, wifi, timer, etc
if (knownHour != hourCurrent) { if (knownHour != hourCurrent) {
// only update date when hour changes // only update date when hour changes
sprintf_P(lineBuffer, PSTR("%s %2d "), monthShortStr(month(localTime)), day(localTime)); sprintf_P(lineBuffer, PSTR("%s %2d "), monthShortStr(month(localTime)), day(localTime));
draw2x2String(2, lineHeight==1 ? 0 : lineHeight, lineBuffer); // adjust for 8 line displays, draw month and day draw2x2String(2, lineHeight==1 ? 0 : lineHeight, lineBuffer); // adjust for 8 line displays, draw month and day
} }
sprintf_P(lineBuffer,PSTR("%2d:%02d"), (useAMPM ? AmPmHour : hourCurrent), minuteCurrent); sprintf_P(lineBuffer,PSTR("%2d:%02d"), (useAMPM ? AmPmHour : hourCurrent), minuteCurrent);
draw2x2String(2, lineHeight*2, lineBuffer); //draw hour, min. blink ":" depending on odd/even seconds draw2x2String(2, lineHeight*2, lineBuffer); //draw hour, min. blink ":" depending on odd/even seconds
if (useAMPM) drawString(12, lineHeight*2, (isitAM ? "AM" : "PM"), true); //draw am/pm if using 12 time if (useAMPM) drawString(12, lineHeight*2, (isitAM ? "AM" : "PM"), true); //draw am/pm if using 12 time
drawStatusIcons(); //icons power, wifi, timer, etc
knownMinute = minuteCurrent; knownMinute = minuteCurrent;
knownHour = hourCurrent; knownHour = hourCurrent;
} else { } else {
if (secondCurrent == lastSecond) return; if (secondCurrent == lastSecond) return;
} }
if (showSeconds && !useAMPM) { if (showSeconds) {
lastSecond = secondCurrent; lastSecond = secondCurrent;
draw2x2String(6, lineHeight*2, secondCurrent%2 ? " " : ":"); draw2x2String(6, lineHeight*2, secondCurrent%2 ? " " : ":");
sprintf_P(lineBuffer, PSTR("%02d"), secondCurrent); sprintf_P(lineBuffer, PSTR("%02d"), secondCurrent);
drawString(12 + (lineHeight%2), lineHeight*2+1, lineBuffer, true); // even with double sized rows print seconds in 1 line drawString(12, lineHeight*2+1, lineBuffer, true); // even with double sized rows print seconds in 1 line
} }
} }
@ -896,7 +841,7 @@ class FourLineDisplayUsermod : public Usermod {
top["help4Type"] = F("1=SSD1306,2=SH1106,3=SSD1306_128x64,4=SSD1305,5=SSD1305_128x64,6=SSD1306_SPI,7=SSD1306_SPI_128x64"); // help for Settings page top["help4Type"] = F("1=SSD1306,2=SH1106,3=SSD1306_128x64,4=SSD1305,5=SSD1305_128x64,6=SSD1306_SPI,7=SSD1306_SPI_128x64"); // help for Settings page
top[FPSTR(_flip)] = (bool) flip; top[FPSTR(_flip)] = (bool) flip;
top[FPSTR(_contrast)] = contrast; top[FPSTR(_contrast)] = contrast;
top[FPSTR(_refreshRate)] = refreshRate/1000; top[FPSTR(_refreshRate)] = refreshRate;
top[FPSTR(_screenTimeOut)] = screenTimeout/1000; top[FPSTR(_screenTimeOut)] = screenTimeout/1000;
top[FPSTR(_sleepMode)] = (bool) sleepMode; top[FPSTR(_sleepMode)] = (bool) sleepMode;
top[FPSTR(_clockMode)] = (bool) clockMode; top[FPSTR(_clockMode)] = (bool) clockMode;
@ -930,7 +875,8 @@ class FourLineDisplayUsermod : public Usermod {
for (byte i=0; i<5; i++) newPin[i] = top["pin"][i] | ioPin[i]; for (byte i=0; i<5; i++) newPin[i] = top["pin"][i] | ioPin[i];
flip = top[FPSTR(_flip)] | flip; flip = top[FPSTR(_flip)] | flip;
contrast = top[FPSTR(_contrast)] | contrast; contrast = top[FPSTR(_contrast)] | contrast;
refreshRate = (top[FPSTR(_refreshRate)] | refreshRate/1000) * 1000; refreshRate = top[FPSTR(_refreshRate)] | refreshRate;
refreshRate = min(5000, max(250, (int)refreshRate));
screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000; screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000;
sleepMode = top[FPSTR(_sleepMode)] | sleepMode; sleepMode = top[FPSTR(_sleepMode)] | sleepMode;
clockMode = top[FPSTR(_clockMode)] | clockMode; clockMode = top[FPSTR(_clockMode)] | clockMode;
@ -964,14 +910,15 @@ class FourLineDisplayUsermod : public Usermod {
setup(); setup();
needsRedraw |= true; needsRedraw |= true;
} }
/*if (!(type == SSD1306_SPI || type == SSD1306_SPI64))*/ u8x8->setBusClock(ioFrequency); // can be used for SPI too u8x8->setBusClock(ioFrequency); // can be used for SPI too
setContrast(contrast); setContrast(contrast);
setFlipMode(flip); setFlipMode(flip);
knownHour = 99; knownHour = 99;
if (needsRedraw && !wakeDisplay()) redraw(true); if (needsRedraw && !wakeDisplay()) redraw(true);
else overlayLogo(3500);
} }
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features // use "return !top["newestParameter"].isNull();" when updating Usermod with new features
return !top[FPSTR(_showSeconds)].isNull(); return !top[FPSTR(_refreshRate)].isNull();
} }
/* /*
@ -987,7 +934,7 @@ class FourLineDisplayUsermod : public Usermod {
const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay"; const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay";
const char FourLineDisplayUsermod::_enabled[] PROGMEM = "enabled"; const char FourLineDisplayUsermod::_enabled[] PROGMEM = "enabled";
const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast"; const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast";
const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRateSec"; const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRate-ms";
const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec"; const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec";
const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip"; const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip";
const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode"; const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode";

View File

@ -47,7 +47,7 @@
// The last UI state, remove color and saturation option if diplay not active(too many options) // The last UI state, remove color and saturation option if diplay not active(too many options)
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
#define LAST_UI_STATE 6 #define LAST_UI_STATE 7
#else #else
#define LAST_UI_STATE 4 #define LAST_UI_STATE 4
#endif #endif
@ -115,17 +115,20 @@ static int re_qstringCmp(const void *ap, const void *bp) {
class RotaryEncoderUIUsermod : public Usermod { class RotaryEncoderUIUsermod : public Usermod {
private: private:
int fadeAmount = 5; // Amount to change every step (brightness) int8_t fadeAmount = 5; // Amount to change every step (brightness)
unsigned long currentTime;
unsigned long loopTime; unsigned long loopTime;
unsigned long buttonHoldTime;
unsigned long buttonPressedTime = 0;
unsigned long buttonWaitTime = 0;
bool buttonPressedBefore = false;
bool buttonLongPressed = false;
int8_t pinA = ENCODER_DT_PIN; // DT from encoder int8_t pinA = ENCODER_DT_PIN; // DT from encoder
int8_t pinB = ENCODER_CLK_PIN; // CLK from encoder int8_t pinB = ENCODER_CLK_PIN; // CLK from encoder
int8_t pinC = ENCODER_SW_PIN; // SW from encoder int8_t pinC = ENCODER_SW_PIN; // SW from encoder
unsigned char select_state = 0; // 0: brightness, 1: effect, 2: effect speed
unsigned char button_state = HIGH; unsigned char select_state = 0; // 0: brightness, 1: effect, 2: effect speed, ...
unsigned char prev_button_state = HIGH;
bool networkShown = false;
uint16_t currentHue1 = 16; // default boot color uint16_t currentHue1 = 16; // default boot color
byte currentSat1 = 255; byte currentSat1 = 255;
@ -157,6 +160,9 @@ private:
uint8_t knownMode = 0; uint8_t knownMode = 0;
uint8_t knownPalette = 0; uint8_t knownPalette = 0;
byte presetHigh = 0;
byte presetLow = 0;
bool initDone = false; bool initDone = false;
bool enabled = true; bool enabled = true;
@ -166,6 +172,8 @@ private:
static const char _DT_pin[]; static const char _DT_pin[];
static const char _CLK_pin[]; static const char _CLK_pin[];
static const char _SW_pin[]; static const char _SW_pin[];
static const char _presetHigh[];
static const char _presetLow[];
/** /**
* Sort the modes and palettes to the index arrays * Sort the modes and palettes to the index arrays
@ -266,8 +274,7 @@ public:
pinMode(pinA, INPUT_PULLUP); pinMode(pinA, INPUT_PULLUP);
pinMode(pinB, INPUT_PULLUP); pinMode(pinB, INPUT_PULLUP);
pinMode(pinC, INPUT_PULLUP); pinMode(pinC, INPUT_PULLUP);
currentTime = millis(); loopTime = millis();
loopTime = currentTime;
if (!initDone) sortModesAndPalettes(); if (!initDone) sortModesAndPalettes();
@ -307,7 +314,8 @@ public:
*/ */
void loop() void loop()
{ {
currentTime = millis(); // get the current elapsed time if (!enabled || strip.isUpdating()) return;
unsigned long currentTime = millis(); // get the current elapsed time
// Initialize effectCurrentIndex and effectPaletteIndex to // Initialize effectCurrentIndex and effectPaletteIndex to
// current state. We do it here as (at least) effectCurrent // current state. We do it here as (at least) effectCurrent
@ -323,58 +331,48 @@ public:
if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz
{ {
button_state = digitalRead(pinC); loopTime = currentTime; // Updates loopTime
if (prev_button_state != button_state)
{
if (button_state == HIGH && (millis()-buttonHoldTime < 3000))
{
prev_button_state = button_state;
char newState = select_state + 1; bool buttonPressed = !digitalRead(pinC); //0=pressed, 1=released
if (newState > LAST_UI_STATE) newState = 0; if (buttonPressed) {
if (!buttonPressedBefore) buttonPressedTime = currentTime;
bool changedState = true; buttonPressedBefore = true;
if (display != nullptr) { if (currentTime-buttonPressedTime > 3000) {
switch(newState) { if (!buttonLongPressed) displayNetworkInfo(); //long press for network info
case 0: buttonLongPressed = true;
changedState = changeState(PSTR("Brightness"), 1, 0, 1); }
break; } else if (!buttonPressed && buttonPressedBefore) {
case 1: bool doublePress = buttonWaitTime;
changedState = changeState(PSTR("Speed"), 1, 4, 2); buttonWaitTime = 0;
break; if (!buttonLongPressed) {
case 2: if (doublePress) {
changedState = changeState(PSTR("Intensity"), 1 ,8, 3); toggleOnOff();
break; lampUdated();
case 3: } else {
changedState = changeState(PSTR("Color Palette"), 2, 0, 4); buttonWaitTime = currentTime;
break;
case 4:
changedState = changeState(PSTR("Effect"), 3, 0, 5);
break;
case 5:
changedState = changeState(PSTR("Main Color"), 255, 255, 7);
break;
case 6:
changedState = changeState(PSTR("Saturation"), 255, 255, 8);
break;
}
}
if (changedState) {
select_state = newState;
} }
} }
else buttonLongPressed = false;
{ buttonPressedBefore = false;
prev_button_state = button_state;
networkShown = false;
if (!prev_button_state) buttonHoldTime = millis();
}
} }
if (buttonWaitTime && currentTime-buttonWaitTime>350 && !buttonPressedBefore) {
if (!prev_button_state && (millis()-buttonHoldTime > 3000) && !networkShown) { buttonWaitTime = 0;
displayNetworkInfo(); //long press for network info char newState = select_state + 1;
loopTime = currentTime; // Updates loopTime bool changedState = true;
return; if (newState > LAST_UI_STATE || (newState == 7 && presetHigh==0 && presetLow == 0)) newState = 0;
if (display != nullptr) {
switch (newState) {
case 0: changedState = changeState(PSTR("Brightness"), 1, 0, 1); break; //1 = sun
case 1: changedState = changeState(PSTR("Speed"), 1, 4, 2); break; //2 = skip forward
case 2: changedState = changeState(PSTR("Intensity"), 1, 8, 3); break; //3 = fire
case 3: changedState = changeState(PSTR("Color Palette"), 2, 0, 4); break; //4 = custom palette
case 4: changedState = changeState(PSTR("Effect"), 3, 0, 5); break; //5 = puzzle piece
case 5: changedState = changeState(PSTR("Main Color"), 255, 255, 7); break; //7 = brush
case 6: changedState = changeState(PSTR("Saturation"), 255, 255, 8); break; //8 = contrast
case 7: changedState = changeState(PSTR("Preset"), 255, 255, 11); break; //11 = heart
}
}
if (changedState) select_state = newState;
} }
Enc_A = digitalRead(pinA); // Read encoder pins Enc_A = digitalRead(pinA); // Read encoder pins
@ -384,65 +382,37 @@ public:
if (Enc_B == LOW) //changes to LOW so that then encoder registers a change at the very end of a pulse if (Enc_B == LOW) //changes to LOW so that then encoder registers a change at the very end of a pulse
{ // B is high so clockwise { // B is high so clockwise
switch(select_state) { switch(select_state) {
case 0: case 0: changeBrightness(true); break;
changeBrightness(true); case 1: changeEffectSpeed(true); break;
break; case 2: changeEffectIntensity(true); break;
case 1: case 3: changePalette(true); break;
changeEffectSpeed(true); case 4: changeEffect(true); break;
break; case 5: changeHue(true); break;
case 2: case 6: changeSat(true); break;
changeEffectIntensity(true); case 7: changePreset(true); break;
break;
case 3:
changePalette(true);
break;
case 4:
changeEffect(true);
break;
case 5:
changeHue(true);
break;
case 6:
changeSat(true);
break;
} }
} }
else if (Enc_B == HIGH) else if (Enc_B == HIGH)
{ // B is low so counter-clockwise { // B is low so counter-clockwise
switch(select_state) { switch(select_state) {
case 0: case 0: changeBrightness(false); break;
changeBrightness(false); case 1: changeEffectSpeed(false); break;
break; case 2: changeEffectIntensity(false); break;
case 1: case 3: changePalette(false); break;
changeEffectSpeed(false); case 4: changeEffect(false); break;
break; case 5: changeHue(false); break;
case 2: case 6: changeSat(false); break;
changeEffectIntensity(false); case 7: changePreset(false); break;
break;
case 3:
changePalette(false);
break;
case 4:
changeEffect(false);
break;
case 5:
changeHue(false);
break;
case 6:
changeSat(false);
break;
} }
} }
} }
Enc_A_prev = Enc_A; // Store value of A for next time Enc_A_prev = Enc_A; // Store value of A for next time
loopTime = currentTime; // Updates loopTime
} }
} }
void displayNetworkInfo() { void displayNetworkInfo() {
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
display->networkOverlay(PSTR("NETWORK INFO"), 10000); display->networkOverlay(PSTR("NETWORK INFO"), 10000);
networkShown = true;
#endif #endif
} }
@ -468,12 +438,10 @@ public:
if (display != nullptr) { if (display != nullptr) {
if (display->wakeDisplay()) { if (display->wakeDisplay()) {
// Throw away wake up input // Throw away wake up input
display->redraw(true);
return false; return false;
} }
String line = stateName; display->overlay(stateName, 750, glyph);
//line.trim();
display->center(line, display->getCols());
display->overlay(line.c_str(), 750, glyph);
display->setMarkLine(markedLine, markedCol); display->setMarkLine(markedLine, markedCol);
} }
#endif #endif
@ -491,12 +459,12 @@ public:
void changeBrightness(bool increase) { void changeBrightness(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) { if (display && display->wakeDisplay()) {
display->redraw(true);
// Throw away wake up input // Throw away wake up input
return; return;
} }
#endif #endif
if (increase) bri = (bri + fadeAmount <= 255) ? (bri + fadeAmount) : 255; bri = max(min((increase ? bri+fadeAmount : bri-fadeAmount), 255), 0);
else bri = (bri - fadeAmount >= 0) ? (bri - fadeAmount) : 0;
lampUdated(); lampUdated();
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
display->updateBrightness(); display->updateBrightness();
@ -507,6 +475,7 @@ public:
void changeEffect(bool increase) { void changeEffect(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) { if (display && display->wakeDisplay()) {
display->redraw(true);
// Throw away wake up input // Throw away wake up input
return; return;
} }
@ -523,6 +492,7 @@ public:
void changeEffectSpeed(bool increase) { void changeEffectSpeed(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) { if (display && display->wakeDisplay()) {
display->redraw(true);
// Throw away wake up input // Throw away wake up input
return; return;
} }
@ -538,6 +508,7 @@ public:
void changeEffectIntensity(bool increase) { void changeEffectIntensity(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) { if (display && display->wakeDisplay()) {
display->redraw(true);
// Throw away wake up input // Throw away wake up input
return; return;
} }
@ -553,6 +524,7 @@ public:
void changePalette(bool increase) { void changePalette(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) { if (display && display->wakeDisplay()) {
display->redraw(true);
// Throw away wake up input // Throw away wake up input
return; return;
} }
@ -569,13 +541,13 @@ public:
void changeHue(bool increase){ void changeHue(bool increase){
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) { if (display && display->wakeDisplay()) {
display->redraw(true);
// Throw away wake up input // Throw away wake up input
return; return;
} }
#endif #endif
if (increase) { if (currentHue1<256) currentHue1 += 4; else currentHue1 = 0; } currentHue1 = max(min((increase ? currentHue1+fadeAmount : currentHue1-fadeAmount), 255), 0);
else { if (currentHue1>3) currentHue1 -= 4; else currentHue1 = 256; } colorHStoRGB(currentHue1*256, currentSat1, col);
colorHStoRGB(currentHue1*255, currentSat1, col);
strip.applyToAllSelected = true; strip.applyToAllSelected = true;
strip.setColor(0, colorFromRgbw(col)); strip.setColor(0, colorFromRgbw(col));
lampUdated(); lampUdated();
@ -587,6 +559,7 @@ public:
void changeSat(bool increase){ void changeSat(bool increase){
#ifdef USERMOD_FOUR_LINE_DISPLAY #ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) { if (display && display->wakeDisplay()) {
display->redraw(true);
// Throw away wake up input // Throw away wake up input
return; return;
} }
@ -601,6 +574,29 @@ public:
#endif #endif
} }
void changePreset(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) {
display->redraw(true);
// Throw away wake up input
return;
}
#endif
if (presetHigh && presetLow && presetHigh > presetLow) {
String apireq = F("win&PL=~");
if (!increase) apireq += '-';
apireq += F("&P1=");
apireq += presetLow;
apireq += F("&P2=");
apireq += presetHigh;
handleSet(nullptr, apireq, false);
lampUdated();
}
#ifdef USERMOD_FOUR_LINE_DISPLAY
display->updateRedrawTime();
#endif
}
/* /*
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
@ -652,6 +648,8 @@ public:
top[FPSTR(_DT_pin)] = pinA; top[FPSTR(_DT_pin)] = pinA;
top[FPSTR(_CLK_pin)] = pinB; top[FPSTR(_CLK_pin)] = pinB;
top[FPSTR(_SW_pin)] = pinC; top[FPSTR(_SW_pin)] = pinC;
top[FPSTR(_presetLow)] = presetLow;
top[FPSTR(_presetHigh)] = presetHigh;
DEBUG_PRINTLN(F("Rotary Encoder config saved.")); DEBUG_PRINTLN(F("Rotary Encoder config saved."));
} }
@ -672,7 +670,12 @@ public:
int8_t newCLKpin = top[FPSTR(_CLK_pin)] | pinB; int8_t newCLKpin = top[FPSTR(_CLK_pin)] | pinB;
int8_t newSWpin = top[FPSTR(_SW_pin)] | pinC; int8_t newSWpin = top[FPSTR(_SW_pin)] | pinC;
enabled = top[FPSTR(_enabled)] | enabled; presetHigh = top[FPSTR(_presetHigh)] | presetHigh;
presetLow = top[FPSTR(_presetLow)] | presetLow;
presetHigh = MIN(250,MAX(0,presetHigh));
presetLow = MIN(250,MAX(0,presetLow));
enabled = top[FPSTR(_enabled)] | enabled;
DEBUG_PRINT(FPSTR(_name)); DEBUG_PRINT(FPSTR(_name));
if (!initDone) { if (!initDone) {
@ -699,7 +702,7 @@ public:
} }
} }
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features // use "return !top["newestParameter"].isNull();" when updating Usermod with new features
return !top[FPSTR(_enabled)].isNull(); return !top[FPSTR(_presetHigh)].isNull();
} }
/* /*
@ -713,8 +716,10 @@ public:
}; };
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
const char RotaryEncoderUIUsermod::_name[] PROGMEM = "Rotary-Encoder"; const char RotaryEncoderUIUsermod::_name[] PROGMEM = "Rotary-Encoder";
const char RotaryEncoderUIUsermod::_enabled[] PROGMEM = "enabled"; const char RotaryEncoderUIUsermod::_enabled[] PROGMEM = "enabled";
const char RotaryEncoderUIUsermod::_DT_pin[] PROGMEM = "DT-pin"; const char RotaryEncoderUIUsermod::_DT_pin[] PROGMEM = "DT-pin";
const char RotaryEncoderUIUsermod::_CLK_pin[] PROGMEM = "CLK-pin"; const char RotaryEncoderUIUsermod::_CLK_pin[] PROGMEM = "CLK-pin";
const char RotaryEncoderUIUsermod::_SW_pin[] PROGMEM = "SW-pin"; const char RotaryEncoderUIUsermod::_SW_pin[] PROGMEM = "SW-pin";
const char RotaryEncoderUIUsermod::_presetHigh[] PROGMEM = "preset-high";
const char RotaryEncoderUIUsermod::_presetLow[] PROGMEM = "preset-low";

View File

@ -355,8 +355,7 @@ uint8_t WS2812FX::getTargetFps() {
} }
void WS2812FX::setTargetFps(uint8_t fps) { void WS2812FX::setTargetFps(uint8_t fps) {
if (fps > 0 && fps <= 120) _targetFps = fps; if (fps > 0 && fps <= 120) _targetFps = fps;
//_targetFps = min(max((int)fps,1),120);
_frametime = 1000 / _targetFps; _frametime = 1000 / _targetFps;
} }

View File

@ -210,6 +210,8 @@ void handleAnalog(uint8_t b)
void handleButton() void handleButton()
{ {
static unsigned long lastRead = 0UL; static unsigned long lastRead = 0UL;
bool analog = false;
unsigned long now = millis();
for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) { for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) {
#ifdef ESP8266 #ifdef ESP8266
@ -220,8 +222,8 @@ void handleButton()
if (usermods.handleButton(b)) continue; // did usermod handle buttons if (usermods.handleButton(b)) continue; // did usermod handle buttons
if ((buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) && millis() - lastRead > 250) { // button is not a button but a potentiometer if ((buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) && now - lastRead > 250) { // button is not a button but a potentiometer
if (b+1 == WLED_MAX_BUTTONS) lastRead = millis(); analog = true;
handleAnalog(b); continue; handleAnalog(b); continue;
} }
@ -233,21 +235,21 @@ void handleButton()
//momentary button logic //momentary button logic
if (isButtonPressed(b)) { //pressed if (isButtonPressed(b)) { //pressed
if (!buttonPressedBefore[b]) buttonPressedTime[b] = millis(); if (!buttonPressedBefore[b]) buttonPressedTime[b] = now;
buttonPressedBefore[b] = true; buttonPressedBefore[b] = true;
if (millis() - buttonPressedTime[b] > WLED_LONG_PRESS) { //long press if (now - buttonPressedTime[b] > WLED_LONG_PRESS) { //long press
if (!buttonLongPressed[b]) longPressAction(b); if (!buttonLongPressed[b]) longPressAction(b);
else if (b) { //repeatable action (~3 times per s) on button > 0 else if (b) { //repeatable action (~3 times per s) on button > 0
longPressAction(b); longPressAction(b);
buttonPressedTime[b] = millis() - WLED_LONG_REPEATED_ACTION; //300ms buttonPressedTime[b] = now - WLED_LONG_REPEATED_ACTION; //300ms
} }
buttonLongPressed[b] = true; buttonLongPressed[b] = true;
} }
} else if (!isButtonPressed(b) && buttonPressedBefore[b]) { //released } else if (!isButtonPressed(b) && buttonPressedBefore[b]) { //released
long dur = millis() - buttonPressedTime[b]; long dur = now - buttonPressedTime[b];
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} //too short "press", debounce if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} //too short "press", debounce
bool doublePress = buttonWaitTime[b]; //did we have a short press before? bool doublePress = buttonWaitTime[b]; //did we have a short press before?
buttonWaitTime[b] = 0; buttonWaitTime[b] = 0;
@ -261,7 +263,7 @@ void handleButton()
if (doublePress) { if (doublePress) {
doublePressAction(b); doublePressAction(b);
} else { } else {
buttonWaitTime[b] = millis(); buttonWaitTime[b] = now;
} }
} }
} }
@ -270,11 +272,12 @@ void handleButton()
} }
//if 350ms elapsed since last short press release it is a short press //if 350ms elapsed since last short press release it is a short press
if (buttonWaitTime[b] && millis() - buttonWaitTime[b] > WLED_DOUBLE_PRESS && !buttonPressedBefore[b]) { if (buttonWaitTime[b] && now - buttonWaitTime[b] > WLED_DOUBLE_PRESS && !buttonPressedBefore[b]) {
buttonWaitTime[b] = 0; buttonWaitTime[b] = 0;
shortPressAction(b); shortPressAction(b);
} }
} }
if (analog) lastRead = now;
} }
void handleIO() void handleIO()

View File

@ -86,10 +86,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
Bus::setAutoWhiteMode(hw_led[F("rgbwm")] | Bus::getAutoWhiteMode()); Bus::setAutoWhiteMode(hw_led[F("rgbwm")] | Bus::getAutoWhiteMode());
CJSON(correctWB, hw_led["cct"]); CJSON(correctWB, hw_led["cct"]);
CJSON(cctFromRgb, hw_led[F("cr")]); CJSON(cctFromRgb, hw_led[F("cr")]);
CJSON(strip.cctBlending, hw_led[F("cb")]); CJSON(strip.cctBlending, hw_led[F("cb")]);
Bus::setCCTBlend(strip.cctBlending); Bus::setCCTBlend(strip.cctBlending);
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
//strip.setTargetFps(hw_led["fps"].isNull() ? WLED_FPS : hw_led["fps"].as<byte>());
JsonArray ins = hw_led["ins"]; JsonArray ins = hw_led["ins"];
@ -371,7 +370,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(timerMinutes[it], timer["min"]); CJSON(timerMinutes[it], timer["min"]);
CJSON(timerMacro[it], timer["macro"]); CJSON(timerMacro[it], timer["macro"]);
byte dowPrev = timerWeekday[it]; byte dowPrev = timerWeekday[it];
//note: act is currently only 0 or 1. //note: act is currently only 0 or 1.
//the reason we are not using bool is that the on-disk type in 0.11.0 was already int //the reason we are not using bool is that the on-disk type in 0.11.0 was already int
int actPrev = timerWeekday[it] & 0x01; int actPrev = timerWeekday[it] & 0x01;
@ -382,8 +381,15 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
if (act) timerWeekday[it]++; if (act) timerWeekday[it]++;
} }
if (it<8) { if (it<8) {
CJSON(timerMonth[it], timer[F("mon")]); JsonObject start = timer["start"];
CJSON(timerDay[it], timer[F("day")]); byte startm = start["mon"];
if (startm) timerMonth[it] = (startm << 4);
CJSON(timerDay[it], start["day"]);
JsonObject end = timer["end"];
CJSON(timerDayEnd[it], end["day"]);
byte endm = end["mon"];
if (startm) timerMonth[it] += endm & 0x0F;
if (!(timerMonth[it] & 0x0F)) timerMonth[it] += 12; //default end month to 12
} }
it++; it++;
} }
@ -745,8 +751,12 @@ void serializeConfig() {
timers_ins0["macro"] = timerMacro[i]; timers_ins0["macro"] = timerMacro[i];
timers_ins0[F("dow")] = timerWeekday[i] >> 1; timers_ins0[F("dow")] = timerWeekday[i] >> 1;
if (i<8) { if (i<8) {
timers_ins0[F("mon")] = timerMonth[i]; JsonObject start = timers_ins0.createNestedObject("start");
timers_ins0[F("day")] = timerDay[i]; start["mon"] = (timerMonth[i] >> 4) & 0xF;
start["day"] = timerDay[i];
JsonObject end = timers_ins0.createNestedObject("end");
end["mon"] = timerMonth[i] & 0xF;
end["day"] = timerDayEnd[i];
} }
} }

View File

@ -537,7 +537,6 @@ img {
#gwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #0f0); } #gwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #0f0); }
#bwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #00f); } #bwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #00f); }
#wwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #fff); } #wwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #fff); }
/*#vwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #fff); }*/
#kwrap .sliderdisplay { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff); } #kwrap .sliderdisplay { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff); }
#wbal .sliderdisplay { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff); } #wbal .sliderdisplay { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff); }

View File

@ -15,7 +15,7 @@ var csel = 0;
var currentPreset = -1, prevPS = -1; var currentPreset = -1, prevPS = -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, wW;
var tr = 7; var tr = 7;
var d = document; var d = document;
var palettesData; var palettesData;
@ -198,15 +198,15 @@ function onLoad()
fetch((loc?`http://${locip}`:'.') + "/holidays.json", { // may be loaded from external source fetch((loc?`http://${locip}`:'.') + "/holidays.json", { // may be loaded from external source
method: 'get' method: 'get'
}) })
.then(res => { .then((res)=>{
//if (!res.ok) showErrorToast(); //if (!res.ok) showErrorToast();
return res.json(); return res.json();
}) })
.then(json => { .then((json)=>{
if (Array.isArray(json)) hol = json; if (Array.isArray(json)) hol = json;
//TODO: do some parsing first //TODO: do some parsing first
}) })
.catch(function (error) { .catch((e)=>{
console.log("holidays.json does not contain array of holidays. Defaults loaded."); console.log("holidays.json does not contain array of holidays. Defaults loaded.");
}) })
.finally(()=>{ .finally(()=>{
@ -421,9 +421,8 @@ function loadPresets(callback = null)
pJson = json; pJson = json;
populatePresets(); populatePresets();
}) })
.catch(function (error) { .catch((e)=>{
showToast(error, true); showToast(e, true);
console.log(error);
presetError(false); presetError(false);
}) })
.finally(()=>{ .finally(()=>{
@ -438,17 +437,17 @@ function loadPalettes(callback = null)
fetch(url, { fetch(url, {
method: 'get' method: 'get'
}) })
.then(res => { .then((res)=>{
if (!res.ok) showErrorToast(); if (!res.ok) showErrorToast();
return res.json(); return res.json();
}) })
.then(json => { .then((json)=>{
clearErrorToast(); clearErrorToast();
lJson = Object.entries(json); lJson = Object.entries(json);
populatePalettes(); populatePalettes();
}) })
.catch(function (error) { .catch((e)=>{
showToast(error, true); showToast(e, true);
presetError(false); presetError(false);
}) })
.finally(()=>{ .finally(()=>{
@ -464,17 +463,17 @@ function loadFX(callback = null)
fetch(url, { fetch(url, {
method: 'get' method: 'get'
}) })
.then(res => { .then((res)=>{
if (!res.ok) showErrorToast(); if (!res.ok) showErrorToast();
return res.json(); return res.json();
}) })
.then(json => { .then((json)=>{
clearErrorToast(); clearErrorToast();
eJson = Object.entries(json); eJson = Object.entries(json);
populateEffects(); populateEffects();
}) })
.catch(function (error) { .catch((e)=>{
showToast(error, true); showToast(e, true);
presetError(false); presetError(false);
}) })
.finally(()=>{ .finally(()=>{
@ -490,20 +489,20 @@ function loadFXData(callback = null)
fetch(url, { fetch(url, {
method: 'get' method: 'get'
}) })
.then(res => { .then((res)=>{
if (!res.ok) showErrorToast(); if (!res.ok) showErrorToast();
return res.json(); return res.json();
}) })
.then(json => { .then((json)=>{
clearErrorToast(); clearErrorToast();
fxdata = json||[]; fxdata = json||[];
// add default value for Solid // add default value for Solid
fxdata.shift() fxdata.shift()
fxdata.unshift("@;!;"); fxdata.unshift("@;!;");
}) })
.catch(function (error) { .catch((e)=>{
fxdata = []; fxdata = [];
showToast(error, true); showToast(e, true);
}) })
.finally(()=>{ .finally(()=>{
if (callback) callback(); if (callback) callback();
@ -910,17 +909,16 @@ function loadNodes()
fetch(url, { fetch(url, {
method: 'get' method: 'get'
}) })
.then(res => { .then((res)=>{
if (!res.ok) showToast('Could not load Node list!', true); if (!res.ok) showToast('Could not load Node list!', true);
return res.json(); return res.json();
}) })
.then(json => { .then((json)=>{
clearErrorToast(); clearErrorToast();
populateNodes(lastinfo, json); populateNodes(lastinfo, json);
}) })
.catch(function (error) { .catch((e)=>{
showToast(error, true); showToast(e, true);
console.log(error);
}); });
} }
@ -1074,8 +1072,8 @@ function cmpP(a, b)
function makeWS() { function makeWS() {
if (ws) return; if (ws) return;
ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws'); ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws');
ws.onmessage = function(event) { ws.onmessage = (e)=>{
var json = JSON.parse(event.data); var json = JSON.parse(e.data);
if (json.leds) return; //liveview packet if (json.leds) return; //liveview packet
clearTimeout(jsonTimeout); clearTimeout(jsonTimeout);
jsonTimeout = null; jsonTimeout = null;
@ -1095,11 +1093,12 @@ function makeWS() {
displayRover(i, s); displayRover(i, s);
readState(s); readState(s);
}; };
ws.onclose = function(event) { ws.onclose = (e)=>{
gId('connind').style.backgroundColor = "var(--c-r)"; gId('connind').style.backgroundColor = "var(--c-r)";
ws = null; ws = null;
if (lastinfo.ws > -1) setTimeout(makeWS,500); //retry WS connection
} }
ws.onopen = function(event) { ws.onopen = (e)=>{
ws.send("{'v':true}"); ws.send("{'v':true}");
reqsLegal = true; reqsLegal = true;
clearErrorToast(); clearErrorToast();
@ -1236,7 +1235,7 @@ function setSliderAndColorControl(idx, applyDef=false)
if (i==0) { if (applyDef) gId("sliderSpeed").value = v; obj.seg.sx = v; } if (i==0) { if (applyDef) gId("sliderSpeed").value = v; obj.seg.sx = v; }
else if (i==1) { if (applyDef) gId("sliderIntensity").value = v; obj.seg.ix = v; } else if (i==1) { if (applyDef) gId("sliderIntensity").value = v; obj.seg.ix = v; }
else { if (applyDef) gId("sliderC"+(i-1)).value = v; obj.seg["C"+(i-1)] = v} else { if (applyDef) gId("sliderC"+(i-1)).value = v; obj.seg["C"+(i-1)] = v}
slOnOff[i] = slOnOff[i].substring(0,dPos-1); slOnOff[i] = slOnOff[i].substring(0,dPos);
} }
if (slOnOff.length>i && slOnOff[i]!="!") label.innerHTML = slOnOff[i]; if (slOnOff.length>i && slOnOff[i]!="!") label.innerHTML = slOnOff[i];
else if (i==0) label.innerHTML = "Effect speed"; else if (i==0) label.innerHTML = "Effect speed";
@ -1389,9 +1388,9 @@ function requestJson(command=null)
readState(s); readState(s);
reqsLegal = true; reqsLegal = true;
}) })
.catch(function (error) { .catch((e)=>{
showToast(error, true); showToast(e, true);
console.log(error); console.log(e);
}); });
} }
@ -2335,12 +2334,12 @@ function move(e)
} }
function showNodes() { function showNodes() {
gId('buttonNodes').style.display = (lastinfo.ndc > 0 && (w > 797 || (w > 539 && w < 720))) ? "block":"none"; gId('buttonNodes').style.display = (lastinfo.ndc > 0 && (wW > 797 || (wW > 539 && wW < 720))) ? "block":"none";
} }
function size() function size()
{ {
w = window.innerWidth; wW = window.innerWidth;
showNodes(); showNodes();
var h = gId('top').clientHeight; var h = gId('top').clientHeight;
sCol('--th', h + "px"); sCol('--th', h + "px");
@ -2357,8 +2356,8 @@ function togglePcMode(fromB = false)
localStorage.setItem('pcm', pcModeA); localStorage.setItem('pcm', pcModeA);
pcMode = pcModeA; pcMode = pcModeA;
} }
if (w < 1250 && !pcMode) return; if (wW < 1250 && !pcMode) return;
if (!fromB && ((w < 1250 && lastw < 1250) || (w >= 1250 && lastw >= 1250))) return; if (!fromB && ((wW < 1250 && lastw < 1250) || (wW >= 1250 && lastw >= 1250))) return;
openTab(0, true); openTab(0, true);
if (w < 1250) {pcMode = false;} if (w < 1250) {pcMode = false;}
else if (pcModeA && !fromB) pcMode = pcModeA; else if (pcModeA && !fromB) pcMode = pcModeA;
@ -2367,7 +2366,7 @@ function togglePcMode(fromB = false)
gId('bot').style.height = (pcMode && !cfg.comp.pcmbot) ? "0":"auto"; gId('bot').style.height = (pcMode && !cfg.comp.pcmbot) ? "0":"auto";
sCol('--bh', gId('bot').clientHeight + "px"); sCol('--bh', gId('bot').clientHeight + "px");
_C.style.width = (pcMode)?'100%':'400%'; _C.style.width = (pcMode)?'100%':'400%';
lastw = w; lastw = wW;
} }
function mergeDeep(target, ...sources) function mergeDeep(target, ...sources)

View File

@ -353,7 +353,7 @@ ${i+1}:
c += `<option value="7" ${t==7?"selected":""}>Analog</option>`; c += `<option value="7" ${t==7?"selected":""}>Analog</option>`;
c += `<option value="8" ${t==8?"selected":""}>Analog inverted</option>`; c += `<option value="8" ${t==8?"selected":""}>Analog inverted</option>`;
c += `</select>`; c += `</select>`;
c += `<span style="cursor: pointer;" onclick="off('${bt}')">&nbsp;&#215;</span><br>`; c += `<span style="cursor: pointer;" onclick="off('${bt}')">&nbsp;&#x2715;</span><br>`;
gId("btns").innerHTML = c; gId("btns").innerHTML = c;
} }
function tglSi(cs) { function tglSi(cs) {
@ -515,10 +515,10 @@ ${i+1}:
<option value=6>6-key black</option> <option value=6>6-key black</option>
<option value=7>9-key red</option> <option value=7>9-key red</option>
<option value=8>JSON remote</option> <option value=8>JSON remote</option>
</select><span style="cursor: pointer;" onclick="off('IR')">&nbsp;&#215;</span><br> </select><span style="cursor: pointer;" onclick="off('IR')">&nbsp;&#x2715;</span><br>
<div id="json" style="display:none;">JSON file: <input type="file" name="data" accept=".json"><button type="button" class="sml" onclick="uploadFile('/ir.json')">Upload</button><br></div> <div id="json" style="display:none;">JSON file: <input type="file" name="data" accept=".json"><button type="button" class="sml" onclick="uploadFile('/ir.json')">Upload</button><br></div>
<a href="https://kno.wled.ge/interfaces/infrared/" target="_blank">IR info</a><br> <a href="https://kno.wled.ge/interfaces/infrared/" target="_blank">IR info</a><br>
Relay GPIO: <input type="number" min="-1" max="33" name="RL" onchange="UI()" class="xs"> Invert <input type="checkbox" name="RM"><span style="cursor: pointer;" onclick="off('RL')">&nbsp;&#215;</span><br> Relay GPIO: <input type="number" min="-1" max="33" name="RL" onchange="UI()" class="xs"> Invert <input type="checkbox" name="RM"><span style="cursor: pointer;" onclick="off('RL')">&nbsp;&#x2715;</span><br>
<hr style="width:260px"> <hr style="width:260px">
<h3>Defaults</h3> <h3>Defaults</h3>
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br> Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br>

View File

@ -7,6 +7,7 @@
<title>Time Settings</title> <title>Time Settings</title>
<script> <script>
var d=document; var d=document;
var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
function H() function H()
{ {
window.open("https://kno.wled.ge/features/settings/#time-settings"); window.open("https://kno.wled.ge/features/settings/#time-settings");
@ -23,11 +24,14 @@
{ {
return d.getElementById(s); return d.getElementById(s);
} }
function gN(s) {
return d.getElementsByName(s)[0];
}
function expand(o,i) function expand(o,i)
{ {
o.classList.toggle("exp");
var t = gId("WD"+i); var t = gId("WD"+i);
t.style.display = t.style.display!=="none" ? "none" : ""; t.style.display = t.style.display!=="none" ? "none" : "";
o.innerHTML = t.style.display==="none" ? "&#128467;" : "&#x2715;";
} }
function Cs() function Cs()
{ {
@ -50,73 +54,52 @@
} }
function BTa() function BTa()
{ {
var ih="<tr><th>En.</th><th>Hour</th><th>Minute</th><th>Preset</th><th></th></tr>"; var ih="<thead><tr><th>En.</th><th>Hour</th><th>Minute</th><th>Preset</th><th></th></tr></thead>";
for (i=0;i<8;i++) { for (i=0;i<8;i++) {
ih+=`<tr><td><input name="W${i}" id="W${i}" type="hidden"><input id="W${i}0" type="checkbox"></td> ih+=`<tr><td><input name="W${i}" id="W${i}" type="hidden"><input id="W${i}0" type="checkbox"></td>
<td><input name="H${i}" class="xs" type="number" min="0" max="24"></td> <td><input name="H${i}" class="xs" type="number" min="0" max="24"></td>
<td><input name="N${i}" class="xs" type="number" min="0" max="59"></td> <td><input name="N${i}" class="xs" type="number" min="0" max="59"></td>
<td><input name="T${i}" class="s" type="number" min="0" max="250"></td> <td><input name="T${i}" class="s" type="number" min="0" max="250"></td>
<td><button type="button" class="sml" onclick="expand(this,${i})">&gt;</button></td></tr>`; <td><div id="CB${i}" onclick="expand(this,${i})" class="cal">&#128467;</div></td></tr>`;
ih+=`<tr><td colspan=5><div id="WD${i}" style="display:none;">`; ih+=`<tr><td colspan=5><div id="WD${i}" style="display:none;"><hr>Run on weekdays`;
ih+=`<input name="X${i}" id="TMX${i}" type="checkbox" onchange="tglDOW(${i},this.checked)"><label for="TMX${i}">Use DOW</label>`; ih+=`<table><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`
ih+=`<table id="TT${i}" style="width:100%;"><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`
for (j=1;j<8;j++) ih+=`<td><input id="W${i}${j}" type="checkbox"></td>`; for (j=1;j<8;j++) ih+=`<td><input id="W${i}${j}" type="checkbox"></td>`;
ih+=`</tr></table><div id="TD${i}">Date: ih+=`</tr></table>from <select name="M${i}">`;
<select id="TMM${i}" name="M${i}" onchange="chkMon(this,${i})"> for (j=0;j<12;j++) ih+=`<option value="${j+1}">${ms[j]}</option>`;
<option value="0">Every month</option> ih+=`</select><input name="D${i}" class="xs" type="number" min="1" max="31"></input> to <select name="P${i}">`;
<option value="13">Odd month</option> for (j=0;j<12;j++) ih+=`<option value="${j+1}">${ms[j]}</option>`;
<option value="14">Even month</option> ih+=`</select><input name="E${i}" class="xs" type="number" min="1" max="31"></input>
<option value="1">Jan</option> <hr></div></td></tr>`;
<option value="2">Feb</option>
<option value="3">Mar</option>
<option value="4">Apr</option>
<option value="5">May</option>
<option value="6">Jun</option>
<option value="7">Jul</option>
<option value="8">Aug</option>
<option value="9">Sep</option>
<option value="10">Oct</option>
<option value="11">Nov</option>
<option value="12">Dec</option>
</select><select id="TMD${i}" name="D${i}">`;
for (j=1;j<32;j++) ih+=`<option value="${j}">${j}</option>`;
ih+="</select></div><hr></div></td></tr>";
} }
ih+=`<tr><td><input name="W8" id="W8" type="hidden"><input id="W80" type="checkbox"></td> ih+=`<tr><td><input name="W8" id="W8" type="hidden"><input id="W80" type="checkbox"></td>
<td>Sunrise<input name="H8" value="255" type="hidden"></td> <td>Sunrise<input name="H8" value="255" type="hidden"></td>
<td><input name="N8" class="xs" type="number" min="-59" max="59"></td> <td><input name="N8" class="xs" type="number" min="-59" max="59"></td>
<td><input name="T8" class="s" type="number" min="0" max="250"></td> <td><input name="T8" class="s" type="number" min="0" max="250"></td>
<td><button type="button" class="sml" onclick="expand(this,8)">&gt;</button></td></tr><tr><td colspan=5>`; <td><div onclick="expand(this,8)" class="cal">&#128467;</div></td></tr><tr><td colspan=5>`;
ih+=`<div id="WD8"style="display:none;"><table style="width:100%;"><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`; ih+=`<div id="WD8" style="display:none;"><hr><table><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`;
for (j=1;j<8;j++) ih+=`<td><input id="W8${j}" type="checkbox"></td>`; for (j=1;j<8;j++) ih+=`<td><input id="W8${j}" type="checkbox"></td>`;
ih+="</tr></table><hr></div></td></tr>"; ih+="</tr></table><hr></div></td></tr>";
ih+=`<tr><td><input name="W9" id="W9" type="hidden"><input id="W90" type="checkbox"></td> ih+=`<tr><td><input name="W9" id="W9" type="hidden"><input id="W90" type="checkbox"></td>
<td>Sunrise<input name="H9" value="255" type="hidden"></td> <td>Sunset<input name="H9" value="255" type="hidden"></td>
<td><input name="N9" class="xs" type="number" min="-59" max="59"></td> <td><input name="N9" class="xs" type="number" min="-59" max="59"></td>
<td><input name="T9" class="s" type="number" min="0" max="250"></td> <td><input name="T9" class="s" type="number" min="0" max="250"></td>
<td><button type="button" class="sml" onclick="expand(this,9)">&gt;</button></td></tr><tr><td colspan=5>`; <td><div onclick="expand(this,9)" class="cal">&#128467;</div></td></tr><tr><td colspan=5>`;
ih+=`<div id="WD9" style="display:none;"><table style="width:100%;"><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`; ih+=`<div id="WD9" style="display:none;"><hr><table><tr><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr><tr>`;
for (j=1;j<8;j++) ih+=`<td><input id="W9${j}" type="checkbox"></td>`; for (j=1;j<8;j++) ih+=`<td><input id="W9${j}" type="checkbox"></td>`;
ih+="</tr></table><hr></div></td></tr>"; ih+="</tr></table><hr></div></td></tr>";
gId("TMT").innerHTML=ih; gId("TMT").innerHTML=ih;
} }
function tglDOW(i,b)
{
gId("TT"+i).style.display = b ? "table" : "none";
gId("TD"+i).style.display = !b ? "block" : "none";
}
function chkMon(o,i)
{
const m31 = [1,3,5,7,8,10,12,0,13,14];
if (!m31.includes(parseInt(o.value)) && parseInt(gId("TMD"+i).value)>30) gId("TMD"+i).value="30";
if (parseInt(o.value)===2 && parseInt(gId("TMD"+i).value)>28) gId("TMD"+i).value="28";
}
function FC() function FC()
{ {
for(j=0;j<8;j++) for(i=0;i<10;i++)
{ {
for(i=0;i<10;i++) gId("W"+i+j).checked=gId("W"+i).value>>j&1; let wd = gId("W"+i).value;
tglDOW(j,gId('TMX'+j).checked); for(j=0;j<8;j++) {
gId("W"+i+j).checked=wd>>j&1;
}
if ((wd&127) != 127 || (i<8 && (gN("M"+i).value != 1 || gN("D"+i).value != 1 || gN("P"+i).value != 12 || gN("E"+i).value != 31))) {
expand(gId("CB"+i),i); //expand macros with custom DOW or date range set
}
} }
} }
function Wd() function Wd()
@ -154,7 +137,6 @@
//values injected by server while sending HTML //values injected by server while sending HTML
} }
</script> </script>
<!--script src="http://192.168.70.61/settings/settings.js?p=5"></script-->
<style>@import url("style.css");</style> <style>@import url("style.css");</style>
</head> </head>
<body onload="S()"> <body onload="S()">
@ -218,12 +200,12 @@
</div> </div>
Countdown Mode: <input type="checkbox" name="CE"><br> Countdown Mode: <input type="checkbox" name="CE"><br>
Countdown Goal:<br> Countdown Goal:<br>
Date: <nowrap>20<input name="CY" class="xs" type="number" min="0" max="99" required>-<input name="CI" class="xs" type="number" min="1" max="12" required>-<input name="CD" class="xs" type="number" min="1" max="31" required></nowrap><br> Date:&nbsp;<nowrap>20<input name="CY" class="xs" type="number" min="0" max="99" required>-<input name="CI" class="xs" type="number" min="1" max="12" required>-<input name="CD" class="xs" type="number" min="1" max="31" required></nowrap><br>
Time: <nowrap><input name="CH" class="xs" type="number" min="0" max="23" required>:<input name="CM" class="xs" type="number" min="0" max="59" required>:<input name="CS" class="xs" type="number" min="0" max="59" required></nowrap><br> Time:&nbsp;<nowrap><input name="CH" class="xs" type="number" min="0" max="23" required>:<input name="CM" class="xs" type="number" min="0" max="59" required>:<input name="CS" class="xs" type="number" min="0" max="59" required></nowrap><br>
<h3>Macro presets</h3> <h3>Macro presets</h3>
<b>Macros have moved!</b><br> <b>Macros have moved!</b><br>
<i>Presets now also can be used as macros to save both JSON and HTTP API commands.<br> <i>Presets now also can be used as macros to save both JSON and HTTP API commands.<br>
Just enter the preset id below!</i> Just enter the preset ID below!</i>
<i>Use 0 for the default action instead of a preset</i><br> <i>Use 0 for the default action instead of a preset</i><br>
Alexa On/Off Preset: <input name="A0" class="m" type="number" min="0" max="250" required> <input name="A1" class="m" type="number" min="0" max="250" required><br> Alexa On/Off Preset: <input name="A0" class="m" type="number" min="0" max="250" required> <input name="A1" class="m" type="number" min="0" max="250" required><br>
Countdown-Over Preset: <input name="MC" class="m" type="number" min="0" max="250" required><br> Countdown-Over Preset: <input name="MC" class="m" type="number" min="0" max="250" required><br>

View File

@ -102,7 +102,7 @@ button:hover {
.label { .label {
margin: 0; margin: 0;
padding: 8px 0 2px 0; padding: 6px 0 0;
} }
#namelabel { #namelabel {
@ -135,6 +135,7 @@ button:hover {
line-height: 1; line-height: 1;
display: inline-block; display: inline-block;
margin: -2px 0 4px 0; margin: -2px 0 4px 0;
text-shadow: -1px -1px 0 var(--c-3), 1px -1px 0 var(--c-3), -1px 1px 0 var(--c-3), 1px 1px 0 var(--c-3);
} }
.huge { .huge {
@ -343,7 +344,7 @@ button:hover {
} }
#info table .btn, #nodes table .btn { #info table .btn, #nodes table .btn {
margin: 0; margin: 0;
width: 230px; width: 180px;
} }
#info div, #nodes div { #info div, #nodes div {
width: 490px; width: 490px;
@ -378,14 +379,11 @@ img {
.sliderwrap { .sliderwrap {
height: 30px; height: 30px;
width: 225px; width: 250px;
position: relative; position: relative;
margin: 4px 0;
} }
#rwrap .sliderwrap, #Colors .sliderwrap {
#gwrap .sliderwrap,
#bwrap .sliderwrap,
#wwrap .sliderwrap,
#wbal .sliderwrap {
width: 260px; width: 260px;
margin: 10px 0 0; margin: 10px 0 0;
} }
@ -393,18 +391,14 @@ img {
.sliderdisplay { .sliderdisplay {
content:''; content:'';
position: absolute; position: absolute;
top: 13px; left: 8px; right: 8px; top: 10px; left: 8px; right: 8px;
height: 4px; height: 8px;
background: var(--c-4); background: var(--c-4);
border-radius: 16px; border-radius: 16px;
pointer-events: none; pointer-events: none;
z-index: -1; z-index: -1;
} }
#rwrap .sliderdisplay, #Colors .sliderdisplay {
#gwrap .sliderdisplay,
#bwrap .sliderdisplay,
#wwrap .sliderdisplay,
#wbal .sliderdisplay {
height: 28px; height: 28px;
top: 0; bottom: 0; top: 0; bottom: 0;
left: 0; right: 0; left: 0; right: 0;
@ -414,6 +408,7 @@ img {
#gwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #0f0); } #gwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #0f0); }
#bwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #00f); } #bwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #00f); }
#wwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #fff); } #wwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #fff); }
#kwrap .sliderdisplay { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff); }
#wbal .sliderdisplay { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #d4e0ff); } #wbal .sliderdisplay { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #d4e0ff); }
.sliderbubble { .sliderbubble {
@ -448,11 +443,7 @@ input[type=range] {
background-color: transparent; background-color: transparent;
cursor: pointer; cursor: pointer;
} }
#rwrap input[type=range], #Colors input[type=range] {
#gwrap input[type=range],
#bwrap input[type=range],
#wwrap input[type=range],
#wbal input[type=range] {
width: 252px; width: 252px;
margin: 0; margin: 0;
} }
@ -463,46 +454,55 @@ input[type=range]::-webkit-slider-runnable-track {
background: transparent; background: transparent;
} }
input[type=range]::-webkit-slider-thumb { input[type=range]::-webkit-slider-thumb {
height: 16px; border: 2px solid #000;
width: 16px; height: 20px;
width: 20px;
border-radius: 50%; border-radius: 50%;
background: var(--c-f); background: var(--c-f);
cursor: pointer; cursor: pointer;
-webkit-appearance: none; -webkit-appearance: none;
margin-top: 7px; margin-top: 4px;
} }
input[type=range]::-moz-range-track { input[type=range]::-moz-range-track {
width: 100%; width: 100%;
height: 30px; height: 30px;
background-color: rgba(0, 0, 0, 0); background-color: var(--c-0);
} }
input[type=range]::-moz-range-thumb { input[type=range]::-moz-range-thumb {
border: 0px solid rgba(0, 0, 0, 0); border: 2px solid var(--c-3);
height: 16px; height: 20px;
width: 16px; width: 20px;
border-radius: 50%; border-radius: 50%;
background: var(--c-f); background: var(--c-f);
transform: translateY(5px); transform: translateY(5px);
} }
#rwrap input[type=range]::-webkit-slider-thumb, #Colors input[type=range]::-webkit-slider-thumb {
#gwrap input[type=range]::-webkit-slider-thumb,
#bwrap input[type=range]::-webkit-slider-thumb,
#wwrap input[type=range]::-webkit-slider-thumb,
#wbal input[type=range]::-webkit-slider-thumb {
height: 18px;
width: 18px;
border: 2px solid #000; border: 2px solid #000;
margin-top: 5px;
} }
#rwrap input[type=range]::-moz-range-thumb, #Colors input[type=range]::-moz-range-thumb {
#gwrap input[type=range]::-moz-range-thumb,
#bwrap input[type=range]::-moz-range-thumb,
#wwrap input[type=range]::-moz-range-thumb,
#wbal input[type=range]::-moz-range-thumb {
border: 2px solid var(--c-1); border: 2px solid var(--c-1);
} }
#wwrap, #wbal {
display: block; #Presets .list {
max-height: 215px;
overflow-y: scroll;
overflow-x: hidden;
width: 280px;
margin: 0 0 0 20px;
-ms-overflow-style: none;
scrollbar-width: none; /* Firefox */
}
/* Hide scrollbar for Chrome, Safari and Opera */
#Presets .list::-webkit-scrollbar {
display: none;
}
#Segments .sliderwrap{
width: 225px;
}
#picker, #rgbwrap, #kwrap, #vwrap, #wwrap, #wbal {
display: none;
} }
.hd { .hd {
@ -516,11 +516,6 @@ input[type=range]::-moz-range-thumb {
#picker { #picker {
width: 260px; width: 260px;
display: none;
}
#rgbwrap, #wwrap, #wbal {
display: none;
} }
#picker, #csl, #segcont { #picker, #csl, #segcont {
@ -553,6 +548,7 @@ input[type=range]::-moz-range-thumb {
width: 42px; width: 42px;
height: 42px; height: 42px;
margin: 4px; margin: 4px;
padding: 0;
} }
#fxBtn, #palBtn { #fxBtn, #palBtn {
@ -632,6 +628,7 @@ input[type=number]::-webkit-outer-spin-button {
width: 44px; width: 44px;
height: 44px; height: 44px;
margin: 5px; margin: 5px;
padding: 0;
} }
.xxs-w { .xxs-w {
@ -639,6 +636,7 @@ input[type=number]::-webkit-outer-spin-button {
margin: 2px; margin: 2px;
width: 50px; width: 50px;
height: 50px; height: 50px;
padding: 0;
} }
.qcs, .xxs { .qcs, .xxs {
@ -652,7 +650,6 @@ input[type=number]::-webkit-outer-spin-button {
.pwr { .pwr {
color: var(--c-6); color: var(--c-6);
/*transform: translate(2px, 3px);*/
cursor: pointer; cursor: pointer;
} }
@ -668,8 +665,8 @@ input[type=number]::-webkit-outer-spin-button {
} }
.schkl { .schkl {
padding: 2px 2px 2px 16px; width: 24px;
margin: 0; top: -2px;
} }
.check input, .radio input { .check input, .radio input {
@ -808,20 +805,17 @@ input[type=number]::-webkit-outer-spin-button {
position: absolute; position: absolute;
width: 284px; width: 284px;
z-index: 1; z-index: 1;
height: 266px; height: 260px;
overflow-y: scroll; overflow-y: scroll;
overflow-x: hidden; overflow-x: hidden;
padding: 0 18px; padding: 0 18px;
margin-top: 10px; margin-top: 10px;
-ms-overflow-style: none;
scrollbar-width: none; /* Firefox */
} }
/* Hide scrollbar for Chrome, Safari and Opera */
.fndIcn { /* needed for magnifier SVG, can be removed when magnifier is in Wicons font */ .dd-content::-webkit-scrollbar {
width: 24px; display: none;
height: 24px;
stroke: var(--c-e);
stroke-width: 3px;
fill-opacity: 0;
margin-top: 1px;
} }
.fnd { .fnd {
@ -832,39 +826,44 @@ input[type=number]::-webkit-outer-spin-button {
margin: 0 auto; margin: 0 auto;
} }
div.fnd div { .search-icon {
position: absolute; position: absolute;
top: 10px; top: 10px;
left: 13px; left: 13px;
pointer-events: none;
width: 24px;
height: 24px;
margin-top: -1px;
z-index: 1; z-index: 1;
} }
div.fnd span { .clear-icon {
position: absolute; position: absolute;
display: none; display: none;
top: 10px; top: 10px;
right: 13px; right: 13px;
cursor: pointer; cursor: pointer;
margin-top: -1px;
z-index: 1; z-index: 1;
} }
input[type="text"].fnd { input[type=text].fnd {
display: block; display: block;
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
padding: 8px 44px 8px 44px; padding: 8px 48px 8px 48px;
margin: 5px auto 0; margin: 5px auto 0;
text-align: left; text-align: left;
border-radius: 20px; border-radius: 25px;
background-color: var(--c-2); background-color: var(--c-2);
border: 1px solid var(--c-4); border: 1px solid var(--c-4);
} }
input[type="text"].fnd:focus { input[type=text].fnd:focus {
background-color: var(--c-4); background-color: var(--c-4);
} }
input[type="text"].fnd:not(:placeholder-shown), input[type="text"].fnd:hover { input[type=text].fnd:not(:placeholder-shown), input[type=text].fnd:hover {
background-color: var(--c-3); background-color: var(--c-3);
} }

View File

@ -7,10 +7,47 @@
<meta content="yes" name="apple-mobile-web-app-capable"> <meta content="yes" name="apple-mobile-web-app-capable">
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAGACGAAAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAE1JREFUOI1j/P//PwOxgNGeAUMxE9G6cQCKDWAhpADZ2f8PMjBS3QW08QK20KaZC2gfC9hCnqouoNgARgY7zMxAyNlUdQHlXiAlO2MDAD63EVqNHAe0AAAAAElFTkSuQmCC"/> <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAGACGAAAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAE1JREFUOI1j/P//PwOxgNGeAUMxE9G6cQCKDWAhpADZ2f8PMjBS3QW08QK20KaZC2gfC9hCnqouoNgARgY7zMxAyNlUdQHlXiAlO2MDAD63EVqNHAe0AAAAAElFTkSuQmCC"/>
<title>WLED</title> <title>WLED</title>
<script>function feedback(){}</script> <script>
function feedback(){}
// instead of including [script src="iro.js"][/script] and [script src="rangetouch.js"][/script]
// (which would be inlined by nodeJS inliner during minimization and compression) we need to load them dynamically
// the following is needed to load iro.js and rangetouch.js as consecutive requests to allow ESP8266
// to keep up with requests (if requests happent too fast some may not get processed)
// it will also call onLoad() after last is loaded (it was removed from [body onload="onLoad()"]).
var h = document.getElementsByTagName('head')[0];
var l = document.createElement('script');
l.type = 'application/javascript';
l.src = 'iro.js';
l.addEventListener('load', (e) => {
// after iro is loaded initialize global variable
cpick = new iro.ColorPicker("#picker", {
width: 260,
wheelLightness: false,
wheelAngle: 270,
wheelDirection: "clockwise",
layout: [{
component: iro.ui.Wheel,
options: {}
}]
});
cpick.on("input:end", () => {setColor(1);});
cpick.on("color:change", () => {updatePSliders()});
var l = document.createElement('script');
l.type = 'application/javascript';
l.src = 'rangetouch.js';
l.addEventListener('load', (e) => {
// after rangetouch is loaded initialize global variable
ranges = RangeTouch.setup('input[type="range"]', {});
onLoad(); // start processing UI
});
//h.appendChild(l); // if this fires too quickly for ESP8266 use next line
setTimeout(function(){h.appendChild(l)},50);
});
setTimeout(function(){h.appendChild(l)},50);
</script>
<link rel="stylesheet" href="simple.css"> <link rel="stylesheet" href="simple.css">
</head> </head>
<body onload="onLoad()"> <body>
<div id="cv" class="overlay">Loading WLED UI...</div> <div id="cv" class="overlay">Loading WLED UI...</div>
<noscript><div class="overlay" style="opacity:1;">Sorry, WLED UI needs JavaScript!</div></noscript> <noscript><div class="overlay" style="opacity:1;">Sorry, WLED UI needs JavaScript!</div></noscript>
@ -24,7 +61,7 @@
<button id="buttonNodes" onclick="toggleNodes()"><i class="icons">&#xe22d;</i><p class="tab-label">Nodes</p></button></div> <button id="buttonNodes" onclick="toggleNodes()"><i class="icons">&#xe22d;</i><p class="tab-label">Nodes</p></button></div>
<button onclick="window.location.href='/settings';"><i class="icons">&#xe0a2;</i><p class="tab-label">Config</p></button> <button onclick="window.location.href='/settings';"><i class="icons">&#xe0a2;</i><p class="tab-label">Config</p></button>
<button id="buttonCP" onclick="tglCP()"><i class="icons">&#xe2b3;</i><p class="tab-label">Expand</p></button> <button id="buttonCP" onclick="tglCP()"><i class="icons">&#xe2b3;</i><p class="tab-label">Expand</p></button>
<button id="buttonBri" onclick="tglBri()"><i class="icons">&#xe2a6;</i><p class="tab-label">Brightness</p></button> <!--button id="buttonBri" onclick="tglBri()"><i class="icons">&#xe2a6;</i><p class="tab-label">Brightness</p></button-->
</div> </div>
<div id="briwrap"> <div id="briwrap">
<p class="label hd">Global brightness</p> <p class="label hd">Global brightness</p>
@ -42,60 +79,88 @@
<div class ="container"> <div class ="container">
<div class="tabcontent"> <div class="tabcontent">
<div id="qcs-w" class="center"> <div id="QuickLoad" class="center">
<div class="qcs" onclick="pC('#ff0000');" title="Red" style="background-color:#ff0000;"></div> <p class="label h">Quick Load</p>
<div class="qcs" onclick="pC('#ffa000');" title="Orange" style="background-color:#ffa000;"></div> <div id="pql"></div>
<div class="qcs" onclick="pC('#ffc800');" title="Yellow" style="background-color:#ffc800;"></div>
<div class="qcs" onclick="pC('#ffe0a0');" title="Warm White" style="background-color:#ffe0a0;"></div>
<div class="qcs" onclick="pC('#ffffff');" title="White" style="background-color:#ffffff;"></div>
<div class="qcs qcsb" onclick="pC('#000000');" title="Black" style="background-color:#000000;"></div><br>
<div class="qcs" onclick="pC('#ff00ff');" title="Pink" style="background-color:#ff00ff;"></div>
<div class="qcs" onclick="pC('#0000ff');" title="Blue" style="background-color:#0000ff;"></div>
<div class="qcs" onclick="pC('#00ffc8');" title="Cyan" style="background-color:#00ffc8;"></div>
<div class="qcs" onclick="pC('#08ff00');" title="Green" style="background-color:#08ff00;"></div>
<div class="qcs" onclick="pC('rnd');" title="Random" style="background:linear-gradient(to right, red, orange, yellow, green, blue, purple);transform: translateY(-11px);">R</div>
</div>
<div id="csl" class="center" style="display: none;">
<button class="xxs btn" onclick="selectSlot(0);">1</button>
<button class="xxs btn" onclick="selectSlot(1);">2</button>
<button class="xxs btn" onclick="selectSlot(2);">3</button>
</div> </div>
<div id="picker" class="center"></div> <div id="QCS" class="center">
<p class="label h">Solid color</p>
<div id="rgbwrap" class="center"> <div id="qcs-w" class="center">
<div id="rwrap" class="il"> <div class="qcs" onclick="pC('#ff0000');" title="Red" style="background-color:#ff0000;"></div>
<div class="sliderwrap il"> <div class="qcs" onclick="pC('#ffa000');" title="Orange" style="background-color:#ffa000;"></div>
<input id="sliderR" onchange="fromRgb()" max="255" min="0" type="range" value="128" /> <div class="qcs" onclick="pC('#ffc800');" title="Yellow" style="background-color:#ffc800;"></div>
<div class="sliderdisplay"></div> <div class="qcs" onclick="pC('#ffe0a0');" title="Warm White" style="background-color:#ffe0a0;"></div>
</div> <div class="qcs" onclick="pC('#ffffff');" title="White" style="background-color:#ffffff;"></div>
</div><br> <div class="qcs qcsb" onclick="pC('#000000');" title="Black" style="background-color:#000000;"></div><br>
<div id="gwrap" class="il"> <div class="qcs" onclick="pC('#ff00ff');" title="Pink" style="background-color:#ff00ff;"></div>
<div class="sliderwrap il"> <div class="qcs" onclick="pC('#0000ff');" title="Blue" style="background-color:#0000ff;"></div>
<input id="sliderG" onchange="fromRgb()" max="255" min="0" type="range" value="128" /> <div class="qcs" onclick="pC('#00ffc8');" title="Cyan" style="background-color:#00ffc8;"></div>
<div class="sliderdisplay"></div> <div class="qcs" onclick="pC('#08ff00');" title="Green" style="background-color:#08ff00;"></div>
</div> <div class="qcs" onclick="pC('rnd');" title="Random" style="background:linear-gradient(to right, red, orange, yellow, green, blue, purple);transform: translateY(-11px);">R</div>
</div><br>
<div id="bwrap" class="il">
<div class="sliderwrap il">
<input id="sliderB" onchange="fromRgb()" max="255" min="0" type="range" value="128" />
<div class="sliderdisplay"></div>
</div>
</div><br>
</div>
<div id="wwrap" class="center">
<p class="label hd">White channel</p>
<div class="sliderwrap il">
<input id="sliderW" onchange="setColor(0)" max="255" min="0" type="range" value="128" />
<div class="sliderdisplay"></div>
</div> </div>
</div> </div>
<div id="wbal">
<p class="labels hd">White balance</p> <div id="picker" class="center"></div>
<div class="sliderwrap il">
<input id="sliderA" onchange="setBalance(this.value)" max="255" min="0" type="range" value="128" /> <div id="Colors" class="center">
<div class="sliderdisplay"></div> <div id="vwrap">
<!--p class="label h">Value</p-->
<div class="sliderwrap il">
<input id="sliderV" class="noslide" oninput="fromV()" onchange="setColor(0)" max="100" min="0" type="range" value="100" step="any" />
<div class="sliderdisplay"></div>
</div><br>
</div>
<div id="kwrap">
<!--p class="label h">Temperature</p-->
<div class="sliderwrap il">
<input id="sliderK" class="noslide" oninput="fromK()" onchange="setColor(0)" max="10091" min="1900" type="range" value="6550" />
<div class="sliderdisplay"></div>
</div>
</div>
<div id="rgbwrap" class="center">
<p class="label h">RGB channels</p>
<div id="rwrap" class="il">
<div class="sliderwrap il">
<input id="sliderR" onchange="fromRgb()" max="255" min="0" type="range" value="128" />
<div class="sliderdisplay"></div>
</div>
</div><br>
<div id="gwrap" class="il">
<div class="sliderwrap il">
<input id="sliderG" onchange="fromRgb()" max="255" min="0" type="range" value="128" />
<div class="sliderdisplay"></div>
</div>
</div><br>
<div id="bwrap" class="il">
<div class="sliderwrap il">
<input id="sliderB" onchange="fromRgb()" max="255" min="0" type="range" value="128" />
<div class="sliderdisplay"></div>
</div>
</div><br>
</div>
<div id="wwrap" class="center">
<p class="label h">White channel</p>
<div class="sliderwrap il">
<input id="sliderW" onchange="setColor(0)" max="255" min="0" type="range" value="128" />
<div class="sliderdisplay"></div>
</div>
</div>
<div id="wbal">
<p class="label h">White balance</p>
<div class="sliderwrap il">
<input id="sliderA" onchange="setBalance(this.value)" max="255" min="0" type="range" value="128" />
<div class="sliderdisplay"></div>
</div>
</div>
</div>
<div id="Slots" class="center">
<p class="label h">Color slots</p>
<div id="csl" class="center" style="display: none;">
<button class="xxs btn" onclick="selectSlot(0);">1</button>
<button class="xxs btn" onclick="selectSlot(1);">2</button>
<button class="xxs btn" onclick="selectSlot(2);">3</button>
</div> </div>
</div> </div>
@ -103,17 +168,12 @@
<div id="segcont"></div> <div id="segcont"></div>
</div> </div>
<div id="QuickLoad" class="center"> <div id="Presets" class="center">
<p class="label h">Quick Load</p>
<div id="pql"></div>
</div>
<div id="Presets" class="center" style="display:none;">
<p class="label h">Presets</p> <p class="label h">Presets</p>
<div class="fnd"> <div class="fnd">
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'pcont')" onfocus="search(this)" /> <input type="text" class="fnd" placeholder="Search" oninput="search(this,'pcont')" onfocus="search(this)" />
<span onclick="clean(this)" class="icons">&#xe38f;</span> <i class="icons clear-icon" onclick="clean(this);">&#xe38f;</i>
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div> <i class="icons search-icon">&#xe0a1;</i>
</div> </div>
<div id="pcont" class="list"></div> <div id="pcont" class="list"></div>
</div> </div>
@ -142,8 +202,8 @@
<div id="fxDropdown" class="dd-content"> <div id="fxDropdown" class="dd-content">
<div class="fnd"> <div class="fnd">
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'fxlist')" onfocus="search(this)" /> <input type="text" class="fnd" placeholder="Search" oninput="search(this,'fxlist')" onfocus="search(this)" />
<span onclick="clean(this)" class="icons">&#xe38f;</span> <i class="icons clear-icon" onclick="clean(this);">&#xe38f;</i>
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div> <i class="icons search-icon">&#xe0a1;</i>
</div> </div>
<div id="fxlist" class="list"> <div id="fxlist" class="list">
<div class="lstI" data-id="0" onClick="setX(0)"><a href="#0" onClick="setX(0)">Solid</a></div> <div class="lstI" data-id="0" onClick="setX(0)"><a href="#0" onClick="setX(0)">Solid</a></div>
@ -152,8 +212,8 @@
<div id="palDropdown" class="dd-content"> <div id="palDropdown" class="dd-content">
<div class="fnd"> <div class="fnd">
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'pallist')" onfocus="search(this)" /> <input type="text" class="fnd" placeholder="Search" oninput="search(this,'pallist')" onfocus="search(this)" />
<span onclick="clean(this)" class="icons">&#xe38f;</span> <i class="icons clear-icon" onclick="clean(this);">&#xe38f;</i>
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div> <i class="icons search-icon">&#xe0a1;</i>
</div> </div>
<div id="pallist" class="list"> <div id="pallist" class="list">
<div class="lstI" data-id="0" onClick="setPalette(0)"><a href="#0" onClick="setPalette(0)">Default</a><div class="lstIprev"></div></div> <div class="lstI" data-id="0" onClick="setPalette(0)"><a href="#0" onClick="setPalette(0)">Default</a><div class="lstIprev"></div></div>

View File

@ -1,7 +1,7 @@
//page js //page js
var loc = false, locip; var loc = false, locip;
var noNewSegs = false; var noNewSegs = false;
var isOn = false, isInfo = false, isNodes = false, isRgbw = false; var isOn = false, isInfo = false, isNodes = false, isRgbw = false, cct = false;
var whites = [0,0,0]; var whites = [0,0,0];
var selColors; var selColors;
var powered = [true]; var powered = [true];
@ -11,16 +11,15 @@ var csel = 0;
var currentPreset = -1; 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 lastw = 0;
var tr = 7; var tr = 7;
var d = document; var d = document;
const ranges = RangeTouch.setup('input[type="range"]', {});
var palettesData; var palettesData;
var fxdata = [];
var pJson = {}, eJson = {}, lJson = {}; var pJson = {}, eJson = {}, lJson = {};
var pN = "", pI = 0, pNum = 0; var pN = "", pI = 0, pNum = 0;
var pmt = 1, pmtLS = 0, pmtLast = 0; var pmt = 1, pmtLS = 0, pmtLast = 0;
var lastinfo = {}; var lastinfo = {};
var ws; var ws, cpick, ranges;
var cfg = { var cfg = {
theme:{base:"dark", bg:{url:""}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}}, theme:{base:"dark", bg:{url:""}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}},
comp :{colors:{picker: true, rgb: false, quick: true, hex: false}, labels:true, pcmbot:false, pid:true, seglen:false} comp :{colors:{picker: true, rgb: false, quick: true, hex: false}, labels:true, pcmbot:false, pid:true, seglen:false}
@ -33,30 +32,6 @@ var hol = [
[2024,2,31,2,"https://aircoookie.github.io/easter.png"] [2024,2,31,2,"https://aircoookie.github.io/easter.png"]
]; ];
var cpick = new iro.ColorPicker("#picker", {
width: 260,
wheelLightness: false,
wheelAngle: 90,
layout: [
{
component: iro.ui.Wheel,
options: {}
},
{
component: iro.ui.Slider,
options: { sliderType: 'value' }
}/*,
{
component: iro.ui.Slider,
options: {
sliderType: 'kelvin',
minTemperature: 2100,
maxTemperature: 10000
}
}*/
]
});
function handleVisibilityChange() {if (!d.hidden && new Date () - lastUpdate > 3000) requestJson();} function handleVisibilityChange() {if (!d.hidden && new Date () - lastUpdate > 3000) requestJson();}
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);}
@ -71,7 +46,8 @@ function applyCfg()
if (bg) sCol('--c-1', bg); if (bg) sCol('--c-1', bg);
var ccfg = cfg.comp.colors; var ccfg = cfg.comp.colors;
//gId('picker').style.display = "none"; // ccfg.picker ? "block":"none"; //gId('picker').style.display = "none"; // ccfg.picker ? "block":"none";
gId('rgbwrap').style.display = ccfg.rgb ? "block":"none"; //gId('vwrap').style.display = "none"; // ccfg.picker ? "block":"none";
//gId('rgbwrap').style.display = ccfg.rgb ? "block":"none";
gId('qcs-w').style.display = ccfg.quick ? "block":"none"; gId('qcs-w').style.display = ccfg.quick ? "block":"none";
var l = cfg.comp.labels; //l = false; var l = cfg.comp.labels; //l = false;
var e = d.querySelectorAll('.tab-label'); var e = d.querySelectorAll('.tab-label');
@ -200,14 +176,14 @@ async function onLoad()
fetch((loc?`http://${locip}`:'.') + "/holidays.json", { fetch((loc?`http://${locip}`:'.') + "/holidays.json", {
method: 'get' method: 'get'
}) })
.then(res => { .then((res)=>{
return res.json(); return res.json();
}) })
.then(json => { .then((json)=>{
if (Array.isArray(json)) hol = json; if (Array.isArray(json)) hol = json;
//TODO: do some parsing first //TODO: do some parsing first
}) })
.catch(function(error){ .catch((e)=>{
console.log("holidays.json does not contain array of holidays. Defaults loaded."); console.log("holidays.json does not contain array of holidays. Defaults loaded.");
}) })
.finally(()=>{ .finally(()=>{
@ -228,7 +204,7 @@ async function onLoad()
var cd = gId('csl').children; var cd = gId('csl').children;
for (var i = 0; i < cd.length; i++) cd[i].style.backgroundColor = "rgb(0, 0, 0)"; for (var i = 0; i < cd.length; i++) cd[i].style.backgroundColor = "rgb(0, 0, 0)";
selectSlot(0); selectSlot(0);
cpick.on("input:end", function() { cpick.on("input:end", ()=>{
setColor(1); setColor(1);
}); });
pmtLS = localStorage.getItem('wledPmt'); pmtLS = localStorage.getItem('wledPmt');
@ -237,13 +213,12 @@ async function onLoad()
loadPalettes(()=>{ loadPalettes(()=>{
loadPalettesData(redrawPalPrev); loadPalettesData(redrawPalPrev);
loadFX(()=>{ loadFX(()=>{
loadFXData();
loadPresets(()=>{ loadPresets(()=>{
//if (isObj(lastinfo) && isEmpty(lastinfo)) loadInfo(requestJson); // if not filled by WS
requestJson(); requestJson();
}); });
}); });
}); });
//updateUI(true);
d.addEventListener("visibilitychange", handleVisibilityChange, false); d.addEventListener("visibilitychange", handleVisibilityChange, false);
size(); size();
@ -264,7 +239,8 @@ function showToast(text, error = false)
x.className = error ? "error":"show"; x.className = error ? "error":"show";
clearTimeout(timeout); clearTimeout(timeout);
x.style.animation = 'none'; x.style.animation = 'none';
timeout = setTimeout(function(){ x.classList.remove("show"); }, 2900); timeout = setTimeout(()=>{ x.classList.remove("show"); }, 2900);
if (error) console.log(text);
} }
function showErrorToast() function showErrorToast()
@ -425,6 +401,34 @@ function loadFX(callback = null)
}); });
} }
function loadFXData(callback = null)
{
var url = (loc?`http://${locip}`:'') + '/json/fxdata';
fetch(url, {
method: 'get'
})
.then(res => {
if (!res.ok) showErrorToast();
return res.json();
})
.then(json => {
clearErrorToast();
fxdata = json||[];
// add default value for Solid
fxdata.shift()
fxdata.unshift("@;!;");
})
.catch(function (error) {
fxdata = [];
showToast(error, true);
})
.finally(()=>{
if (callback) callback();
updateUI();
});
}
var pQL = []; var pQL = [];
function populateQL() function populateQL()
{ {
@ -479,40 +483,7 @@ function parseInfo() {
syncTglRecv = li.str; syncTglRecv = li.str;
maxSeg = li.leds.maxseg; maxSeg = li.leds.maxseg;
pmt = li.fs.pmt; pmt = li.fs.pmt;
} cct = li.leds.cct;
function loadInfo(callback=null)
{
var url = (loc?`http://${locip}`:'') + '/json/info';
var useWs = (ws && ws.readyState === WebSocket.OPEN);
if (useWs) {
ws.send('{"v":true}');
return;
}
fetch(url, {
method: 'get'
})
.then(res => {
if (!res.ok) showToast('Could not load Info!', true);
return res.json();
})
.then(json => {
clearErrorToast();
lastinfo = json;
parseInfo();
showNodes();
if (isInfo) populateInfo(json);
updateUI();
reqsLegal = true;
if (!ws && lastinfo.ws > -1) setTimeout(makeWS,500);
})
.catch(function (error) {
showToast(error, true);
console.log(error);
})
.finally(()=>{
if (callback) callback();
});
} }
function populateInfo(i) function populateInfo(i)
@ -538,7 +509,7 @@ function populateInfo(i)
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;
cn += `v${i.ver} "${vcn}"<br><br><table class="infot"> cn += `v${i.ver} "${vcn}"<br><br><table>
${urows} ${urows}
${inforow("Build",i.vid)} ${inforow("Build",i.vid)}
${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")} ${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")}
@ -577,19 +548,21 @@ function populateSegments(s)
<input type="checkbox" id="seg${i}sel" onchange="selSeg(${i})" ${inst.sel ? "checked":""}> <input type="checkbox" id="seg${i}sel" onchange="selSeg(${i})" ${inst.sel ? "checked":""}>
<span class="checkmark schk"></span> <span class="checkmark schk"></span>
</label> </label>
<i class="icons slider-icon pwr ${powered[i] ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})" title="${inst.n}">&#xe08f;</i> <div class="il">
<div id="sliderSeg${i}Bri" class="sliderwrap il"> <i class="icons slider-icon pwr ${powered[i] ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})" title="${inst.n}">&#xe08f;</i>
<input id="seg${i}bri" class="noslide" onchange="setSegBri(${i})" oninput="updateTrail(this)" max="255" min="1" type="range" value="${inst.bri}" /> <div id="sliderSeg${i}Bri" class="sliderwrap il">
<div class="sliderdisplay"></div> <input id="seg${i}bri" class="noslide" onchange="setSegBri(${i})" oninput="updateTrail(this)" max="255" min="1" type="range" value="${inst.bri}" />
<div class="sliderdisplay"></div>
</div>
<output class="sliderbubble"></output>
</div> </div>
<output class="sliderbubble"></output>
</div>`; </div>`;
} }
if (gId('buttonBri').className !== 'active') tglBri(true); //if (gId('buttonBri').className !== 'active') tglBri(true);
} else { } else {
tglBri(false); //tglBri(false);
} }
gId('buttonBri').style.display = (segCount > 1) ? "block" : "none"; //gId('buttonBri').style.display = (segCount > 1) ? "block" : "none";
gId('segcont').innerHTML = cn; gId('segcont').innerHTML = cn;
for (var i = 0; i < segCount && i<4; i++) updateTrail(gId(`seg${i}bri`)); for (var i = 0; i < segCount && i<4; i++) updateTrail(gId(`seg${i}bri`));
} }
@ -666,20 +639,27 @@ function populateEffects()
effects.sort((a,b) => (a.name).localeCompare(b.name)); effects.sort((a,b) => (a.name).localeCompare(b.name));
effects.unshift({ effects.unshift({
"id": 0, "id": 0,
"name": "Solid", "name": "Solid@;!;0"
}); });
for (let i = 0; i < effects.length; i++) { for (let i = 0; i < effects.length; i++) {
var posAt = effects[i].name.indexOf("@"); // WLEDSR: add slider and color control to setEffect (used by requestjson)
var extra = ''; if (effects[i].name.indexOf("Reserved") < 0) {
if (posAt > 0) var posAt = effects[i].name.indexOf("@");
extra = effects[i].name.substr(posAt); var extra = '';
else if (posAt > 0)
posAt = 999; extra = effects[i].name.substr(posAt);
html += generateListItemHtml( else
effects[i].id, posAt = 999;
effects[i].name.substr(0,posAt), html += generateListItemHtml(
'setEffect' 'fx',
); effects[i].id,
effects[i].name.substr(0,posAt),
'setEffect',
'','',
extra
);
}
} }
gId('fxlist').innerHTML=html; gId('fxlist').innerHTML=html;
} }
@ -702,11 +682,12 @@ function populatePalettes()
var html = ""; var html = "";
for (let i = 0; i < palettes.length; i++) { for (let i = 0; i < palettes.length; i++) {
html += generateListItemHtml( html += generateListItemHtml(
palettes[i].id, 'palette',
palettes[i].name, palettes[i].id,
'setPalette', palettes[i].name,
'setPalette',
`<div class="lstIprev"></div>` `<div class="lstIprev"></div>`
); );
} }
gId('pallist').innerHTML=html; gId('pallist').innerHTML=html;
} }
@ -779,11 +760,19 @@ function generateOptionItemHtml(id, name)
return `<option value="${id}">${name}</option>`; return `<option value="${id}">${name}</option>`;
} }
function generateListItemHtml(id, name, clickAction, extraHtml = '') function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', extraClass = '', extraPar = '')
{ {
return `<div class="lstI c" data-id="${id}" onClick="${clickAction}(${id})"><span class="lstIname">${name}</span>${extraHtml}</div>`; return `<div class="lstI ${extraClass}" data-id="${id}" data-opt="${extraPar}" onClick="${clickAction}(${id})">
<div class="lstIcontent">
<span class="lstIname">
${name}
</span>
</div>
${extraHtml}
</div>`;
} }
//update the 'sliderdisplay' background div of a slider for a visual indication of slider position
function updateTrail(e) function updateTrail(e)
{ {
if (e==null) return; if (e==null) return;
@ -791,15 +780,17 @@ function updateTrail(e)
var perc = e.value * 100 / max; var perc = e.value * 100 / max;
perc = parseInt(perc); perc = parseInt(perc);
if (perc < 50) perc += 2; if (perc < 50) perc += 2;
e.parentNode.getElementsByClassName('sliderdisplay')[0].style.background = `linear-gradient(90deg, var(--c-f) ${perc}%, var(--c-4) ${perc}%)`; var val = `linear-gradient(90deg, var(--c-f) ${perc}%, var(--c-4) ${perc}%)`;
var bubble = e.parentNode.parentNode.getElementsByTagName('output')[0]; e.parentNode.getElementsByClassName('sliderdisplay')[0].style.background = val;
if (bubble) bubble.innerHTML = e.value; var b = e.parentNode.parentNode.getElementsByTagName('output')[0];
if (b) b.innerHTML = e.value;
} }
//rangetouch slider function
function toggleBubble(e) function toggleBubble(e)
{ {
var bubble = e.target.parentNode.parentNode.getElementsByTagName('output')[0]; var b = e.target.parentNode.parentNode.getElementsByTagName('output')[0];
bubble.classList.toggle('sliderbubbleshow'); b.classList.toggle('sliderbubbleshow');
} }
function updatePA() function updatePA()
@ -832,18 +823,22 @@ function updateUI()
sel = 0; sel = 0;
if (eJson && eJson.length) { if (eJson && eJson.length) {
for (var i=0; i<eJson.length; i++) if (eJson[i].id == selectedFx) {sel = i; break;} for (var i=0; i<eJson.length; i++) if (eJson[i].id == selectedFx) {sel = i; break;}
gId('fxBtn').innerHTML = '<i class="icons">&#xe0e8;</i> ' + eJson[sel].name; var posAt = eJson[sel].name.indexOf("@");
if (posAt<=0) posAt=999;
gId('fxBtn').innerHTML = '<i class="icons">&#xe0e8;</i> ' + eJson[sel].name.substr(0,posAt);
} }
updateTrail(gId('sliderBri')); updateTrail(gId('sliderBri'));
updateTrail(gId('sliderSpeed')); updateTrail(gId('sliderSpeed'));
updateTrail(gId('sliderIntensity')); updateTrail(gId('sliderIntensity'));
if (isRgbw) gId('wwrap').style.display = "block";
gId("wbal").style.display = (lastinfo.leds.cct) ? "block":"none";
updatePA(true); gId('wwrap').style.display = (isRgbw) ? "block":"none";
gId("wbal").style.display = (cct) ? "block":"none";
gId('kwrap').style.display = (cct) ? "none":"block";
updatePA();
redrawPalPrev(); redrawPalPrev();
updateRgb(); updatePSliders();
var l = cfg.comp.labels; //l = false; var l = cfg.comp.labels; //l = false;
var e = d.querySelectorAll('.label'); var e = d.querySelectorAll('.label');
@ -859,10 +854,10 @@ function cmpP(a, b)
} }
function makeWS() { function makeWS() {
if (ws || lastinfo.ws<0) return; if (ws) return;
ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws'); ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws');
ws.onmessage = function(event) { ws.onmessage = (e)=>{
var json = JSON.parse(event.data); var json = JSON.parse(e.data);
if (json.leds) return; //liveview packet if (json.leds) return; //liveview packet
clearTimeout(jsonTimeout); clearTimeout(jsonTimeout);
jsonTimeout = null; jsonTimeout = null;
@ -874,18 +869,18 @@ function makeWS() {
if (i) { if (i) {
lastinfo = i; lastinfo = i;
parseInfo(); parseInfo();
showNodes();
if (isInfo) populateInfo(i); if (isInfo) populateInfo(i);
} else } else
i = lastinfo; i = lastinfo;
var s = json.state ? json.state : json; var s = json.state ? json.state : json;
readState(s); readState(s);
}; };
ws.onclose = function(event) { ws.onclose = (e)=>{
gId('connind').style.backgroundColor = "var(--c-r)"; gId('connind').style.backgroundColor = "var(--c-r)";
ws = null; ws = null;
if (lastinfo.ws > -1) setTimeout(makeWS,500);
} }
ws.onopen = function(event) { ws.onopen = (e)=>{
ws.send("{'v':true}"); ws.send("{'v':true}");
reqsLegal = true; reqsLegal = true;
clearErrorToast(); clearErrorToast();
@ -938,7 +933,11 @@ function readState(s,command=false)
gId('sliderSpeed').value = i.sx; gId('sliderSpeed').value = i.sx;
gId('sliderIntensity').value = i.ix; gId('sliderIntensity').value = i.ix;
/*
gId('sliderC1').value = i.f1x ? i.f1x : 0;
gId('sliderC2').value = i.f2x ? i.f2x : 0;
gId('sliderC3').value = i.f3x ? i.f3x : 0;
*/
if (s.error && s.error != 0) { if (s.error && s.error != 0) {
var errstr = ""; var errstr = "";
switch (s.error) { switch (s.error) {
@ -981,11 +980,6 @@ function requestJson(command=null)
if (command) { if (command) {
if (useWs || !command.ps) command.v = true; // force complete /json/si API response if (useWs || !command.ps) command.v = true; // force complete /json/si API response
command.time = Math.floor(Date.now() / 1000); command.time = Math.floor(Date.now() / 1000);
var t = gId('tt');
if (t.validity.valid && command.transition==null) {
var tn = parseInt(t.value*10);
if (tn != tr) command.transition = tn;
}
req = JSON.stringify(command); req = JSON.stringify(command);
if (req.length > 1000) useWs = false; //do not send very long requests over websocket if (req.length > 1000) useWs = false; //do not send very long requests over websocket
}; };
@ -1042,8 +1036,9 @@ function toggleInfo()
{ {
if (isNodes) toggleNodes(); if (isNodes) toggleNodes();
isInfo = !isInfo; isInfo = !isInfo;
if (isInfo) requestJson(); // loadInfo(); if (isInfo) requestJson();
gId('info').style.transform = (isInfo) ? "translateY(0px)":"translateY(100%)"; gId('info').style.transform = (isInfo) ? "translateY(0px)":"translateY(100%)";
gId('buttonI').className = (isInfo) ? "active":"";
} }
function toggleNodes() function toggleNodes()
@ -1052,8 +1047,9 @@ function toggleNodes()
isNodes = !isNodes; isNodes = !isNodes;
if (isNodes) loadNodes(); if (isNodes) loadNodes();
gId('nodes').style.transform = (isNodes) ? "translateY(0px)":"translateY(100%)"; gId('nodes').style.transform = (isNodes) ? "translateY(0px)":"translateY(100%)";
gId('buttonNodes').className = (isNodes) ? "active":"";
} }
/*
function tglBri(b=null) function tglBri(b=null)
{ {
if (b===null) b = gId(`briwrap`).style.display === "block"; if (b===null) b = gId(`briwrap`).style.display === "block";
@ -1061,17 +1057,18 @@ function tglBri(b=null)
gId('buttonBri').className = !b ? "active":""; gId('buttonBri').className = !b ? "active":"";
size(); size();
} }
*/
function tglCP() function tglCP()
{ {
var p = gId('buttonCP').className === "active"; var p = gId('buttonCP').className === "active";
gId('buttonCP').className = !p ? "active":""; gId('buttonCP').className = !p ? "active":"";
gId('picker').style.display = !p ? "block":"none"; gId('picker').style.display = !p ? "block":"none";
gId('vwrap').style.display = !p ? "block":"none";
gId('rgbwrap').style.display = !p ? "block":"none"; gId('rgbwrap').style.display = !p ? "block":"none";
var csl = gId(`csl`).style.display === "block"; var csl = gId('Slots').style.display === "block";
gId('csl').style.display = !csl ? "block":"none"; gId('Slots').style.display = !csl ? "block":"none";
var ps = gId(`Presets`).style.display === "block"; //var ps = gId(`Presets`).style.display === "block";
gId('Presets').style.display = !ps ? "block":"none"; //gId('Presets').style.display = !ps ? "block":"none";
} }
function tglCs(i) function tglCs(i)
@ -1124,7 +1121,7 @@ function setSegBri(s)
requestJson(obj); requestJson(obj);
} }
function setEffect(ind = null) function setEffect(ind = 0)
{ {
tglFxDropdown(); tglFxDropdown();
var obj = {"seg": {"fx": parseInt(ind)}}; var obj = {"seg": {"fx": parseInt(ind)}};
@ -1174,14 +1171,12 @@ function selectSlot(b)
{ {
csel = b; csel = b;
var cd = gId('csl').children; var cd = gId('csl').children;
for (let i = 0; i < cd.length; i++) { for (let i = 0; i < cd.length; i++) cd[i].classList.remove('xxs-w');
cd[i].classList.remove('xxs-w'); cd[b].classList.add('xxs-w');
} setPicker(cd[b].style.backgroundColor);
cd[csel].classList.add('xxs-w'); gId('sliderW').value = whites[b];
cpick.color.set(cd[csel].style.backgroundColor);
gId('sliderW').value = whites[csel];
redrawPalPrev(); redrawPalPrev();
updateRgb(); updatePSliders();
} }
var lasth = 0; var lasth = 0;
@ -1195,16 +1190,49 @@ function pC(col)
} while (Math.abs(col.h - lasth) < 50); } while (Math.abs(col.h - lasth) < 50);
lasth = col.h; lasth = col.h;
} }
cpick.color.set(col); setPicker(col);
setColor(0); setColor(0);
} }
function updateRgb() function updatePSliders() {
{ //update RGB sliders
var col = cpick.color.rgb; var col = cpick.color.rgb;
gId('sliderR').value = col.r; gId('sliderR').value = col.r;
gId('sliderG').value = col.g; gId('sliderG').value = col.g;
gId('sliderB').value = col.b; gId('sliderB').value = col.b;
//update hex field
var str = cpick.color.hexString.substring(1);
var w = whites[csel];
if (w > 0) str += w.toString(16);
//update value slider
var v = gId('sliderV');
v.value = cpick.color.value;
//background color as if color had full value
var hsv = {"h":cpick.color.hue,"s":cpick.color.saturation,"v":100};
var c = iro.Color.hsvToRgb(hsv);
var cs = 'rgb('+c.r+','+c.g+','+c.b+')';
v.nextElementSibling.style.backgroundImage = `linear-gradient(90deg, #000 0%, ${cs})`;
//update Kelvin slider
gId('sliderK').value = cpick.color.kelvin;
}
function setPicker(rgb) {
var c = new iro.Color(rgb);
if (c.value > 0) cpick.color.set(c);
else cpick.color.setChannel('hsv', 'v', 0);
}
function fromV()
{
cpick.color.setChannel('hsv', 'v', d.getElementById('sliderV').value);
}
function fromK()
{
cpick.color.set({ kelvin: d.getElementById('sliderK').value });
} }
function fromRgb() function fromRgb()
@ -1212,7 +1240,7 @@ function fromRgb()
var r = gId('sliderR').value; var r = gId('sliderR').value;
var g = gId('sliderG').value; var g = gId('sliderG').value;
var b = gId('sliderB').value; var b = gId('sliderB').value;
cpick.color.set(`rgb(${r},${g},${b})`); setPicker(`rgb(${r},${g},${b})`);
setColor(0); setColor(0);
} }
@ -1220,7 +1248,7 @@ function fromRgb()
function setColor(sr) function setColor(sr)
{ {
var cd = gId('csl').children; // color slots var cd = gId('csl').children; // color slots
if (sr == 1 && cd[csel].style.backgroundColor == 'rgb(0,0,0)') cpick.color.setChannel('hsv', 'v', 100); if (sr == 1 && cd[csel].style.backgroundColor == 'rgb(0, 0, 0)') cpick.color.setChannel('hsv', 'v', 100);
cd[csel].style.backgroundColor = cpick.color.rgbString; cd[csel].style.backgroundColor = cpick.color.rgbString;
if (sr != 2) whites[csel] = parseInt(gId('sliderW').value); if (sr != 2) whites[csel] = parseInt(gId('sliderW').value);
var col = cpick.color.rgb; var col = cpick.color.rgb;
@ -1241,7 +1269,7 @@ function setBalance(b)
} }
var hc = 0; var hc = 0;
setInterval(function(){if (!isInfo) return; hc+=18; if (hc>300) hc=0; if (hc>200)hc=306; if (hc==144) hc+=36; if (hc==108) hc+=18; setInterval(()=>{if (!isInfo) return; hc+=18; if (hc>300) hc=0; if (hc>200)hc=306; if (hc==144) hc+=36; if (hc==108) hc+=18;
gId('heart').style.color = `hsl(${hc}, 100%, 50%)`;}, 910); gId('heart').style.color = `hsl(${hc}, 100%, 50%)`;}, 910);
function openGH() { window.open("https://github.com/Aircoookie/WLED/wiki"); } function openGH() { window.open("https://github.com/Aircoookie/WLED/wiki"); }
@ -1275,7 +1303,7 @@ function loadPalettesData(callback = null)
} }
palettesData = {}; palettesData = {};
getPalettesData(0, function() { getPalettesData(0, ()=>{
localStorage.setItem(lsKey, JSON.stringify({ localStorage.setItem(lsKey, JSON.stringify({
p: palettesData, p: palettesData,
vid: lastinfo.vid vid: lastinfo.vid
@ -1294,18 +1322,17 @@ function getPalettesData(page, callback)
"Content-type": "application/json; charset=UTF-8" "Content-type": "application/json; charset=UTF-8"
} }
}) })
.then(res => { .then((res)=>{
if (!res.ok) showErrorToast(); if (!res.ok) showErrorToast();
return res.json(); return res.json();
}) })
.then(json => { .then((json)=>{
palettesData = Object.assign({}, palettesData, json.p); palettesData = Object.assign({}, palettesData, json.p);
if (page < json.m) setTimeout(function() { getPalettesData(page + 1, callback); }, 50); if (page < json.m) setTimeout(()=>{ getPalettesData(page + 1, callback); }, 50);
else callback(); else callback();
}) })
.catch(function(error) { .catch((e)=>{
showToast(error, true); showToast(e, true);
console.log(error);
}); });
} }
@ -1390,7 +1417,6 @@ function move(e)
function size() function size()
{ {
w = window.innerWidth;
var h = gId('top').clientHeight; var h = gId('top').clientHeight;
sCol('--th', h + "px"); sCol('--th', h + "px");
sCol("--tp", h - (gId(`briwrap`).style.display === "block" ? 0 : gId(`briwrap`).clientTop) + "px"); sCol("--tp", h - (gId(`briwrap`).style.display === "block" ? 0 : gId(`briwrap`).clientTop) + "px");

View File

@ -92,6 +92,9 @@ input[type="checkbox"] {
transform: scale(1.5); transform: scale(1.5);
margin-right: 10px; margin-right: 10px;
} }
td input[type="checkbox"] {
margin-right: revert;
}
select { select {
margin: 2px; margin: 2px;
background: #333; background: #333;
@ -108,8 +111,12 @@ td {
.d5 { .d5 {
width: 4rem !important; width: 4rem !important;
} }
.exp { .cal {
transform: rotate(90deg); font-size:1.5rem;
cursor:pointer
}
#TMT table {
width: 100%;
} }
#toast { #toast {
opacity: 0; opacity: 0;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -654,7 +654,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);

View File

@ -168,11 +168,9 @@ void colorUpdated(int callMode)
void updateInterfaces(uint8_t callMode) void updateInterfaces(uint8_t callMode)
{ {
lastInterfaceUpdate = millis();
sendDataWs(); sendDataWs();
if (callMode == CALL_MODE_WS_SEND) { if (callMode == CALL_MODE_WS_SEND) return;
lastInterfaceUpdate = millis();
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 +183,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();
} }

View File

@ -318,6 +318,32 @@ byte weekdayMondayFirst()
return wd; return wd;
} }
bool isTodayInDateRange(byte monthStart, byte dayStart, byte monthEnd, byte dayEnd)
{
if (monthStart == 0 || dayStart == 0) return true;
if (monthEnd == 0) monthEnd = monthStart;
if (dayEnd == 0) dayEnd = 31;
byte d = day(localTime);
byte m = month(localTime);
if (monthStart < monthEnd) {
if (m > monthStart && m < monthEnd) return true;
if (m == monthStart) return (d >= dayStart);
if (m == monthEnd) return (d <= dayEnd);
return false;
}
if (monthEnd < monthStart) { //range spans change of year
if (m > monthStart || m < monthEnd) return true;
if (m == monthStart) return (d >= dayStart);
if (m == monthEnd) return (d <= dayEnd);
return false;
}
//start month and end month are the same
if (dayEnd < dayStart) return (m != monthStart || (d <= dayEnd || d >= dayStart)); //all year, except the designated days in this month
return (m == monthStart && d >= dayStart && d <= dayEnd); //just the designated days this month
}
void checkTimers() void checkTimers()
{ {
if (lastTimerMinute != minute(localTime)) //only check once a new minute begins if (lastTimerMinute != minute(localTime)) //only check once a new minute begins
@ -334,12 +360,9 @@ void checkTimers()
&& (timerWeekday[i] & 0x01) //timer is enabled && (timerWeekday[i] & 0x01) //timer is enabled
&& (timerHours[i] == hour(localTime) || timerHours[i] == 24) //if hour is set to 24, activate every hour && (timerHours[i] == hour(localTime) || timerHours[i] == 24) //if hour is set to 24, activate every hour
&& timerMinutes[i] == minute(localTime) && timerMinutes[i] == minute(localTime)
&& ( (timerDay[i] == 0 && ((timerWeekday[i] >> weekdayMondayFirst()) & 0x01)) //timer should activate at current day of week && ((timerWeekday[i] >> weekdayMondayFirst()) & 0x01) //timer should activate at current day of week
|| (timerDay[i] > 0 && timerDay[i]==day(localTime) && && isTodayInDateRange(((timerMonth[i] >> 4) & 0x0F), timerDay[i], timerMonth[i] & 0x0F, timerDayEnd[i])
(timerMonth[i] == 0 || timerMonth[i]==month(localTime) || (timerMonth[i]==13 && month(localTime)%2) || (timerMonth[i]==14 && !(month(localTime)%2))) )
)
)
)
{ {
unloadPlaylist(); unloadPlaylist();
applyPreset(timerMacro[i]); applyPreset(timerMacro[i]);

View File

@ -107,7 +107,7 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) {
playlistRepeat = rep; playlistRepeat = rep;
if (playlistRepeat > 0) playlistRepeat++; //add one extra repetition immediately since it will be deducted on first start if (playlistRepeat > 0) playlistRepeat++; //add one extra repetition immediately since it will be deducted on first start
playlistEndPreset = playlistObj[F("end")] | 0; playlistEndPreset = playlistObj["end"] | 0;
shuffle = shuffle || playlistObj["r"]; shuffle = shuffle || playlistObj["r"];
if (shuffle) playlistOptions += PL_OPTION_SHUFFLE; if (shuffle) playlistOptions += PL_OPTION_SHUFFLE;

View File

@ -39,9 +39,17 @@ void handlePresets()
errorFlag = readObjectFromFileUsingId(filename, presetToApply, fileDoc) ? ERR_NONE : ERR_FS_PLOAD; errorFlag = readObjectFromFileUsingId(filename, presetToApply, fileDoc) ? ERR_NONE : ERR_FS_PLOAD;
} }
fdo = fileDoc->as<JsonObject>(); fdo = fileDoc->as<JsonObject>();
fdo.remove("ps"); //remove load request for presets to prevent recursive crash
deserializeState(fdo, callModeToApply, presetToApply); //HTTP API commands
const char* httpwin = fdo["win"];
if (httpwin) {
String apireq = "win&";
apireq += httpwin;
handleSet(nullptr, apireq, false);
} else {
fdo.remove("ps"); //remove load request for presets to prevent recursive crash
deserializeState(fdo, CALL_MODE_NO_NOTIFY, presetToApply);
}
#if defined(ARDUINO_ARCH_ESP32) #if defined(ARDUINO_ARCH_ESP32)
//Aircoookie recommended not to delete buffer //Aircoookie recommended not to delete buffer
@ -54,7 +62,11 @@ void handlePresets()
releaseJSONBufferLock(); // will also clear fileDoc releaseJSONBufferLock(); // will also clear fileDoc
if (!errorFlag && presetToApply < 255) currentPreset = presetToApply; if (!errorFlag && presetToApply < 255) currentPreset = presetToApply;
if (callModeToApply == CALL_MODE_BUTTON_PRESET) errorFlag = ERR_NONE; //ignore error on button press
effectChanged = true; //force UDP notification
colorUpdated(callModeToApply);
updateInterfaces(callModeToApply);
presetToApply = 0; //clear request for preset presetToApply = 0; //clear request for preset
callModeToApply = 0; callModeToApply = 0;
} }

View File

@ -339,7 +339,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
char k[3]; k[2] = 0; char k[3]; k[2] = 0;
for (int i = 0; i<10; i++) { for (int i = 0; i<10; i++) {
k[1] = i+48;//ascii 0,1,2,3 k[1] = i+48;//ascii 0,1,2,3,...
k[0] = 'H'; //timer hours k[0] = 'H'; //timer hours
timerHours[i] = request->arg(k).toInt(); timerHours[i] = request->arg(k).toInt();
k[0] = 'N'; //minutes k[0] = 'N'; //minutes
@ -349,16 +349,15 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
k[0] = 'W'; //weekdays k[0] = 'W'; //weekdays
timerWeekday[i] = request->arg(k).toInt(); timerWeekday[i] = request->arg(k).toInt();
if (i<8) { if (i<8) {
k[0] = 'X'; //DOW k[0] = 'M'; //start month
if (!request->hasArg(k)) { timerMonth[i] = request->arg(k).toInt() & 0x0F;
k[0] = 'M'; //month timerMonth[i] <<= 4;
timerMonth[i] = request->arg(k).toInt(); k[0] = 'P'; //end month
k[0] = 'D'; //day timerMonth[i] += (request->arg(k).toInt() & 0x0F);
timerDay[i] = request->arg(k).toInt(); k[0] = 'D'; //start day
} else { timerDay[i] = request->arg(k).toInt();
timerMonth[i] = 0; k[0] = 'E'; //end day
timerDay[i] = 0; timerDayEnd[i] = request->arg(k).toInt();
}
} }
} }
} }

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2201011 #define VERSION 2201093
//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
@ -503,15 +503,17 @@ WLED_GLOBAL byte dP[] _INIT_N(({ 255, 255, 255, 255, 255, 255 }));
WLED_GLOBAL unsigned long countdownTime _INIT(1514764800L); WLED_GLOBAL unsigned long countdownTime _INIT(1514764800L);
WLED_GLOBAL bool countdownOverTriggered _INIT(true); WLED_GLOBAL bool countdownOverTriggered _INIT(true);
// timer //timer
WLED_GLOBAL byte lastTimerMinute _INIT(0); WLED_GLOBAL byte lastTimerMinute _INIT(0);
WLED_GLOBAL byte timerHours[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })); WLED_GLOBAL byte timerHours[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
WLED_GLOBAL int8_t timerMinutes[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })); WLED_GLOBAL int8_t timerMinutes[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
WLED_GLOBAL byte timerMacro[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })); WLED_GLOBAL byte timerMacro[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 })); // weekdays to activate on //weekdays to activate on, bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity
// bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }));
WLED_GLOBAL byte timerMonth[] _INIT_N(({0,0,0,0,0,0,0,0})); //upper 4 bits start, lower 4 bits end month (default 28: start month 1 and end month 12)
WLED_GLOBAL byte timerDay[] _INIT_N(({0,0,0,0,0,0,0,0})); WLED_GLOBAL byte timerMonth[] _INIT_N(({28,28,28,28,28,28,28,28}));
WLED_GLOBAL byte timerDay[] _INIT_N(({1,1,1,1,1,1,1,1}));
WLED_GLOBAL byte timerDayEnd[] _INIT_N(({31,31,31,31,31,31,31,31}));
// blynk // blynk
WLED_GLOBAL bool blynkEnabled _INIT(false); WLED_GLOBAL bool blynkEnabled _INIT(false);

View File

@ -458,7 +458,7 @@ void getSettingsJS(byte subPage, char* dest)
memset(fpass,'*',l); memset(fpass,'*',l);
sappends('s',SET_F("MQPASS"),fpass); sappends('s',SET_F("MQPASS"),fpass);
sappends('s',SET_F("MQCID"),mqttClientID); sappends('s',SET_F("MQCID"),mqttClientID);
sappends('s',SET_F("MD"),mqttDeviceTopic); sappends('s',"MD",mqttDeviceTopic);
sappends('s',SET_F("MG"),mqttGroupTopic); sappends('s',SET_F("MG"),mqttGroupTopic);
sappend('c',SET_F("BM"),buttonPublishMqtt); sappend('c',SET_F("BM"),buttonPublishMqtt);
#endif #endif
@ -550,10 +550,10 @@ void getSettingsJS(byte subPage, char* dest)
k[0] = 'T'; sappend('v',k,timerMacro[i]); k[0] = 'T'; sappend('v',k,timerMacro[i]);
k[0] = 'W'; sappend('v',k,timerWeekday[i]); k[0] = 'W'; sappend('v',k,timerWeekday[i]);
if (i<8) { if (i<8) {
k[0] = 'X'; sappend('c',k,timerDay[i]==0); k[0] = 'M'; sappend('v',k,(timerMonth[i] >> 4) & 0x0F);
k[0] = 'M'; sappend('v',k,timerMonth[i]); k[0] = 'P'; sappend('v',k,timerMonth[i] & 0x0F);
k[0] = 'D'; sappend('v',k,timerDay[i]?timerDay[i]:1); k[0] = 'D'; sappend('v',k,timerDay[i]);
k[0] = 'E'; sappend('v',k,timerDayEnd[i]);
} }
} }
} }