Multi button support.

This commit is contained in:
Blaz Kristan 2021-05-20 19:54:07 +02:00
parent 1617658bfe
commit 69099fcdd7
13 changed files with 1677 additions and 1376 deletions

View File

@ -6,105 +6,124 @@
#define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing) #define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing)
void shortPressAction() void shortPressAction(uint8_t b)
{ {
if (!macroButton) if (!macroButton[b])
{ {
toggleOnOff(); toggleOnOff();
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
} else { } else {
applyPreset(macroButton); applyPreset(macroButton[b]);
} }
} }
bool isButtonPressed() bool isButtonPressed(uint8_t i)
{ {
if (btnPin>=0 && digitalRead(btnPin) == LOW) return true; if (btnPin[i]<0) return false;
#ifdef TOUCHPIN switch (buttonType[i]) {
if (touchRead(TOUCHPIN) <= TOUCH_THRESHOLD) return true; case BTN_TYPE_NONE:
#endif case BTN_TYPE_RESERVED:
break;
case BTN_TYPE_PUSH:
case BTN_TYPE_SWITCH:
if (digitalRead(btnPin[i]) == LOW) return true;
break;
case BTN_TYPE_PUSH_ACT_HIGH:
case BTN_TYPE_SWITCH_ACT_HIGH:
if (digitalRead(btnPin[i]) == HIGH) return true;
break;
case BTN_TYPE_TOUCH:
#ifdef ARDUINO_ARCH_ESP32
if (touchRead(btnPin[i]) <= touchThreshold) return true;
DEBUG_PRINT(F("Touch value: "));
DEBUG_PRINTLN(touchRead(btnPin[i]));
#endif
break;
}
return false; return false;
} }
void handleSwitch() void handleSwitch(uint8_t b)
{ {
if (buttonPressedBefore != isButtonPressed()) { if (buttonPressedBefore[b] != isButtonPressed(b)) {
buttonPressedTime = millis(); buttonPressedTime[b] = millis();
buttonPressedBefore = !buttonPressedBefore; buttonPressedBefore[b] = !buttonPressedBefore[b];
} }
if (buttonLongPressed == buttonPressedBefore) return; if (buttonLongPressed[b] == buttonPressedBefore[b]) return;
if (millis() - buttonPressedTime > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce) if (millis() - buttonPressedTime[b] > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce)
if (buttonPressedBefore) { //LOW, falling edge, switch closed if (buttonPressedBefore[b]) { //LOW, falling edge, switch closed
if (macroButton) applyPreset(macroButton); if (macroButton[b]) applyPreset(macroButton[b]);
else { //turn on else { //turn on
if (!bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);} if (!bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);}
} }
} else { //HIGH, rising edge, switch opened } else { //HIGH, rising edge, switch opened
if (macroLongPress) applyPreset(macroLongPress); if (macroLongPress[b]) applyPreset(macroLongPress[b]);
else { //turn off else { //turn off
if (bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);} if (bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);}
} }
} }
buttonLongPressed = buttonPressedBefore; //save the last "long term" switch state buttonLongPressed[b] = buttonPressedBefore[b]; //save the last "long term" switch state
} }
} }
void handleButton() void handleButton()
{ {
if (btnPin<0 || buttonType < BTN_TYPE_PUSH) return; for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) {
if (btnPin[b]<0 || !(buttonType[b] > BTN_TYPE_NONE)) continue;
if (buttonType == BTN_TYPE_SWITCH) { //button is not momentary, but switch. This is only suitable on pins whose on-boot state does not matter (NO gpio0) if (buttonType[b] == BTN_TYPE_SWITCH) { //button is not momentary, but switch. This is only suitable on pins whose on-boot state does not matter (NOT gpio0)
handleSwitch(); return; handleSwitch(b); continue;
} }
//momentary button logic //momentary button logic
if (isButtonPressed()) //pressed if (isButtonPressed(b)) //pressed
{
if (!buttonPressedBefore) buttonPressedTime = millis();
buttonPressedBefore = true;
if (millis() - buttonPressedTime > 600) //long press
{ {
if (!buttonLongPressed) if (!buttonPressedBefore[b]) buttonPressedTime[b] = millis();
{ buttonPressedBefore[b] = true;
if (macroLongPress) {applyPreset(macroLongPress);}
else _setRandomColor(false,true);
buttonLongPressed = true; if (millis() - buttonPressedTime[b] > 600) //long press
{
if (!buttonLongPressed[b])
{
if (macroLongPress[b]) {applyPreset(macroLongPress[b]);}
else _setRandomColor(false,true);
buttonLongPressed[b] = true;
}
} }
} }
} else if (!isButtonPressed(b) && buttonPressedBefore[b]) //released
else if (!isButtonPressed() && buttonPressedBefore) //released
{
long dur = millis() - buttonPressedTime;
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore = false; return;} //too short "press", debounce
bool doublePress = buttonWaitTime;
buttonWaitTime = 0;
if (dur > 6000) //long press
{ {
WLED::instance().initAP(true); long dur = millis() - buttonPressedTime[b];
} if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} //too short "press", debounce
else if (!buttonLongPressed) { //short press bool doublePress = buttonWaitTime[b];
if (macroDoublePress) buttonWaitTime[b] = 0;
{
if (doublePress) applyPreset(macroDoublePress);
else buttonWaitTime = millis();
} else shortPressAction();
}
buttonPressedBefore = false;
buttonLongPressed = false;
}
if (buttonWaitTime && millis() - buttonWaitTime > 450 && !buttonPressedBefore) if (dur > 6000 && b==0) //long press on button 0
{ {
buttonWaitTime = 0; WLED::instance().initAP(true);
shortPressAction(); }
else if (!buttonLongPressed[b]) { //short press
if (macroDoublePress[b])
{
if (doublePress) applyPreset(macroDoublePress[b]);
else buttonWaitTime[b] = millis();
} else shortPressAction(b);
}
buttonPressedBefore[b] = false;
buttonLongPressed[b] = false;
}
if (buttonWaitTime[b] && millis() - buttonWaitTime[b] > 450 && !buttonPressedBefore[b])
{
buttonWaitTime[b] = 0;
shortPressAction(b);
}
} }
} }
@ -128,7 +147,8 @@ void handleIO()
{ {
if (!offMode) { if (!offMode) {
#ifdef ESP8266 #ifdef ESP8266
//turn off built-in LED if strip is turned off // turn off built-in LED if strip is turned off
// this will break digital bus so will need to be reinitialised on On
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH); digitalWrite(LED_BUILTIN, HIGH);
#endif #endif

View File

@ -62,7 +62,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonArray ap_ip = ap["ip"]; JsonArray ap_ip = ap["ip"];
for (byte i = 0; i < 4; i++) { for (byte i = 0; i < 4; i++) {
apIP[i] = ap_ip; apIP[i] = ap_ip;
}*/ }
*/
noWifiSleep = doc[F("wifi")][F("sleep")] | !noWifiSleep; // inverted noWifiSleep = doc[F("wifi")][F("sleep")] | !noWifiSleep; // inverted
noWifiSleep = !noWifiSleep; noWifiSleep = !noWifiSleep;
@ -89,13 +90,12 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
for (JsonObject elm : ins) { for (JsonObject elm : ins) {
if (s >= WLED_MAX_BUSSES) break; if (s >= WLED_MAX_BUSSES) break;
uint8_t pins[5] = {255, 255, 255, 255, 255}; uint8_t pins[5] = {255, 255, 255, 255, 255};
JsonArray pinArr = elm[F("pin")]; JsonArray pinArr = elm["pin"];
if (pinArr.size() == 0) continue; if (pinArr.size() == 0) continue;
pins[0] = pinArr[0]; pins[0] = pinArr[0];
uint8_t i = 0; uint8_t i = 0;
for (int p : pinArr) { for (int p : pinArr) {
pins[i] = p; pins[i++] = p;
i++;
if (i>4) break; if (i>4) break;
} }
@ -123,22 +123,47 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
} }
if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0]; // read multiple button configuration
CJSON(buttonType, hw_btn_ins_0["type"]); JsonArray hw_btn_ins = hw[F("btn")][F("ins")];
int hw_btn_pin = hw_btn_ins_0[F("pin")][0] | -2; //-2 = not present in doc, keep current. -1 = disable if (!hw_btn_ins.isNull()) {
if (hw_btn_pin > -2) { uint8_t s = 0;
if (pinManager.allocatePin(hw_btn_pin,false)) { for (JsonObject btn : hw_btn_ins) {
btnPin = hw_btn_pin; CJSON(buttonType[s], btn["type"]);
pinMode(btnPin, INPUT_PULLUP); int8_t pin = btn[F("pin")][0] | -1;
} else { if (pin > -1) {
btnPin = -1; if (pinManager.allocatePin(pin,false)) {
btnPin[s] = pin;
pinMode(btnPin[s], INPUT_PULLUP);
} else {
btnPin[s] = -1;
}
}
JsonArray hw_btn_ins_0_macros = btn[F("macros")];
CJSON(macroButton[s], hw_btn_ins_0_macros[0]);
CJSON(macroLongPress[s],hw_btn_ins_0_macros[1]);
CJSON(macroDoublePress[s], hw_btn_ins_0_macros[2]);
if (++s >= WLED_MAX_BUTTONS) break; // max buttons reached
} }
// clear remaining buttons
for (; s<WLED_MAX_BUTTONS; s++) {
btnPin[s] = -1;
buttonType[s] = BTN_TYPE_NONE;
macroButton[s] = 0;
macroLongPress[s] = 0;
macroDoublePress[s] = 0;
}
} else {
// new install/missing configuration (button 0 has defaults)
if (fromFS)
for (uint8_t s=1; s<WLED_MAX_BUTTONS; s++) {
btnPin[s] = -1;
buttonType[s] = BTN_TYPE_NONE;
macroButton[s] = 0;
macroLongPress[s] = 0;
macroDoublePress[s] = 0;
}
} }
CJSON(touchThreshold,hw[F("btn")][F("tt")]);
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0[F("macros")];
CJSON(macroButton, hw_btn_ins_0_macros[0]);
CJSON(macroLongPress,hw_btn_ins_0_macros[1]);
CJSON(macroDoublePress, hw_btn_ins_0_macros[2]);
#ifndef WLED_DISABLE_INFRARED #ifndef WLED_DISABLE_INFRARED
int hw_ir_pin = hw["ir"]["pin"] | -2; // 4 int hw_ir_pin = hw["ir"]["pin"] | -2; // 4
@ -166,7 +191,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
rlyMde = !relay["rev"]; rlyMde = !relay["rev"];
} }
//int hw_status_pin = hw[F("status")][F("pin")]; // -1 //int hw_status_pin = hw[F("status")]["pin"]; // -1
JsonObject light = doc[F("light")]; JsonObject light = doc[F("light")];
CJSON(briMultiplier, light[F("scale-bri")]); CJSON(briMultiplier, light[F("scale-bri")]);
@ -181,7 +206,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonObject light_tr = light[F("tr")]; JsonObject light_tr = light[F("tr")];
CJSON(fadeTransition, light_tr[F("mode")]); CJSON(fadeTransition, light_tr[F("mode")]);
int tdd = light_tr[F("dur")] | -1; int tdd = light_tr["dur"] | -1;
if (tdd >= 0) transitionDelayDefault = tdd * 100; if (tdd >= 0) transitionDelayDefault = tdd * 100;
CJSON(strip.paletteFade, light_tr["pal"]); CJSON(strip.paletteFade, light_tr["pal"]);
@ -205,7 +230,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(presetCycleMin, def_cy[F("range")][0]); CJSON(presetCycleMin, def_cy[F("range")][0]);
CJSON(presetCycleMax, def_cy[F("range")][1]); CJSON(presetCycleMax, def_cy[F("range")][1]);
tdd = def_cy[F("dur")] | -1; tdd = def_cy["dur"] | -1;
if (tdd > 0) presetCycleTime = tdd; if (tdd > 0) presetCycleTime = tdd;
JsonObject interfaces = doc["if"]; JsonObject interfaces = doc["if"];
@ -257,6 +282,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(macroAlexaOn, interfaces[F("va")][F("macros")][0]); CJSON(macroAlexaOn, interfaces[F("va")][F("macros")][0]);
CJSON(macroAlexaOff, interfaces[F("va")][F("macros")][1]); CJSON(macroAlexaOff, interfaces[F("va")][F("macros")][1]);
#ifndef WLED_DISABLE_BLYNK
const char* apikey = interfaces["blynk"][F("token")] | "Hidden"; const char* apikey = interfaces["blynk"][F("token")] | "Hidden";
tdd = strnlen(apikey, 36); tdd = strnlen(apikey, 36);
if (tdd > 20 || tdd == 0) if (tdd > 20 || tdd == 0)
@ -265,7 +291,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonObject if_blynk = interfaces["blynk"]; JsonObject if_blynk = interfaces["blynk"];
getStringFromJson(blynkHost, if_blynk[F("host")], 33); getStringFromJson(blynkHost, if_blynk[F("host")], 33);
CJSON(blynkPort, if_blynk["port"]); CJSON(blynkPort, if_blynk["port"]);
#endif
#ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces["mqtt"]; JsonObject if_mqtt = interfaces["mqtt"];
CJSON(mqttEnabled, if_mqtt["en"]); CJSON(mqttEnabled, if_mqtt["en"]);
getStringFromJson(mqttServer, if_mqtt[F("broker")], 33); getStringFromJson(mqttServer, if_mqtt[F("broker")], 33);
@ -276,7 +304,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test" getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test"
getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // "" getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // ""
#endif
#ifndef WLED_DISABLE_HUESYNC
JsonObject if_hue = interfaces[F("hue")]; JsonObject if_hue = interfaces[F("hue")];
CJSON(huePollingEnabled, if_hue["en"]); CJSON(huePollingEnabled, if_hue["en"]);
CJSON(huePollLightId, if_hue["id"]); CJSON(huePollLightId, if_hue["id"]);
@ -292,6 +322,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
for (byte i = 0; i < 4; i++) for (byte i = 0; i < 4; i++)
CJSON(hueIP[i], if_hue_ip[i]); CJSON(hueIP[i], if_hue_ip[i]);
#endif
JsonObject if_ntp = interfaces[F("ntp")]; JsonObject if_ntp = interfaces[F("ntp")];
CJSON(ntpEnabled, if_ntp["en"]); CJSON(ntpEnabled, if_ntp["en"]);
@ -308,7 +339,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(countdownMode, ol[F("cntdwn")]); CJSON(countdownMode, ol[F("cntdwn")]);
if (prev != overlayDefault) overlayCurrent = overlayDefault; if (prev != overlayDefault) overlayCurrent = overlayDefault;
CJSON(overlayMin, ol[F("min")]); CJSON(overlayMin, ol["min"]);
CJSON(overlayMax, ol[F("max")]); CJSON(overlayMax, ol[F("max")]);
CJSON(analogClock12pixel, ol[F("o12pix")]); CJSON(analogClock12pixel, ol[F("o12pix")]);
CJSON(analogClock5MinuteMarks, ol[F("o5m")]); CJSON(analogClock5MinuteMarks, ol[F("o5m")]);
@ -333,7 +364,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
if (it > 9) break; if (it > 9) break;
if (it<8 && timer[F("hour")]==255) it=8; // hour==255 -> sunrise/sunset if (it<8 && timer[F("hour")]==255) it=8; // hour==255 -> sunrise/sunset
CJSON(timerHours[it], timer[F("hour")]); CJSON(timerHours[it], timer[F("hour")]);
CJSON(timerMinutes[it], timer[F("min")]); CJSON(timerMinutes[it], timer["min"]);
CJSON(timerMacro[it], timer[F("macro")]); CJSON(timerMacro[it], timer[F("macro")]);
byte dowPrev = timerWeekday[it]; byte dowPrev = timerWeekday[it];
@ -379,6 +410,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
} }
#endif #endif
DEBUG_PRINTLN(F("Starting usermod config."));
JsonObject usermods_settings = doc["um"]; JsonObject usermods_settings = doc["um"];
if (!usermods_settings.isNull()) usermods.readFromConfig(usermods_settings); if (!usermods_settings.isNull()) usermods.readFromConfig(usermods_settings);
@ -492,27 +524,38 @@ void serializeConfig() {
ins["type"] = bus->getType(); ins["type"] = bus->getType();
} }
// button(s)
JsonObject hw_btn = hw.createNestedObject("btn"); JsonObject hw_btn = hw.createNestedObject("btn");
hw_btn["max"] = WLED_MAX_BUTTONS; // just information about max number of buttons (not actually used)
JsonArray hw_btn_ins = hw_btn.createNestedArray("ins"); JsonArray hw_btn_ins = hw_btn.createNestedArray("ins");
// button BTNPIN // there is always at least one button
JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject(); JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject();
hw_btn_ins_0["type"] = buttonType; hw_btn_ins_0["type"] = buttonType[0];
JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin"); JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin");
hw_btn_ins_0_pin.add(btnPin); hw_btn_ins_0_pin.add(btnPin[0]);
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros"); JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros");
hw_btn_ins_0_macros.add(macroButton); hw_btn_ins_0_macros.add(macroButton[0]);
hw_btn_ins_0_macros.add(macroLongPress); hw_btn_ins_0_macros.add(macroLongPress[0]);
hw_btn_ins_0_macros.add(macroDoublePress); hw_btn_ins_0_macros.add(macroDoublePress[0]);
// additional buttons
for (uint8_t i=1; i<WLED_MAX_BUTTONS; i++) {
//if (btnPin[i]<0) continue;
hw_btn_ins_0 = hw_btn_ins.createNestedObject();
hw_btn_ins_0["type"] = buttonType[i];
hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin");
hw_btn_ins_0_pin.add(btnPin[i]);
hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros");
hw_btn_ins_0_macros.add(macroButton[i]);
hw_btn_ins_0_macros.add(macroLongPress[i]);
hw_btn_ins_0_macros.add(macroDoublePress[i]);
}
hw_btn[F("tt")] = touchThreshold;
#ifndef WLED_DISABLE_INFRARED
JsonObject hw_ir = hw.createNestedObject("ir"); JsonObject hw_ir = hw.createNestedObject("ir");
hw_ir["pin"] = irPin; hw_ir["pin"] = irPin;
hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled ) hw_ir["type"] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
#endif
JsonObject hw_relay = hw.createNestedObject(F("relay")); JsonObject hw_relay = hw.createNestedObject(F("relay"));
hw_relay["pin"] = rlyPin; hw_relay["pin"] = rlyPin;
@ -531,12 +574,12 @@ void serializeConfig() {
JsonObject light_tr = light.createNestedObject("tr"); JsonObject light_tr = light.createNestedObject("tr");
light_tr[F("mode")] = fadeTransition; light_tr[F("mode")] = fadeTransition;
light_tr[F("dur")] = transitionDelayDefault / 100; light_tr["dur"] = transitionDelayDefault / 100;
light_tr["pal"] = strip.paletteFade; light_tr["pal"] = strip.paletteFade;
JsonObject light_nl = light.createNestedObject("nl"); JsonObject light_nl = light.createNestedObject("nl");
light_nl[F("mode")] = nightlightMode; light_nl[F("mode")] = nightlightMode;
light_nl[F("dur")] = nightlightDelayMinsDefault; light_nl["dur"] = nightlightDelayMinsDefault;
light_nl[F("tbri")] = nightlightTargetBri; light_nl[F("tbri")] = nightlightTargetBri;
light_nl[F("macro")] = macroNl; light_nl[F("macro")] = macroNl;
@ -553,7 +596,7 @@ void serializeConfig() {
JsonArray def_cy_range = def_cy.createNestedArray(F("range")); JsonArray def_cy_range = def_cy.createNestedArray(F("range"));
def_cy_range.add(presetCycleMin); def_cy_range.add(presetCycleMin);
def_cy_range.add(presetCycleMax); def_cy_range.add(presetCycleMax);
def_cy[F("dur")] = presetCycleTime; def_cy["dur"] = presetCycleTime;
} }
JsonObject interfaces = doc.createNestedObject("if"); JsonObject interfaces = doc.createNestedObject("if");
@ -565,7 +608,7 @@ void serializeConfig() {
JsonObject if_sync_recv = if_sync.createNestedObject("recv"); JsonObject if_sync_recv = if_sync.createNestedObject("recv");
if_sync_recv["bri"] = receiveNotificationBrightness; if_sync_recv["bri"] = receiveNotificationBrightness;
if_sync_recv["col"] = receiveNotificationColor; if_sync_recv["col"] = receiveNotificationColor;
if_sync_recv[F("fx")] = receiveNotificationEffects; if_sync_recv["fx"] = receiveNotificationEffects;
JsonObject if_sync_send = if_sync.createNestedObject("send"); JsonObject if_sync_send = if_sync.createNestedObject("send");
if_sync_send[F("dir")] = notifyDirect; if_sync_send[F("dir")] = notifyDirect;
@ -600,11 +643,15 @@ void serializeConfig() {
JsonArray if_va_macros = if_va.createNestedArray("macros"); JsonArray if_va_macros = if_va.createNestedArray("macros");
if_va_macros.add(macroAlexaOn); if_va_macros.add(macroAlexaOn);
if_va_macros.add(macroAlexaOff); if_va_macros.add(macroAlexaOff);
#ifndef WLED_DISABLE_BLYNK
JsonObject if_blynk = interfaces.createNestedObject("blynk"); JsonObject if_blynk = interfaces.createNestedObject("blynk");
if_blynk[F("token")] = strlen(blynkApiKey) ? "Hidden":""; if_blynk[F("token")] = strlen(blynkApiKey) ? "Hidden":"";
if_blynk[F("host")] = blynkHost; if_blynk[F("host")] = blynkHost;
if_blynk["port"] = blynkPort; if_blynk["port"] = blynkPort;
#endif
#ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces.createNestedObject("mqtt"); JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
if_mqtt["en"] = mqttEnabled; if_mqtt["en"] = mqttEnabled;
if_mqtt[F("broker")] = mqttServer; if_mqtt[F("broker")] = mqttServer;
@ -616,7 +663,9 @@ void serializeConfig() {
JsonObject if_mqtt_topics = if_mqtt.createNestedObject(F("topics")); JsonObject if_mqtt_topics = if_mqtt.createNestedObject(F("topics"));
if_mqtt_topics[F("device")] = mqttDeviceTopic; if_mqtt_topics[F("device")] = mqttDeviceTopic;
if_mqtt_topics[F("group")] = mqttGroupTopic; if_mqtt_topics[F("group")] = mqttGroupTopic;
#endif
#ifndef WLED_DISABLE_HUESYNC
JsonObject if_hue = interfaces.createNestedObject("hue"); JsonObject if_hue = interfaces.createNestedObject("hue");
if_hue["en"] = huePollingEnabled; if_hue["en"] = huePollingEnabled;
if_hue["id"] = huePollLightId; if_hue["id"] = huePollLightId;
@ -631,6 +680,7 @@ void serializeConfig() {
for (byte i = 0; i < 4; i++) { for (byte i = 0; i < 4; i++) {
if_hue_ip.add(hueIP[i]); if_hue_ip.add(hueIP[i]);
} }
#endif
JsonObject if_ntp = interfaces.createNestedObject("ntp"); JsonObject if_ntp = interfaces.createNestedObject("ntp");
if_ntp["en"] = ntpEnabled; if_ntp["en"] = ntpEnabled;
@ -645,7 +695,7 @@ void serializeConfig() {
ol[F("clock")] = overlayDefault; ol[F("clock")] = overlayDefault;
ol[F("cntdwn")] = countdownMode; ol[F("cntdwn")] = countdownMode;
ol[F("min")] = overlayMin; ol["min"] = overlayMin;
ol[F("max")] = overlayMax; ol[F("max")] = overlayMax;
ol[F("o12pix")] = analogClock12pixel; ol[F("o12pix")] = analogClock12pixel;
ol[F("o5m")] = analogClock5MinuteMarks; ol[F("o5m")] = analogClock5MinuteMarks;
@ -666,7 +716,7 @@ void serializeConfig() {
JsonObject timers_ins0 = timers_ins.createNestedObject(); JsonObject timers_ins0 = timers_ins.createNestedObject();
timers_ins0["en"] = (timerWeekday[i] & 0x01); timers_ins0["en"] = (timerWeekday[i] & 0x01);
timers_ins0[F("hour")] = timerHours[i]; timers_ins0[F("hour")] = timerHours[i];
timers_ins0[F("min")] = timerMinutes[i]; timers_ins0["min"] = timerMinutes[i];
timers_ins0[F("macro")] = timerMacro[i]; timers_ins0[F("macro")] = timerMacro[i];
timers_ins0[F("dow")] = timerWeekday[i] >> 1; timers_ins0[F("dow")] = timerWeekday[i] >> 1;
} }
@ -688,7 +738,6 @@ void serializeConfig() {
for (byte i = 0; i < 15; i++) for (byte i = 0; i < 15; i++)
dmx_fixmap.add(DMXFixtureMap[i]); dmx_fixmap.add(DMXFixtureMap[i]);
#endif #endif
//}
JsonObject usermods_settings = doc.createNestedObject("um"); JsonObject usermods_settings = doc.createNestedObject("um");
usermods.addToConfig(usermods_settings); usermods.addToConfig(usermods_settings);
@ -715,15 +764,21 @@ bool deserializeConfigSec() {
JsonObject interfaces = doc["if"]; JsonObject interfaces = doc["if"];
#ifndef WLED_DISABLE_BLYNK
const char* apikey = interfaces["blynk"][F("token")] | "Hidden"; const char* apikey = interfaces["blynk"][F("token")] | "Hidden";
int tdd = strnlen(apikey, 36); int tdd = strnlen(apikey, 36);
if (tdd > 20 || tdd == 0) if (tdd > 20 || tdd == 0)
getStringFromJson(blynkApiKey, apikey, 36); getStringFromJson(blynkApiKey, apikey, 36);
#endif
#ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces["mqtt"]; JsonObject if_mqtt = interfaces["mqtt"];
getStringFromJson(mqttPass, if_mqtt["psk"], 41); getStringFromJson(mqttPass, if_mqtt["psk"], 41);
#endif
#ifndef WLED_DISABLE_HUESYNC
getStringFromJson(hueApiKey, interfaces[F("hue")][F("key")], 47); getStringFromJson(hueApiKey, interfaces[F("hue")][F("key")], 47);
#endif
JsonObject ota = doc["ota"]; JsonObject ota = doc["ota"];
getStringFromJson(otaPass, ota[F("pwd")], 33); getStringFromJson(otaPass, ota[F("pwd")], 33);
@ -750,12 +805,18 @@ void serializeConfigSec() {
ap["psk"] = apPass; ap["psk"] = apPass;
JsonObject interfaces = doc.createNestedObject("if"); JsonObject interfaces = doc.createNestedObject("if");
#ifndef WLED_DISABLE_BLYNK
JsonObject if_blynk = interfaces.createNestedObject("blynk"); JsonObject if_blynk = interfaces.createNestedObject("blynk");
if_blynk[F("token")] = blynkApiKey; if_blynk[F("token")] = blynkApiKey;
#endif
#ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces.createNestedObject("mqtt"); JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
if_mqtt["psk"] = mqttPass; if_mqtt["psk"] = mqttPass;
#endif
#ifndef WLED_DISABLE_HUESYNC
JsonObject if_hue = interfaces.createNestedObject("hue"); JsonObject if_hue = interfaces.createNestedObject("hue");
if_hue[F("key")] = hueApiKey; if_hue[F("key")] = hueApiKey;
#endif
JsonObject ota = doc.createNestedObject("ota"); JsonObject ota = doc.createNestedObject("ota");
ota[F("pwd")] = otaPass; ota[F("pwd")] = otaPass;

View File

@ -31,37 +31,45 @@
#endif #endif
#endif #endif
#ifndef WLED_MAX_BUTTONS
#ifdef ESP8266
#define WLED_MAX_BUTTONS 2
#else
#define WLED_MAX_BUTTONS 4
#endif
#endif
//Usermod IDs //Usermod IDs
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present #define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID #define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
#define USERMOD_ID_EXAMPLE 2 //Usermod "usermod_v2_example.h" #define USERMOD_ID_EXAMPLE 2 //Usermod "usermod_v2_example.h"
#define USERMOD_ID_TEMPERATURE 3 //Usermod "usermod_temperature.h" #define USERMOD_ID_TEMPERATURE 3 //Usermod "usermod_temperature.h"
#define USERMOD_ID_FIXNETSERVICES 4 //Usermod "usermod_Fix_unreachable_netservices.h" #define USERMOD_ID_FIXNETSERVICES 4 //Usermod "usermod_Fix_unreachable_netservices.h"
#define USERMOD_ID_PIRSWITCH 5 //Usermod "usermod_PIR_sensor_switch.h" #define USERMOD_ID_PIRSWITCH 5 //Usermod "usermod_PIR_sensor_switch.h"
#define USERMOD_ID_IMU 6 //Usermod "usermod_mpu6050_imu.h" #define USERMOD_ID_IMU 6 //Usermod "usermod_mpu6050_imu.h"
#define USERMOD_ID_FOUR_LINE_DISP 7 //Usermod "usermod_v2_four_line_display.h #define USERMOD_ID_FOUR_LINE_DISP 7 //Usermod "usermod_v2_four_line_display.h
#define USERMOD_ID_ROTARY_ENC_UI 8 //Usermod "usermod_v2_rotary_encoder_ui.h" #define USERMOD_ID_ROTARY_ENC_UI 8 //Usermod "usermod_v2_rotary_encoder_ui.h"
#define USERMOD_ID_AUTO_SAVE 9 //Usermod "usermod_v2_auto_save.h" #define USERMOD_ID_AUTO_SAVE 9 //Usermod "usermod_v2_auto_save.h"
#define USERMOD_ID_DHT 10 //Usermod "usermod_dht.h" #define USERMOD_ID_DHT 10 //Usermod "usermod_dht.h"
#define USERMOD_ID_MODE_SORT 11 //Usermod "usermod_v2_mode_sort.h" #define USERMOD_ID_MODE_SORT 11 //Usermod "usermod_v2_mode_sort.h"
#define USERMOD_ID_VL53L0X 12 //Usermod "usermod_vl53l0x_gestures.h" #define USERMOD_ID_VL53L0X 12 //Usermod "usermod_vl53l0x_gestures.h"
#define USERMOD_ID_MULTI_RELAY 101 //Usermod "usermod_multi_relay.h" #define USERMOD_ID_MULTI_RELAY 13 //Usermod "usermod_multi_relay.h"
#define USERMOD_ID_ANIMATED_STAIRCASE 102 //Usermod "Animated_Staircase.h" #define USERMOD_ID_ANIMATED_STAIRCASE 14 //Usermod "Animated_Staircase.h"
//Access point behavior //Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
#define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost) #define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost)
#define AP_BEHAVIOR_ALWAYS 2 //Always open #define AP_BEHAVIOR_ALWAYS 2 //Always open
#define AP_BEHAVIOR_BUTTON_ONLY 3 //Only when button pressed for 6 sec #define AP_BEHAVIOR_BUTTON_ONLY 3 //Only when button pressed for 6 sec
//Notifier callMode //Notifier callMode
#define NOTIFIER_CALL_MODE_INIT 0 //no updates on init, can be used to disable updates #define NOTIFIER_CALL_MODE_INIT 0 //no updates on init, can be used to disable updates
#define NOTIFIER_CALL_MODE_DIRECT_CHANGE 1 #define NOTIFIER_CALL_MODE_DIRECT_CHANGE 1
#define NOTIFIER_CALL_MODE_BUTTON 2 #define NOTIFIER_CALL_MODE_BUTTON 2
#define NOTIFIER_CALL_MODE_NOTIFICATION 3 #define NOTIFIER_CALL_MODE_NOTIFICATION 3
#define NOTIFIER_CALL_MODE_NIGHTLIGHT 4 #define NOTIFIER_CALL_MODE_NIGHTLIGHT 4
#define NOTIFIER_CALL_MODE_NO_NOTIFY 5 #define NOTIFIER_CALL_MODE_NO_NOTIFY 5
#define NOTIFIER_CALL_MODE_FX_CHANGED 6 //no longer used #define NOTIFIER_CALL_MODE_FX_CHANGED 6 //no longer used
#define NOTIFIER_CALL_MODE_HUE 7 #define NOTIFIER_CALL_MODE_HUE 7
#define NOTIFIER_CALL_MODE_PRESET_CYCLE 8 #define NOTIFIER_CALL_MODE_PRESET_CYCLE 8
#define NOTIFIER_CALL_MODE_BLYNK 9 #define NOTIFIER_CALL_MODE_BLYNK 9
@ -148,9 +156,10 @@
#define BTN_TYPE_NONE 0 #define BTN_TYPE_NONE 0
#define BTN_TYPE_RESERVED 1 #define BTN_TYPE_RESERVED 1
#define BTN_TYPE_PUSH 2 #define BTN_TYPE_PUSH 2
#define BTN_TYPE_PUSH_ACT_HIGH 3 //not implemented #define BTN_TYPE_PUSH_ACT_HIGH 3
#define BTN_TYPE_SWITCH 4 #define BTN_TYPE_SWITCH 4
#define BTN_TYPE_SWITCH_ACT_HIGH 5 //not implemented #define BTN_TYPE_SWITCH_ACT_HIGH 5
#define BTN_TYPE_TOUCH 6
//Ethernet board types //Ethernet board types
#define WLED_NUM_ETH_TYPES 5 #define WLED_NUM_ETH_TYPES 5
@ -203,7 +212,7 @@
// maximum number of LEDs - more than 1500 LEDs (or 500 DMA "LEDPIN 3" driven ones) will cause a low memory condition on ESP8266 // maximum number of LEDs - more than 1500 LEDs (or 500 DMA "LEDPIN 3" driven ones) will cause a low memory condition on ESP8266
#ifndef MAX_LEDS #ifndef MAX_LEDS
#ifdef ESP8266 #ifdef ESP8266
#define MAX_LEDS 8192 //rely on memory limit to limit this to 1600 LEDs #define MAX_LEDS 1664 // can't rely on memory limit to limit this to 1600 LEDs
#else #else
#define MAX_LEDS 8192 #define MAX_LEDS 8192
#endif #endif
@ -243,7 +252,7 @@
#ifdef ESP8266 #ifdef ESP8266
#define JSON_BUFFER_SIZE 9216 #define JSON_BUFFER_SIZE 9216
#else #else
#define JSON_BUFFER_SIZE 16384 #define JSON_BUFFER_SIZE 20480
#endif #endif
// Maximum size of node map (list of other WLED instances) // Maximum size of node map (list of other WLED instances)

View File

@ -1,356 +1,409 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=500"> <meta name="viewport" content="width=500">
<title>LED Settings</title> <title>LED Settings</title>
<script> <script>
var d=document,laprev=55,maxB=1,maxM=5000,maxPB=4096,bquot=0; //maximum bytes for LED allocation: 5kB for 8266, 32kB for 32 var d=document,laprev=55,maxB=1,maxM=5000,maxPB=4096,bquot=0; //maximum bytes for LED allocation: 5kB for 8266, 32kB for 32
function H() function H()
{ {
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings"); window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings");
} }
function B() function B()
{ {
window.open("/settings","_self"); window.open("/settings","_self");
} }
function off(n){ function gId(n){return d.getElementById(n);}
d.getElementsByName(n)[0].value = -1; function off(n){
} d.getElementsByName(n)[0].value = -1;
function bLimits(b,p,m) { }
maxB = b; maxM = m; maxPB = p; function bLimits(b,p,m) {
} maxB = b; maxM = m; maxPB = p;
function trySubmit(event) { }
event.preventDefault(); function pinsOK() {
var LCs = d.getElementsByTagName("input"); var LCs = d.getElementsByTagName("input");
for (i=0; i<LCs.length; i++) { for (i=0; i<LCs.length; i++) {
var nm = LCs[i].name.substring(0,2); var nm = LCs[i].name.substring(0,2);
//check for pin conflicts
//check for pin conflicts if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
if (nm=="L0" || nm=="L1" || nm=="RL" || nm=="BT" || nm=="IR" || nm=="AX") if (LCs[i].value!="" && LCs[i].value!="-1") {
if (LCs[i].value!="" && LCs[i].value!="-1") { if (d.um_p && d.um_p.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(d.um_p)} can't be used.`);LCs[i].value="";LCs[i].focus();return false;}
if (LCs[i].value > 5 && LCs[i].value < 12) {alert("Sorry, pins 6-11 can not be used.");LCs[i].focus();return;} else if (LCs[i].value > 5 && LCs[i].value < 12) {alert("Sorry, pins 6-11 can not be used.");LCs[i].value="";LCs[i].focus();return false;}
if (d.um_p && d.um_p.some((e)=>e==parseInt(LCs[i].value,10))) {alert("Usermod pin conflict!");LCs[i].focus();return;} for (j=i+1; j<LCs.length; j++)
for (j=i+1; j<LCs.length; j++) {
{ var n2 = LCs[j].name.substring(0,2);
var n2 = LCs[j].name.substring(0,2); if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR")
if (n2=="L0" || n2=="L1" || n2=="RL" || n2=="BT" || n2=="IR" || n2=="AX") if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert(`Pin conflict between ${nm}/${n2}!`);LCs[j].value="";LCs[j].focus();return false;}
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert("Pin conflict!");LCs[i].focus();return;} }
} }
} }
} return true;
if (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += " Consider using an ESP32."; alert(msg); return;} }
if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914 function trySubmit(e) {
if (d.Sf.reportValidity()) d.Sf.submit(); e.preventDefault();
} if (!pinsOK()) {e.stopPropagation();return false;} // Prevent form submission and contact with server
function S(){GetV();setABL();} if (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += "\n\rConsider using an ESP32."; alert(msg);}
function enABL() if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914
{ }
var en = d.getElementById('able').checked; function S(){GetV();setABL();}
d.Sf.LA.value = (en) ? laprev:0; function enABL()
d.getElementById('abl').style.display = (en) ? 'inline':'none'; {
d.getElementById('psu2').style.display = (en) ? 'inline':'none'; var en = gId('able').checked;
if (d.Sf.LA.value > 0) setABL(); d.Sf.LA.value = (en) ? laprev:0;
} gId('abl').style.display = (en) ? 'inline':'none';
function enLA() gId('psu2').style.display = (en) ? 'inline':'none';
{ if (d.Sf.LA.value > 0) setABL();
var val = d.Sf.LAsel.value; }
d.Sf.LA.value = val; function enLA()
d.getElementById('LAdis').style.display = (val == 50) ? 'inline':'none'; {
UI(); var val = d.Sf.LAsel.value;
} d.Sf.LA.value = val;
function setABL() gId('LAdis').style.display = (val == 50) ? 'inline':'none';
{ UI();
d.getElementById('able').checked = true; }
d.Sf.LAsel.value = 50; function setABL()
switch (parseInt(d.Sf.LA.value)) { {
case 0: d.getElementById('able').checked = false; enABL(); break; gId('able').checked = true;
case 30: d.Sf.LAsel.value = 30; break; d.Sf.LAsel.value = 50;
case 35: d.Sf.LAsel.value = 35; break; switch (parseInt(d.Sf.LA.value)) {
case 55: d.Sf.LAsel.value = 55; break; case 0: gId('able').checked = false; enABL(); break;
case 255: d.Sf.LAsel.value = 255; break; case 30: d.Sf.LAsel.value = 30; break;
default: d.getElementById('LAdis').style.display = 'inline'; case 35: d.Sf.LAsel.value = 35; break;
} case 55: d.Sf.LAsel.value = 55; break;
d.getElementById('m1').innerHTML = maxM; case 255: d.Sf.LAsel.value = 255; break;
UI(); default: gId('LAdis').style.display = 'inline';
} }
//returns mem usage gId('m1').innerHTML = maxM;
function getMem(type, len, p0) { d.getElementsByName("Sf")[0].addEventListener("submit", trySubmit);
//len = parseInt(len); UI();
if (type < 32) { }
if (maxM < 10000 && p0 ==3) { //8266 DMA uses 5x the mem //returns mem usage
if (type > 29) return len*20; //RGBW function getMem(type, len, p0) {
return len*15; //len = parseInt(len);
} else if (maxM >= 10000) //ESP32 RMT uses double buffer? if (type < 32) {
{ if (maxM < 10000 && p0==3) { //8266 DMA uses 5x the mem
if (type > 29) return len*8; //RGBW if (type > 29) return len*20; //RGBW
return len*6; return len*15;
} } else if (maxM >= 10000) //ESP32 RMT uses double buffer?
if (type > 29) return len*4; //RGBW {
return len*3; if (type > 29) return len*8; //RGBW
} return len*6;
if (type > 31 && type < 48) return 5; }
if (type == 44 || type == 45) return len*4; //RGBW if (type > 29) return len*4; //RGBW
return len*3; return len*3;
} }
function UI() if (type > 31 && type < 48) return 5;
{ if (type == 44 || type == 45) return len*4; //RGBW
var isRGBW = false, memu = 0; return len*3;
}
d.getElementById('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none'; function UI(change=false)
{
if (d.Sf.LA.value == 255) laprev = 12; var isRGBW = false, memu = 0;
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
gId('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none';
var s = d.getElementsByTagName("select");
for (i=0; i<s.length; i++) { if (d.Sf.LA.value == 255) laprev = 12;
if (s[i].name.substring(0,2)=="LT") { else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
n=s[i].name.substring(2);
var type = s[i].value; var s = d.getElementsByTagName("select");
d.getElementById("p0d"+n).innerHTML = (type > 49) ? "Data pin:" : (type >41) ? "Pins:" : "Pin:"; for (i=0; i<s.length; i++) {
d.getElementById("p1d"+n).innerHTML = (type > 49) ? "Clk:" : ""; if (s[i].name.substring(0,2)=="LT") {
var LK = d.getElementsByName("L1"+n)[0]; n=s[i].name.substring(2);
var type = parseInt(s[i].value,10);
memu += getMem(type, d.getElementsByName("LC"+n)[0].value, d.getElementsByName("L0"+n)[0].value); gId("p0d"+n).innerHTML = (type > 49) ? "Data:" : (type >41) ? "Pins:" : "Pin:";
gId("p1d"+n).innerHTML = (type > 49) ? "Clk:" : "";
for (p=1; p<5; p++) { var LK = d.getElementsByName("L1"+n)[0];
var LK = d.getElementsByName("L"+p+n)[0];
if (!LK) continue; memu += getMem(type, d.getElementsByName("LC"+n)[0].value, d.getElementsByName("L0"+n)[0].value);
if ((type>49 && p==1) || (type>41 && type < 50 && (p+40 < type))) // TYPE_xxxx values from const.h
{ for (p=1; p<5; p++) {
LK.style.display = "inline"; var LK = d.getElementsByName("L"+p+n)[0];
LK.required = true; if (!LK) continue;
} else { if ((type>49 && p==1) || (type>41 && type < 50 && (p+40 < type))) // TYPE_xxxx values from const.h
LK.style.display = "none"; {
LK.required = false; LK.style.display = "inline";
LK.value=""; LK.required = true;
} } else {
} LK.style.display = "none";
if (type == 30 || type == 31 || (type > 40 && type < 46 && type != 43)) isRGBW = true; LK.required = false;
d.getElementById("dig"+n).style.display = (type > 31 && type < 48) ? "none":"inline"; LK.value="";
d.getElementById("psd"+n).innerHTML = (type > 31 && type < 48) ? "Index:":"Start:"; }
} }
} if (type == 30 || type == 31 || (type > 40 && type < 46 && type != 43)) isRGBW = true;
gId("dig"+n).style.display = (type > 31 && type < 48) ? "none":"inline";
var myC = d.querySelectorAll('.wc'), gId("psd"+n).innerHTML = (type > 31 && type < 48) ? "Index:":"Start:";
l = myC.length; }
for (i = 0; i < l; i++) { }
myC[i].style.display = (isRGBW) ? 'inline':'none';
} var myC = d.querySelectorAll('.wc'),
l = myC.length;
if (d.activeElement == d.getElementsByName("LC")[0]) { for (i = 0; i < l; i++) {
var o = d.getElementsByClassName("iST"); myC[i].style.display = (isRGBW) ? 'inline':'none';
var i = o.length; }
if (i == 1) d.getElementsByName("LC0")[0].value = d.getElementsByName("LC")[0].value;
} if (d.activeElement == d.getElementsByName("LC")[0]) {
var o = d.getElementsByClassName("iST");
var LCs = d.getElementsByTagName("input"); var i = o.length;
var sLC = 0, maxLC = 0; if (i == 1) d.getElementsByName("LC0")[0].value = d.getElementsByName("LC")[0].value;
for (i=0; i<LCs.length; i++) { }
var nm = LCs[i].name.substring(0,2);
if (nm=="LC" && LCs[i].name != "LC") {var c = parseInt(LCs[i].value,10); if (c) {sLC+=c; if (c>maxLC) maxLC = c;} continue;} var LCs = d.getElementsByTagName("input");
} var sLC = 0, maxLC = 0;
for (i=0; i<LCs.length; i++) {
d.getElementById('m0').innerHTML = memu; var nm = LCs[i].name.substring(0,2);
bquot = memu / maxM * 100; if (nm=="LC" && LCs[i].name !== "LC") {
d.getElementById('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? bquot > 90 ? "red":"orange":"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`; var n=LCs[i].name.substring(2);
d.getElementById('ledwarning').style.display = (maxLC > 800 || bquot > 80) ? 'inline':'none'; var c=parseInt(LCs[i].value,10);
//TODO add warning "Recommended pins on ESP8266 are 1 and 2 (3 only with low LED count)" if(gId("ls"+n).readOnly) gId("ls"+n).value=sLC;
//TODO add overmemory warning if(c){sLC+=c;if(c>maxLC)maxLC=c;}
//TODO block disallowed pins 6-11 continue;
d.getElementById('wreason').innerHTML = (bquot > 80) ? "than 60%% of max. LED memory" : "800 LEDs per pin"; }
if (nm=="L0" || nm=="L1") {
//var val = Math.ceil((100 + d.Sf.LC.value * laprev)/500)/2; var lc=d.getElementsByName("LC"+LCs[i].name.substring(2))[0];
var val = Math.ceil((100 + sLC * laprev)/500)/2; lc.max=maxPB;
val = (val > 5) ? Math.ceil(val) : val; }
var s = ""; if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
var is12V = (d.Sf.LAsel.value == 30); if (LCs[i].value!="" && LCs[i].value!="-1") {
var isWS2815 = (d.Sf.LAsel.value == 255); var p = [];
if (val < 1.02 && !is12V && !isWS2815) if (d.um_p && Array.isArray(d.um_p)) for (k=0;k<d.um_p.length;k++) p.push(d.um_p[k]);
{ for (j=0; j<LCs.length; j++) {
s = "ESP 5V pin with 1A USB supply"; if (i==j) continue;
} else var n2 = LCs[j].name.substring(0,2);
{ if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR")
s += is12V ? "12V ": isWS2815 ? "WS2815 12V " : "5V "; if (LCs[j].value!="" && LCs[j].value!="-1") p.push(parseInt(LCs[j].value,10));
s += val; }
s += "A supply connected to LEDs"; if (p.some((e)=>e==parseInt(LCs[i].value,10))) LCs[i].style.color="red"; else LCs[i].style.color="#fff";
} }
var val2 = Math.ceil((100 + sLC * laprev)/1500)/2; }
val2 = (val2 > 5) ? Math.ceil(val2) : val2;
var s2 = "(for most effects, ~"; gId('m0').innerHTML = memu;
s2 += val2; bquot = memu / maxM * 100;
s2 += "A is enough)<br>"; gId('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? (bquot > 90 ? "red":"orange"):"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`;
d.getElementById('psu').innerHTML = s; gId('ledwarning').style.display = (sLC > maxPB || maxLC > 800 || bquot > 80) ? 'inline':'none';
d.getElementById('psu2').innerHTML = isWS2815 ? "" : s2; gId('ledwarning').style.color = (sLC > maxPB || maxLC > maxPB || bquot > 100) ? 'red':'orange';
} gId('wreason').innerHTML = (bquot > 80) ? "80% of max. LED memory" +(bquot>100 ? ` (<b>WARNING: Using over ${maxM}B!</b>)` : "") : "800 LEDs per pin";
function lastEnd(i) {
if (i<1) return 0; //var val = Math.ceil((100 + d.Sf.LC.value * laprev)/500)/2;
v = parseInt(d.getElementsByName("LS"+(i-1))[0].value) + parseInt(d.getElementsByName("LC"+(i-1))[0].value); var val = Math.ceil((100 + sLC * laprev)/500)/2;
if (isNaN(v)) return 0; val = (val > 5) ? Math.ceil(val) : val;
return v; var s = "";
} var is12V = (d.Sf.LAsel.value == 30);
function addLEDs(n) var isWS2815 = (d.Sf.LAsel.value == 255);
{ if (val < 1.02 && !is12V && !isWS2815)
if (n>1) {maxB=n; d.getElementById("+").style.display="inline"; return;} {
s = "ESP 5V pin with 1A USB supply";
var o = d.getElementsByClassName("iST"); } else
var i = o.length; {
s += is12V ? "12V ": isWS2815 ? "WS2815 12V " : "5V ";
if ((n==1 && i>=maxB) || (n==-1 && i==0)) return; s += val;
s += "A supply connected to LEDs";
var f = d.getElementById("mLC"); }
if (n==1) { var val2 = Math.ceil((100 + sLC * laprev)/1500)/2;
var cn = `<div class="iST"> val2 = (val2 > 5) ? Math.ceil(val2) : val2;
${i>0?'<hr style="width:260px">':''} var s2 = "(for most effects, ~";
${i+1}: s2 += val2;
<select name="LT${i}" onchange="UI()"> s2 += "A is enough)<br>";
<option value="22">WS281x</option> gId('psu').innerHTML = s;
<option value="30">SK6812 RGBW</option> gId('psu2').innerHTML = isWS2815 ? "" : s2;
<option value="31">TM1814</option> }
<option value="24">400kHz</option> function lastEnd(i) {
<option value="50">WS2801</option> if (i<1) return 0;
<option value="51">APA102</option> v = parseInt(d.getElementsByName("LS"+(i-1))[0].value) + parseInt(d.getElementsByName("LC"+(i-1))[0].value);
<option value="52">LPD8806</option> if (isNaN(v)) return 0;
<option value="53">P9813</option> return v;
<option value="41">PWM White</option> }
<option value="42">PWM WWCW</option> function addLEDs(n)
<option value="43">PWM RGB</option> {
<option value="44">PWM RGBW</option> if (n>1) {maxB=n; gId("+").style.display="inline"; return;}
<option value="45">PWM RGBWC</option>
</select>&nbsp; var o = d.getElementsByClassName("iST");
Color Order: var i = o.length;
<select name="CO${i}">
<option value="0">GRB</option> if ((n==1 && i>=maxB) || (n==-1 && i==0)) return;
<option value="1">RGB</option>
<option value="2">BRG</option> var f = gId("mLC");
<option value="3">RBG</option> if (n==1) {
<option value="4">BGR</option> // npm run build has trouble minimizing spaces inside string
<option value="5">GBR</option> var cn = `<div class="iST">
</select><br> ${i>0?'<hr style="width:260px">':''}
<span id="p0d${i}">Pin:</span> <input type="number" name="L0${i}" min="0" max="40" required style="width:35px" oninput="UI()"/> ${i+1}:
<span id="p1d${i}">Clock:</span> <input type="number" name="L1${i}" min="0" max="40" style="width:35px"/> <select name="LT${i}" onchange="UI()">
<span id="p2d${i}"></span><input type="number" name="L2${i}" min="0" max="40" style="width:35px"/> <option value="22">WS281x</option>
<span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="40" style="width:35px"/> <option value="30">SK6812 RGBW</option>
<span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="40" style="width:35px"/> <option value="31">TM1814</option>
<br> <option value="24">400kHz</option>
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" min="0" max="8191" value="${lastEnd(i)}" required />&nbsp; <option value="50">WS2801</option>
<div id="dig${i}" style="display:inline"> <option value="51">APA102</option>
Count: <input type="number" name="LC${i}" min="0" max="${maxPB}" value="1" required oninput="UI()" /><br> <option value="52">LPD8806</option>
Skip 1<sup>st</sup> LED: <input id="sl${i}" type="checkbox" name="SL${i}">&nbsp; <option value="53">P9813</option>
</div> <option value="41">PWM White</option>
Reverse: <input type="checkbox" name="CV${i}"><br> <option value="42">PWM WWCW</option>
</div>`; <option value="43">PWM RGB</option>
f.insertAdjacentHTML("beforeend", cn); <option value="44">PWM RGBW</option>
} <option value="45">PWM RGBWC</option>
if (n==-1) { </select>&nbsp;
o[--i].remove();--i; Color Order:
} <select name="CO${i}">
<option value="0">GRB</option>
d.getElementById("+").style.display = (i<maxB-1) ? "inline":"none"; <option value="1">RGB</option>
d.getElementById("-").style.display = (i>0) ? "inline":"none"; <option value="2">BRG</option>
<option value="3">RBG</option>
UI(); <option value="4">BGR</option>
} <option value="5">GBR</option>
function GetV() </select><br>
{ <span id="p0d${i}">Pin:</span> <input type="number" name="L0${i}" min="0" max="40" required style="width:35px" onchange="UI()"/>
//values injected by server while sending HTML <span id="p1d${i}">Clock:</span> <input type="number" name="L1${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
//d.um_p=[];addLEDs(3);d.Sf.LC.value=250;addLEDs(1);d.Sf.L00.value=2;d.Sf.L10.value=0;d.Sf.LC0.value=250;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=0;d.Sf.LS0.checked=0;d.Sf.MA.value=5400;d.Sf.LA.value=55;d.getElementsByClassName("pow")[0].innerHTML="350mA";d.Sf.CA.value=40;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=3;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=64;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RV.checked=0;d.Sf.SL.checked=0;d.Sf.RL.value=12;d.Sf.RM.checked=0;d.Sf.BT.value=-1;d.Sf.IR.value=-1;d.Sf.AX.value=-1; <span id="p2d${i}"></span><input type="number" name="L2${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
} <span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
</script> <span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
<style> <br>
@import url("style.css"); <span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" min="0" max="8191" value="${lastEnd(i)}" required />&nbsp;
</style> <div id="dig${i}" style="display:inline">
</head> Count: <input type="number" name="LC${i}" min="0" max="${maxPB}" value="1" required oninput="UI()" /><br>
<body onload="S()"> Reverse (rotated 180°): <input type="checkbox" name="CV${i}">
<form id="form_s" name="Sf" method="post" onsubmit="trySubmit(event)"> &nbsp;Skip 1<sup>st</sup> LED: <input id="sl${i}" type="checkbox" name="SL${i}"><br>
<div class="helpB"><button type="button" onclick="H()">?</button></div> </div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr> </div>`;
<h2>LED &amp; Hardware setup</h2> f.insertAdjacentHTML("beforeend", cn);
Total LED count: <input name="LC" type="number" min="1" max="8192" oninput="UI()" required><br> }
<i>Recommended power supply for brightest white:</i><br> if (n==-1) {
<b><span id="psu">?</span></b><br> o[--i].remove();--i;
<span id="psu2"><br></span> }
<br>
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br> gId("+").style.display = (i<maxB-1) ? "inline":"none";
<div id="abl"> gId("-").style.display = (i>0) ? "inline":"none";
Maximum Current: <input name="MA" type="number" min="250" max="65000" oninput="UI()" required> mA<br>
<div id="ampwarning" style="color: orange; display: none;"> UI();
&#9888; Your power supply provides high current.<br> }
To improve the safety of your setup,<br> function addBtn(i,p,t) {
please use thick cables,<br> var c = gId("btns").innerHTML;
multiple power injection points and a fuse!<br> var bt = "BT" + i;
</div> var be = "BE" + i;
<i>Automatically limits brightness to stay close to the limit.<br> c += `Button ${i} pin: <input type="number" min="-1" max="40" name="${bt}" onchange="UI()" value="${p}">`;
Keep at &lt;1A if powering LEDs directly from the ESP 5V pin!<br> c += `<select name="${be}">`
If you are using an external power supply, enter its rating.<br> c += `<option value="0" ${t==0?"selected":""}>Disabled</option>`;
(Current estimated usage: <span class="pow">unknown</span>)</i><br><br> c += `<option value="2" ${t==2?"selected":""}>Pushbutton</option>`;
LED voltage (Max. current for a single LED):<br> c += `<option value="2" ${t==3?"selected":""}>Push inverted</option>`;
<select name="LAsel" onchange="enLA()"> c += `<option value="4" ${t==4?"selected":""}>Switch</option>`;
<option value="55" selected>5V default (55mA)</option> c += `<option value="5" ${t==4?"selected":""}>Switch inverted</option>`;
<option value="35">5V efficient (35mA)</option> c += `<option value="6" ${t==6?"selected":""}>Touch</option>`;
<option value="30">12V (30mA)</option> c += `</select>`;
<option value="255">WS2815 (12mA)</option> c += `<span style="cursor: pointer;" onclick="off('${bt}')">&nbsp;&#215;</span><br>`;
<option value="50">Custom</option> gId("btns").innerHTML = c;
</select><br> }
<span id="LAdis" style="display: none;">Custom max. current per LED: <input name="LA" type="number" min="0" max="255" id="la" oninput="UI()" required> mA<br></span> function GetV()
<i>Keep at default if you are unsure about your type of LEDs.</i><br> {
</div> //values injected by server while sending HTML
<h3>Hardware setup</h3> //maxM=5000;maxPB=1536;d.um_p=[1,6,7,8,9,10,11];addLEDs(3);d.Sf.LC.value=250;addLEDs(1);d.Sf.L00.value=2;d.Sf.L10.value=0;d.Sf.LC0.value=250;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=0;d.Sf.LS0.checked=0;d.Sf.MA.value=5400;d.Sf.LA.value=55;d.getElementsByClassName("pow")[0].innerHTML="350mA";d.Sf.CA.value=40;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=3;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=64;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=12;d.Sf.RM.checked=0;addBtn(0,0,2);addBtn(1,3,4);addBtn(2,-1,0);d.Sf.IR.value=-1;
<div id="mLC">LED outputs:</div> }
<button type="button" id="+" onclick="addLEDs(1)" style="display:none;border-radius:20px;height:36px;">+</button> </script>
<button type="button" id="-" onclick="addLEDs(-1)" style="display:none;border-radius:20px;width:36px;height:36px;">-</button><br> <style>
LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br> @import url("style.css");
<div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br> </style>
<div id="ledwarning" style="color: orange; display: none;"> </head>
&#9888; You might run into stability or lag issues.<br> <body onload="S()">
Use less than <span id="wreason">800 LEDs per pin</span> for the best experience!<br> <form id="form_s" name="Sf" method="post">
</div> <div class="helpB"><button type="button" onclick="H()">?</button></div>
Button pin: <input type="number" min="-1" max="40" name="BT" onchange="UI()"><span style="cursor: pointer;" onclick="off('BT')">&nbsp;&#215;</span><br> <button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
IR pin: <input type="number" min="-1" max="40" name="IR" onchange="UI()"><span style="cursor: pointer;" onclick="off('IR')">&nbsp;&#215;</span><br> <h2>LED &amp; Hardware setup</h2>
Relay pin: <input type="number" min="-1" max="40" name="RL" onchange="UI()"><span style="cursor: pointer;" onclick="off('RL')">&nbsp;&#215;</span><br> Total LED count: <input name="LC" id="LC" type="number" min="1" max="8192" oninput="UI()" required><br>
Active high <input type="checkbox" name="RM"> <i>Recommended power supply for brightest white:</i><br>
<h3>Defaults</h3> <b><span id="psu">?</span></b><br>
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br> <span id="psu2"><br></span>
Default brightness: <input name="CA" type="number" min="0" max="255" required> (0-255)<br><br> <br>
Apply preset <input name="BP" type="number" min="0" max="250" required> at boot (0 uses defaults) Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
<br>- <i>or</i> -<br> <div id="abl">
Set current preset cycle setting as boot default: <input type="checkbox" name="PC"><br><br> Maximum Current: <input name="MA" type="number" min="250" max="65000" oninput="UI()" required> mA<br>
Use Gamma correction for color: <input type="checkbox" name="GC"> (strongly recommended)<br> <div id="ampwarning" style="color: orange; display: none;">
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br><br> &#9888; Your power supply provides high current.<br>
Brightness factor: <input name="BF" type="number" min="1" max="255" required> % To improve the safety of your setup,<br>
<h3>Transitions</h3> please use thick cables,<br>
Crossfade: <input type="checkbox" name="TF"><br> multiple power injection points and a fuse!<br>
Transition Time: <input name="TD" maxlength="5" size="2"> ms<br> </div>
Enable Palette transitions: <input type="checkbox" name="PF"> <i>Automatically limits brightness to stay close to the limit.<br>
<h3>Timed light</h3> Keep at &lt;1A if powering LEDs directly from the ESP 5V pin!<br>
Default Duration: <input name="TL" type="number" min="1" max="255" required> min<br> If you are using an external power supply, enter its rating.<br>
Default Target brightness: <input name="TB" type="number" min="0" max="255" required><br> (Current estimated usage: <span class="pow">unknown</span>)</i><br><br>
Mode: LED voltage (Max. current for a single LED):<br>
<select name="TW"> <select name="LAsel" onchange="enLA()">
<option value="0">Wait and set</option> <option value="55" selected>5V default (55mA)</option>
<option value="1">Fade</option> <option value="35">5V efficient (35mA)</option>
<option value="2">Fade Color</option> <option value="30">12V (30mA)</option>
<option value="3">Sunrise</option> <option value="255">WS2815 (12mA)</option>
</select> <option value="50">Custom</option>
<h3>Advanced</h3> </select><br>
Palette blending: <span id="LAdis" style="display: none;">Custom max. current per LED: <input name="LA" type="number" min="0" max="255" id="la" oninput="UI()" required> mA<br></span>
<select name="PB"> <i>Keep at default if you are unsure about your type of LEDs.</i><br>
<option value="0">Linear (wrap if moving)</option> </div>
<option value="1">Linear (always wrap)</option> <h3>Hardware setup</h3>
<option value="2">Linear (never wrap)</option> <div id="mLC">LED outputs:</div>
<option value="3">None (not recommended)</option> <button type="button" id="+" onclick="addLEDs(1)" style="display:none;border-radius:20px;height:36px;">+</button>
</select><br> <button type="button" id="-" onclick="addLEDs(-1)" style="display:none;border-radius:20px;width:36px;height:36px;">-</button><br>
<span class="wc"> LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
Auto-calculate white channel from RGB:<br> <div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
<select name="AW"> <div id="ledwarning" style="color: orange; display: none;">
<option value=0>None</option> &#9888; You might run into stability or lag issues.<br>
<option value=1>Brighter</option> Use less than <span id="wreason">800 LEDs per pin</span> for the best experience!<br>
<option value=2>Accurate</option> </div><hr style="width:260px">
<option value=3>Dual</option> <div id="btns"></div>
<option value=4>Legacy</option> Touch threshold: <input type="number" min="0" max="100" name="TT" required><br>
</select> IR pin: <input type="number" min="-1" max="40" name="IR" onchange="UI()"><select name="IT">
<br></span><hr> <option value="0">Remote disabled</option>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button> <option value="1">24-key RGB</option>
</form> <option value="2">24-key with CT</option>
</body> <option value="3">40-key blue</option>
</html> <option value="4">44-key RGB</option>
<option value="5">21-key RGB</option>
<option value="6">6-key black</option>
<option value="7">9-key red</option>
<option value="8">JSON remote</option>
</select><span style="cursor: pointer;" onclick="off('IR')">&nbsp;&#215;</span><br>
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a><br>
Relay pin: <input type="number" min="-1" max="40" name="RL" onchange="UI()"> invert <input type="checkbox" name="RM"><span style="cursor: pointer;" onclick="off('RL')">&nbsp;&#215;</span><br>
<hr style="width:260px">
<h3>Defaults</h3>
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br>
Default brightness: <input name="CA" type="number" min="0" max="255" required> (0-255)<br><br>
Apply preset <input name="BP" type="number" min="0" max="250" required> at boot (0 uses defaults)
<br>- <i>or</i> -<br>
Set current preset cycle setting as boot default: <input type="checkbox" name="PC"><br><br>
Use Gamma correction for color: <input type="checkbox" name="GC"> (strongly recommended)<br>
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br><br>
Brightness factor: <input name="BF" type="number" min="1" max="255" required> %
<h3>Transitions</h3>
Crossfade: <input type="checkbox" name="TF"><br>
Transition Time: <input name="TD" maxlength="5" size="2"> ms<br>
Enable Palette transitions: <input type="checkbox" name="PF">
<h3>Timed light</h3>
Default Duration: <input name="TL" type="number" min="1" max="255" required> min<br>
Default Target brightness: <input name="TB" type="number" min="0" max="255" required><br>
Mode:
<select name="TW">
<option value="0">Wait and set</option>
<option value="1">Fade</option>
<option value="2">Fade Color</option>
<option value="3">Sunrise</option>
</select>
<h3>Advanced</h3>
Palette blending:
<select name="PB">
<option value="0">Linear (wrap if moving)</option>
<option value="1">Linear (always wrap)</option>
<option value="2">Linear (never wrap)</option>
<option value="3">None (not recommended)</option>
</select><br>
<span class="wc">
Auto-calculate white channel from RGB:<br>
<select name="AW">
<option value=0>None</option>
<option value=1>Brighter</option>
<option value=2>Accurate</option>
<option value=3>Dual</option>
<option value=4>Legacy</option>
</select>
<br></span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
</form>
</body>
</html>

View File

@ -15,29 +15,10 @@ function GetV(){var d=document;}
<div class="helpB"><button type="button" onclick="H()">?</button></div> <div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr> <button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<h2>Sync setup</h2> <h2>Sync setup</h2>
<h3>Button setup</h3>
Button type:
<select name=BT>
<option value=0>Disabled</option>
<option value=2>Pushbutton</option>
<option value=4>Switch</option>
</select><br>
Infrared remote:
<select name=IR>
<option value=0>Disabled</option>
<option value=1>24-key RGB</option>
<option value=2>24-key with CT</option>
<option value=3>40-key blue</option>
<option value=4>44-key RGB</option>
<option value=5>21-key RGB</option>
<option value=6>6-key black</option>
<option value=7>9-key red</option>
</select><br>
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a>
<h3>WLED Broadcast</h3> <h3>WLED Broadcast</h3>
UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br> UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br>
2nd Port: <input name="U2" type="number" min="1" max="65535" class="d5" required><br> 2nd Port: <input name="U2" type="number" min="1" max="65535" class="d5" required><br>
Receive <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br> Receive: <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br>
Send notifications on direct change: <input type="checkbox" name="SD"><br> Send notifications on direct change: <input type="checkbox" name="SD"><br>
Send notifications on button press or IR: <input type="checkbox" name="SB"><br> Send notifications on button press or IR: <input type="checkbox" name="SB"><br>
Send Alexa notifications: <input type="checkbox" name="SA"><br> Send Alexa notifications: <input type="checkbox" name="SA"><br>

View File

@ -6,41 +6,41 @@
<title>Time Settings</title> <title>Time Settings</title>
<script> <script>
var d=document; var d=document;
function H() function H()
{
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings");
}
function B()
{
window.open("/settings","_self");
}
function S()
{
BTa();GetV();Cs();FC();
}
function gId(s)
{
return d.getElementById(s);
}
function Cs()
{
gId("cac").style.display="none";
gId("coc").style.display="block";
gId("ccc").style.display="none";
if (gId("ca").selected)
{ {
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings"); gId("cac").style.display="block";
} }
function B() if (gId("cc").selected)
{ {
window.open("/settings","_self"); gId("coc").style.display="none";
gId("ccc").style.display="block";
} }
function S() if (gId("cn").selected)
{ {
BTa();GetV();Cs();FC(); gId("coc").style.display="none";
}
function gId(s)
{
return d.getElementById(s);
}
function Cs()
{
gId("cac").style.display="none";
gId("coc").style.display="block";
gId("ccc").style.display="none";
if (gId("ca").selected)
{
gId("cac").style.display="block";
}
if (gId("cc").selected)
{
gId("coc").style.display="none";
gId("ccc").style.display="block";
}
if (gId("cn").selected)
{
gId("coc").style.display="none";
}
} }
}
function BTa() function BTa()
{ {
var ih="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Preset</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>"; var ih="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Preset</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";
@ -75,10 +75,25 @@
gId("W"+i).value=a[i]; gId("W"+i).value=a[i];
} }
} }
function GetV() function addRow(i,p,l,d) {
{ var t = gId("macros"); // table
//values injected by server while sending HTML var rCnt = t.rows.length; // get the number of rows.
} var tr = t.insertRow(rCnt); // table row.
var td = document.createElement('td'); // TABLE DEFINITION.
td = tr.insertCell(0);
td.innerHTML = `Button ${i}:`;
td = tr.insertCell(1);
td.innerHTML = `<input name="MP${i}" type="number" min="0" max="250" value="${p}" required>`;
td = tr.insertCell(2);
td.innerHTML = `<input name="ML${i}" type="number" min="0" max="250" value="${l}" required>`;
td = tr.insertCell(3);
td.innerHTML = `<input name="MD${i}" type="number" min="0" max="250" value="${d}" required>`;
}
function GetV()
{
//values injected by server while sending HTML
}
</script> </script>
<style> <style>
@import url("style.css"); @import url("style.css");
@ -107,12 +122,12 @@
<option value="10">JST(KST)</option> <option value="10">JST(KST)</option>
<option value="11">AEST/AEDT</option> <option value="11">AEST/AEDT</option>
<option value="12">NZST/NZDT</option> <option value="12">NZST/NZDT</option>
<option value="13">North Korea</option> <option value="13">North Korea</option>
<option value="14">IST (India)</option> <option value="14">IST (India)</option>
<option value="15">CA-Saskatchewan</option> <option value="15">CA-Saskatchewan</option>
<option value="16">ACST</option> <option value="16">ACST</option>
<option value="17">ACST/ACDT</option> <option value="17">ACST/ACDT</option>
<option value="18">HST (Hawaii)</option> <option value="18">HST (Hawaii)</option>
</select><br> </select><br>
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br> UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
Current local time is <span class="times">unknown</span>.<br> Current local time is <span class="times">unknown</span>.<br>
@ -143,15 +158,26 @@
Year: 20 <input name="CY" type="number" min="0" max="99" required> Month: <input name="CI" type="number" min="1" max="12" required> Day: <input name="CD" type="number" min="1" max="31" required><br> Year: 20 <input name="CY" type="number" min="0" max="99" required> Month: <input name="CI" type="number" min="1" max="12" required> Day: <input name="CD" type="number" min="1" max="31" required><br>
Hour: <input name="CH" type="number" min="0" max="23" required> Minute: <input name="CM" type="number" min="0" max="59" required> Second: <input name="CS" type="number" min="0" max="59" required><br> Hour: <input name="CH" type="number" min="0" max="23" required> Minute: <input name="CM" type="number" min="0" max="59" required> Second: <input name="CS" type="number" min="0" max="59" required><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" type="number" min="0" max="250" required> <input name="A1" type="number" min="0" max="250" required><br> Alexa On/Off Preset: <input name="A0" type="number" min="0" max="250" required> <input name="A1" type="number" min="0" max="250" required><br>
Button short press Preset: <input name="MP" type="number" min="0" max="250" required><br>
Long Press: <input name="ML" type="number" min="0" max="250" required> Double press: <input name="MD" type="number" min="0" max="250" required><br>
Countdown-Over Preset: <input name="MC" type="number" min="0" max="250" required><br> Countdown-Over Preset: <input name="MC" type="number" min="0" max="250" required><br>
Timed-Light-Over Presets: <input name="MN" type="number" min="0" max="250" required><br> Timed-Light-Over Presets: <input name="MN" type="number" min="0" max="250" required><br>
<h3>Button actions</h3>
<table style="margin: 0 auto;" id="macros">
<thead>
<tr>
<td>push<br>switch</td>
<td>short<br>on-&gt;off</td>
<td>long<br>off-&gt;on</td>
<td>double<br>N/A</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
<h3>Time-controlled presets</h3> <h3>Time-controlled presets</h3>
<div style="display: inline-block"> <div style="display: inline-block">
<table id="TMT"> <table id="TMT">

View File

@ -20,8 +20,8 @@ void handleBlynk();
void updateBlynk(); void updateBlynk();
//button.cpp //button.cpp
void shortPressAction(); void shortPressAction(uint8_t b=0);
bool isButtonPressed(); bool isButtonPressed(uint8_t b=0);
void handleButton(); void handleButton();
void handleIO(); void handleIO();

File diff suppressed because one or more lines are too long

View File

@ -81,9 +81,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
#ifndef WLED_DISABLE_INFRARED #ifndef WLED_DISABLE_INFRARED
if (irPin>=0 && pinManager.isPinAllocated(irPin)) pinManager.deallocatePin(irPin); if (irPin>=0 && pinManager.isPinAllocated(irPin)) pinManager.deallocatePin(irPin);
#endif #endif
if (btnPin>=0 && pinManager.isPinAllocated(btnPin)) pinManager.deallocatePin(btnPin); for (uint8_t s=0; s<WLED_MAX_BUTTONS; s++)
//TODO remove all busses, but not in this system call if (btnPin[s]>=0 && pinManager.isPinAllocated(btnPin[s]))
//busses->removeAll(); pinManager.deallocatePin(btnPin[s]);
strip.isRgbw = false; strip.isRgbw = false;
uint8_t colorOrder, type, skip; uint8_t colorOrder, type, skip;
@ -99,7 +99,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse
char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED
if (!request->hasArg(lp)) { if (!request->hasArg(lp)) {
DEBUG_PRINTLN("No data."); break; DEBUG_PRINTLN(F("No data.")); break;
} }
for (uint8_t i = 0; i < 5; i++) { for (uint8_t i = 0; i < 5; i++) {
lp[1] = 48+i; lp[1] = 48+i;
@ -109,7 +109,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
type = request->arg(lt).toInt(); type = request->arg(lt).toInt();
strip.isRgbw = strip.isRgbw || BusManager::isRgbw(type); strip.isRgbw = strip.isRgbw || BusManager::isRgbw(type);
skip = request->hasArg(sl) ? LED_SKIP_AMOUNT : 0; skip = request->hasArg(sl) ? LED_SKIP_AMOUNT : 0;
if (request->hasArg(lc) && request->arg(lc).toInt() > 0) { if (request->hasArg(lc) && request->arg(lc).toInt() > 0) {
length = request->arg(lc).toInt(); length = request->arg(lc).toInt();
} else { } else {
@ -128,14 +128,13 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (t > 0 && t <= MAX_LEDS) ledCount = t; if (t > 0 && t <= MAX_LEDS) ledCount = t;
// upate other pins // upate other pins
#ifndef WLED_DISABLE_INFRARED
int hw_ir_pin = request->arg(F("IR")).toInt(); int hw_ir_pin = request->arg(F("IR")).toInt();
if (pinManager.isPinOk(hw_ir_pin) && pinManager.allocatePin(hw_ir_pin,false)) { if (pinManager.allocatePin(hw_ir_pin,false)) {
irPin = hw_ir_pin; irPin = hw_ir_pin;
} else { } else {
irPin = -1; irPin = -1;
} }
#endif irEnabled = request->arg(F("IT")).toInt();
int hw_rly_pin = request->arg(F("RL")).toInt(); int hw_rly_pin = request->arg(F("RL")).toInt();
if (pinManager.allocatePin(hw_rly_pin,true)) { if (pinManager.allocatePin(hw_rly_pin,true)) {
@ -145,13 +144,20 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
} }
rlyMde = (bool)request->hasArg(F("RM")); rlyMde = (bool)request->hasArg(F("RM"));
int hw_btn_pin = request->arg(F("BT")).toInt(); for (uint8_t i=0; i<WLED_MAX_BUTTONS; i++) {
if (pinManager.allocatePin(hw_btn_pin,false)) { char bt[4] = "BT"; bt[2] = 48+i; bt[3] = 0; // button pin
btnPin = hw_btn_pin; char be[4] = "BE"; be[2] = 48+i; be[3] = 0; // button type
pinMode(btnPin, INPUT_PULLUP); int hw_btn_pin = request->arg(bt).toInt();
} else { if (pinManager.allocatePin(hw_btn_pin,false)) {
btnPin = -1; btnPin[i] = hw_btn_pin;
pinMode(btnPin[i], INPUT_PULLUP);
buttonType[i] = request->arg(be).toInt();
} else {
btnPin[i] = -1;
buttonType[i] = BTN_TYPE_NONE;
}
} }
touchThreshold = request->arg(F("TT")).toInt();
strip.ablMilliampsMax = request->arg(F("MA")).toInt(); strip.ablMilliampsMax = request->arg(F("MA")).toInt();
strip.milliampsPerLed = request->arg(F("LA")).toInt(); strip.milliampsPerLed = request->arg(F("LA")).toInt();
@ -195,8 +201,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
//SYNC //SYNC
if (subPage == 4) if (subPage == 4)
{ {
buttonType = request->arg(F("BT")).toInt();
irEnabled = request->arg(F("IR")).toInt();
int t = request->arg(F("UP")).toInt(); int t = request->arg(F("UP")).toInt();
if (t > 0) udpPort = t; if (t > 0) udpPort = t;
t = request->arg(F("U2")).toInt(); t = request->arg(F("U2")).toInt();
@ -238,6 +242,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
alexaEnabled = request->hasArg(F("AL")); alexaEnabled = request->hasArg(F("AL"));
strlcpy(alexaInvocationName, request->arg(F("AI")).c_str(), 33); strlcpy(alexaInvocationName, request->arg(F("AI")).c_str(), 33);
#ifndef WLED_DISABLE_BLYNK
strlcpy(blynkHost, request->arg("BH").c_str(), 33); strlcpy(blynkHost, request->arg("BH").c_str(), 33);
t = request->arg(F("BP")).toInt(); t = request->arg(F("BP")).toInt();
if (t > 0) blynkPort = t; if (t > 0) blynkPort = t;
@ -245,6 +250,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (request->hasArg("BK") && !request->arg("BK").equals(F("Hidden"))) { if (request->hasArg("BK") && !request->arg("BK").equals(F("Hidden"))) {
strlcpy(blynkApiKey, request->arg("BK").c_str(), 36); initBlynk(blynkApiKey, blynkHost, blynkPort); strlcpy(blynkApiKey, request->arg("BK").c_str(), 36); initBlynk(blynkApiKey, blynkHost, blynkPort);
} }
#endif
#ifdef WLED_ENABLE_MQTT #ifdef WLED_ENABLE_MQTT
mqttEnabled = request->hasArg(F("MQ")); mqttEnabled = request->hasArg(F("MQ"));
@ -307,8 +313,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
analogClock5MinuteMarks = request->hasArg(F("O5")); analogClock5MinuteMarks = request->hasArg(F("O5"));
analogClockSecondsTrail = request->hasArg(F("OS")); analogClockSecondsTrail = request->hasArg(F("OS"));
#ifndef WLED_DISABLE_CRONIXIE
strcpy(cronixieDisplay,request->arg(F("CX")).c_str()); strcpy(cronixieDisplay,request->arg(F("CX")).c_str());
cronixieBacklight = request->hasArg(F("CB")); cronixieBacklight = request->hasArg(F("CB"));
#endif
countdownMode = request->hasArg(F("CE")); countdownMode = request->hasArg(F("CE"));
countdownYear = request->arg(F("CY")).toInt(); countdownYear = request->arg(F("CY")).toInt();
countdownMonth = request->arg(F("CI")).toInt(); countdownMonth = request->arg(F("CI")).toInt();
@ -320,11 +328,17 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
macroAlexaOn = request->arg(F("A0")).toInt(); macroAlexaOn = request->arg(F("A0")).toInt();
macroAlexaOff = request->arg(F("A1")).toInt(); macroAlexaOff = request->arg(F("A1")).toInt();
macroButton = request->arg(F("MP")).toInt();
macroLongPress = request->arg(F("ML")).toInt();
macroCountdown = request->arg(F("MC")).toInt(); macroCountdown = request->arg(F("MC")).toInt();
macroNl = request->arg(F("MN")).toInt(); macroNl = request->arg(F("MN")).toInt();
macroDoublePress = request->arg(F("MD")).toInt(); for (uint8_t i=0; i<WLED_MAX_BUTTONS; i++) {
char mp[4] = "MP"; mp[2] = 48+i; mp[3] = 0; // short
char ml[4] = "ML"; ml[2] = 48+i; ml[3] = 0; // long
char md[4] = "MD"; md[2] = 48+i; md[3] = 0; // double
//if (!request->hasArg(mp)) break;
macroButton[i] = request->arg(mp).toInt(); // these will default to 0 if not present
macroLongPress[i] = request->arg(ml).toInt();
macroDoublePress[i] = request->arg(md).toInt();
}
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++)

File diff suppressed because it is too large Load Diff

View File

@ -113,6 +113,26 @@
#include "src/dependencies/json/AsyncJson-v6.h" #include "src/dependencies/json/AsyncJson-v6.h"
#include "src/dependencies/json/ArduinoJson-v6.h" #include "src/dependencies/json/ArduinoJson-v6.h"
// ESP32-WROVER features SPI RAM (aka PSRAM) which can be allocated using ps_malloc()
// we can create custom PSRAMDynamicJsonDocument to use such feature (replacing DynamicJsonDocument)
// The following is a construct to enable code to compile without it.
// There is a code thet will still not use PSRAM though:
// AsyncJsonResponse is a derived class that implements DynamicJsonDocument (AsyncJson-v6.h)
#ifdef ARDUINO_ARCH_ESP32
struct PSRAM_Allocator {
void* allocate(size_t size) {
if (psramFound()) return ps_malloc(size); // use PSRAM if it exists
else return malloc(size); // fallback
}
void deallocate(void* pointer) {
free(pointer);
}
};
using PSRAMDynamicJsonDocument = BasicJsonDocument<PSRAM_Allocator>;
#else
#define PSRAMDynamicJsonDocument DynamicJsonDocument
#endif
#include "fcn_declare.h" #include "fcn_declare.h"
#include "html_ui.h" #include "html_ui.h"
#include "html_settings.h" #include "html_settings.h"
@ -188,9 +208,9 @@ WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS);
// Hardware CONFIG (only changeble HERE, not at runtime) // Hardware CONFIG (only changeble HERE, not at runtime)
// LED strip pin, button pin and IR pin changeable in NpbWrapper.h! // LED strip pin, button pin and IR pin changeable in NpbWrapper.h!
#ifndef BTNPIN #ifndef BTNPIN
WLED_GLOBAL int8_t btnPin _INIT(0); WLED_GLOBAL int8_t btnPin[WLED_MAX_BUTTONS] _INIT({0});
#else #else
WLED_GLOBAL int8_t btnPin _INIT(BTNPIN); WLED_GLOBAL int8_t btnPin[WLED_MAX_BUTTONS] _INIT({BTNPIN});
#endif #endif
#ifndef RLYPIN #ifndef RLYPIN
WLED_GLOBAL int8_t rlyPin _INIT(12); WLED_GLOBAL int8_t rlyPin _INIT(12);
@ -204,7 +224,7 @@ WLED_GLOBAL bool rlyMde _INIT(true);
WLED_GLOBAL bool rlyMde _INIT(RLYMDE); WLED_GLOBAL bool rlyMde _INIT(RLYMDE);
#endif #endif
#ifndef IRPIN #ifndef IRPIN
WLED_GLOBAL int8_t irPin _INIT(4); WLED_GLOBAL int8_t irPin _INIT(-1);
#else #else
WLED_GLOBAL int8_t irPin _INIT(IRPIN); WLED_GLOBAL int8_t irPin _INIT(IRPIN);
#endif #endif
@ -259,7 +279,7 @@ WLED_GLOBAL NodesMap Nodes;
WLED_GLOBAL bool nodeListEnabled _INIT(true); WLED_GLOBAL bool nodeListEnabled _INIT(true);
WLED_GLOBAL bool nodeBroadcastEnabled _INIT(true); WLED_GLOBAL bool nodeBroadcastEnabled _INIT(true);
WLED_GLOBAL byte buttonType _INIT(BTN_TYPE_PUSH); WLED_GLOBAL byte buttonType[WLED_MAX_BUTTONS] _INIT({BTN_TYPE_PUSH});
WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver
WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port
@ -279,9 +299,11 @@ WLED_GLOBAL bool notifyTwice _INIT(false); // notificatio
WLED_GLOBAL bool alexaEnabled _INIT(false); // enable device discovery by Amazon Echo WLED_GLOBAL bool alexaEnabled _INIT(false); // enable device discovery by Amazon Echo
WLED_GLOBAL char alexaInvocationName[33] _INIT("Light"); // speech control name of device. Choose something voice-to-text can understand WLED_GLOBAL char alexaInvocationName[33] _INIT("Light"); // speech control name of device. Choose something voice-to-text can understand
#ifndef WLED_DISABLE_BLYNK
WLED_GLOBAL char blynkApiKey[36] _INIT(""); // Auth token for Blynk server. If empty, no connection will be made WLED_GLOBAL char blynkApiKey[36] _INIT(""); // Auth token for Blynk server. If empty, no connection will be made
WLED_GLOBAL char blynkHost[33] _INIT("blynk-cloud.com"); // Default Blynk host WLED_GLOBAL char blynkHost[33] _INIT("blynk-cloud.com"); // Default Blynk host
WLED_GLOBAL uint16_t blynkPort _INIT(80); // Default Blynk port WLED_GLOBAL uint16_t blynkPort _INIT(80); // Default Blynk port
#endif
WLED_GLOBAL uint16_t realtimeTimeoutMs _INIT(2500); // ms timeout of realtime mode before returning to normal mode WLED_GLOBAL uint16_t realtimeTimeoutMs _INIT(2500); // ms timeout of realtime mode before returning to normal mode
WLED_GLOBAL int arlsOffset _INIT(0); // realtime LED offset WLED_GLOBAL int arlsOffset _INIT(0); // realtime LED offset
@ -311,6 +333,7 @@ WLED_GLOBAL char mqttPass[41] _INIT(""); // optional: password
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID
WLED_GLOBAL uint16_t mqttPort _INIT(1883); WLED_GLOBAL uint16_t mqttPort _INIT(1883);
#ifndef WLED_DISABLE_HUESYNC
WLED_GLOBAL bool huePollingEnabled _INIT(false); // poll hue bridge for light state WLED_GLOBAL bool huePollingEnabled _INIT(false); // poll hue bridge for light state
WLED_GLOBAL uint16_t huePollIntervalMs _INIT(2500); // low values (< 1sec) may cause lag but offer quicker response WLED_GLOBAL uint16_t huePollIntervalMs _INIT(2500); // low values (< 1sec) may cause lag but offer quicker response
WLED_GLOBAL char hueApiKey[47] _INIT("api"); // key token will be obtained from bridge WLED_GLOBAL char hueApiKey[47] _INIT("api"); // key token will be obtained from bridge
@ -319,6 +342,7 @@ WLED_GLOBAL IPAddress hueIP _INIT_N(((0, 0, 0, 0))); // IP address of the bridge
WLED_GLOBAL bool hueApplyOnOff _INIT(true); WLED_GLOBAL bool hueApplyOnOff _INIT(true);
WLED_GLOBAL bool hueApplyBri _INIT(true); WLED_GLOBAL bool hueApplyBri _INIT(true);
WLED_GLOBAL bool hueApplyColor _INIT(true); WLED_GLOBAL bool hueApplyColor _INIT(true);
#endif
// Time CONFIG // Time CONFIG
WLED_GLOBAL bool ntpEnabled _INIT(false); // get internet time. Only required if you use clock overlays or time-activated macros WLED_GLOBAL bool ntpEnabled _INIT(false); // get internet time. Only required if you use clock overlays or time-activated macros
@ -333,8 +357,10 @@ WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your
WLED_GLOBAL bool analogClockSecondsTrail _INIT(false); // Display seconds as trail of LEDs instead of a single pixel WLED_GLOBAL bool analogClockSecondsTrail _INIT(false); // Display seconds as trail of LEDs instead of a single pixel
WLED_GLOBAL bool analogClock5MinuteMarks _INIT(false); // Light pixels at every 5-minute position WLED_GLOBAL bool analogClock5MinuteMarks _INIT(false); // Light pixels at every 5-minute position
#ifndef WLED_DISABLE_CRONIXIE
WLED_GLOBAL char cronixieDisplay[7] _INIT("HHMMSS"); // Cronixie Display mask. See wled13_cronixie.ino WLED_GLOBAL char cronixieDisplay[7] _INIT("HHMMSS"); // Cronixie Display mask. See wled13_cronixie.ino
WLED_GLOBAL bool cronixieBacklight _INIT(true); // Allow digits to be back-illuminated WLED_GLOBAL bool cronixieBacklight _INIT(true); // Allow digits to be back-illuminated
#endif
WLED_GLOBAL bool countdownMode _INIT(false); // Clock will count down towards date WLED_GLOBAL bool countdownMode _INIT(false); // Clock will count down towards date
WLED_GLOBAL byte countdownYear _INIT(20), countdownMonth _INIT(1); // Countdown target date, year is last two digits WLED_GLOBAL byte countdownYear _INIT(20), countdownMonth _INIT(1); // Countdown target date, year is last two digits
@ -344,7 +370,9 @@ WLED_GLOBAL byte countdownMin _INIT(0) , countdownSec _INIT(0);
WLED_GLOBAL byte macroNl _INIT(0); // after nightlight delay over WLED_GLOBAL byte macroNl _INIT(0); // after nightlight delay over
WLED_GLOBAL byte macroCountdown _INIT(0); WLED_GLOBAL byte macroCountdown _INIT(0);
WLED_GLOBAL byte macroAlexaOn _INIT(0), macroAlexaOff _INIT(0); WLED_GLOBAL byte macroAlexaOn _INIT(0), macroAlexaOff _INIT(0);
WLED_GLOBAL byte macroButton _INIT(0), macroLongPress _INIT(0), macroDoublePress _INIT(0); WLED_GLOBAL byte macroButton[WLED_MAX_BUTTONS] _INIT({0});
WLED_GLOBAL byte macroLongPress[WLED_MAX_BUTTONS] _INIT({0});
WLED_GLOBAL byte macroDoublePress[WLED_MAX_BUTTONS] _INIT({0});
// Security CONFIG // Security CONFIG
WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks
@ -405,10 +433,11 @@ WLED_GLOBAL byte briLast _INIT(128); // brightness before turned off. U
WLED_GLOBAL byte whiteLast _INIT(128); // white channel before turned off. Used for toggle function WLED_GLOBAL byte whiteLast _INIT(128); // white channel before turned off. Used for toggle function
// button // button
WLED_GLOBAL bool buttonPressedBefore _INIT(false); WLED_GLOBAL bool buttonPressedBefore[WLED_MAX_BUTTONS] _INIT({false});
WLED_GLOBAL bool buttonLongPressed _INIT(false); WLED_GLOBAL bool buttonLongPressed[WLED_MAX_BUTTONS] _INIT({false});
WLED_GLOBAL unsigned long buttonPressedTime _INIT(0); WLED_GLOBAL unsigned long buttonPressedTime[WLED_MAX_BUTTONS] _INIT({0});
WLED_GLOBAL unsigned long buttonWaitTime _INIT(0); WLED_GLOBAL unsigned long buttonWaitTime[WLED_MAX_BUTTONS] _INIT({0});
WLED_GLOBAL byte touchThreshold _INIT(TOUCH_THRESHOLD);
// notifications // notifications
WLED_GLOBAL bool notifyDirectDefault _INIT(notifyDirect); WLED_GLOBAL bool notifyDirectDefault _INIT(notifyDirect);

View File

@ -93,7 +93,7 @@ void loadSettingsFromEEPROM()
notifyButton = EEPROM.read(230); notifyButton = EEPROM.read(230);
notifyTwice = EEPROM.read(231); notifyTwice = EEPROM.read(231);
buttonType = EEPROM.read(232) ? BTN_TYPE_PUSH : BTN_TYPE_NONE; buttonType[0] = EEPROM.read(232) ? BTN_TYPE_PUSH : BTN_TYPE_NONE;
staticIP[0] = EEPROM.read(234); staticIP[0] = EEPROM.read(234);
staticIP[1] = EEPROM.read(235); staticIP[1] = EEPROM.read(235);
@ -157,6 +157,7 @@ void loadSettingsFromEEPROM()
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects); receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
if (lastEEPROMversion > 4) { if (lastEEPROMversion > 4) {
#ifndef WLED_DISABLE_HUESYNC
huePollingEnabled = EEPROM.read(2048); huePollingEnabled = EEPROM.read(2048);
//hueUpdatingEnabled = EEPROM.read(2049); //hueUpdatingEnabled = EEPROM.read(2049);
for (int i = 2050; i < 2054; ++i) for (int i = 2050; i < 2054; ++i)
@ -172,6 +173,7 @@ void loadSettingsFromEEPROM()
hueApplyBri = EEPROM.read(2104); hueApplyBri = EEPROM.read(2104);
hueApplyColor = EEPROM.read(2105); hueApplyColor = EEPROM.read(2105);
huePollLightId = EEPROM.read(2106); huePollLightId = EEPROM.read(2106);
#endif
} }
if (lastEEPROMversion > 5) { if (lastEEPROMversion > 5) {
overlayMin = EEPROM.read(2150); overlayMin = EEPROM.read(2150);
@ -188,18 +190,20 @@ void loadSettingsFromEEPROM()
countdownSec = EEPROM.read(2161); countdownSec = EEPROM.read(2161);
setCountdown(); setCountdown();
#ifndef WLED_DISABLE_CRONIXIE
readStringFromEEPROM(2165, cronixieDisplay, 6); readStringFromEEPROM(2165, cronixieDisplay, 6);
cronixieBacklight = EEPROM.read(2171); cronixieBacklight = EEPROM.read(2171);
#endif
//macroBoot = EEPROM.read(2175); //macroBoot = EEPROM.read(2175);
macroAlexaOn = EEPROM.read(2176); macroAlexaOn = EEPROM.read(2176);
macroAlexaOff = EEPROM.read(2177); macroAlexaOff = EEPROM.read(2177);
macroButton = EEPROM.read(2178); macroButton[0] = EEPROM.read(2178);
macroLongPress = EEPROM.read(2179); macroLongPress[0] = EEPROM.read(2179);
macroCountdown = EEPROM.read(2180); macroCountdown = EEPROM.read(2180);
macroNl = EEPROM.read(2181); macroNl = EEPROM.read(2181);
macroDoublePress = EEPROM.read(2182); macroDoublePress[0] = EEPROM.read(2182);
if (macroDoublePress > 16) macroDoublePress = 0; if (macroDoublePress[0] > 16) macroDoublePress[0] = 0;
} }
if (lastEEPROMversion > 6) if (lastEEPROMversion > 6)
@ -237,7 +241,7 @@ void loadSettingsFromEEPROM()
if (lastEEPROMversion > 9) if (lastEEPROMversion > 9)
{ {
strip.setColorOrder(EEPROM.read(383)); //strip.setColorOrder(EEPROM.read(383));
irEnabled = EEPROM.read(385); irEnabled = EEPROM.read(385);
strip.ablMilliampsMax = EEPROM.read(387) + ((EEPROM.read(388) << 8) & 0xFF00); strip.ablMilliampsMax = EEPROM.read(387) + ((EEPROM.read(388) << 8) & 0xFF00);
} else if (lastEEPROMversion > 1) //ABL is off by default when updating from version older than 0.8.2 } else if (lastEEPROMversion > 1) //ABL is off by default when updating from version older than 0.8.2
@ -343,8 +347,10 @@ void loadSettingsFromEEPROM()
//custom macro memory (16 slots/ each 64byte) //custom macro memory (16 slots/ each 64byte)
//1024-2047 reserved //1024-2047 reserved
#ifndef WLED_DISABLE_BLYNK
readStringFromEEPROM(2220, blynkApiKey, 35); readStringFromEEPROM(2220, blynkApiKey, 35);
if (strlen(blynkApiKey) < 25) blynkApiKey[0] = 0; if (strlen(blynkApiKey) < 25) blynkApiKey[0] = 0;
#endif
#ifdef WLED_ENABLE_DMX #ifdef WLED_ENABLE_DMX
// DMX (2530 - 2549)2535 // DMX (2530 - 2549)2535
@ -417,10 +423,10 @@ void deEEP() {
for (byte j = 0; j < numChannels; j++) colX.add(EEPROM.read(memloc + j)); for (byte j = 0; j < numChannels; j++) colX.add(EEPROM.read(memloc + j));
} }
segObj[F("fx")] = EEPROM.read(i+10); segObj["fx"] = EEPROM.read(i+10);
segObj[F("sx")] = EEPROM.read(i+11); segObj[F("sx")] = EEPROM.read(i+11);
segObj[F("ix")] = EEPROM.read(i+16); segObj[F("ix")] = EEPROM.read(i+16);
segObj[F("pal")] = EEPROM.read(i+17); segObj["pal"] = EEPROM.read(i+17);
} else { } else {
WS2812FX::Segment* seg = strip.getSegments(); WS2812FX::Segment* seg = strip.getSegments();
memcpy(seg, EEPROM.getDataPtr() +i+2, 240); memcpy(seg, EEPROM.getDataPtr() +i+2, 240);

View File

@ -256,27 +256,72 @@ void getSettingsJS(byte subPage, char* dest)
if (subPage == 2) { if (subPage == 2) {
char nS[8]; char nS[8];
// add usermod pins as d.um_p array (TODO: usermod config shouldn't use state. instead we should load "um" object from cfg.json) // add reserved and usermod pins as d.um_p array
/*DynamicJsonDocument doc(JSON_BUFFER_SIZE); DynamicJsonDocument doc(JSON_BUFFER_SIZE/2);
JsonObject mods = doc.createNestedObject(F("mods")); JsonObject mods = doc.createNestedObject(F("um"));
usermods.addToJsonState(mods); usermods.addToConfig(mods);
oappend(SET_F("d.um_p=["));
if (!mods.isNull()) { if (!mods.isNull()) {
uint8_t i=0; uint8_t i=0;
oappend(SET_F("d.um_p=["));
for (JsonPair kv : mods) { for (JsonPair kv : mods) {
if (strncmp_P(kv.key().c_str(),PSTR("pin_"),4) == 0) { if (!kv.value().isNull()) {
if (i++) oappend(SET_F(",")); // element is an JsonObject
oappend(itoa((int)kv.value(),nS,10)); JsonObject obj = kv.value();
if (obj["pin"] != nullptr) {
if (obj["pin"].is<JsonArray>()) {
JsonArray pins = obj["pin"].as<JsonArray>();
for (JsonVariant pv : pins) {
if (i++) oappend(SET_F(","));
oappendi(pv.as<int>());
}
} else {
if (i++) oappend(SET_F(","));
oappendi(obj["pin"].as<int>());
}
}
} }
} }
oappend(SET_F("];")); if (i) oappend(SET_F(","));
}*/ oappend(SET_F("6,7,8,9,10,11")); // flash memory pins
#ifdef WLED_ENABLE_DMX
oappend(SET_F(",2")); // DMX hardcoded pin
#endif
#ifdef WLED_ENABLE_ADALIGHT
// inform settings page that pin 3 is used by ADALights if not aleready used by strip (previous setup)
// NOTE: this will prohibit pin 3 use on new installs
{
bool pin3used = false;
for (uint8_t s=0; s < busses.getNumBusses(); s++) {
Bus* bus = busses.getBus(s);
uint8_t pins[5];
uint8_t nPins = bus->getPins(pins);
for (uint8_t i = 0; i < nPins; i++) {
if (pins[i] == 3) {
pin3used = true;
break;
}
}
if (pin3used) break;
}
if (!pin3used && pinManager.isPinAllocated(3)) oappend(SET_F(",3")); // ADALight (RX) pin
}
#endif
#ifdef WLED_DEBUG
oappend(SET_F(",1")); // debug output (TX) pin
#endif
#ifdef ARDUINO_ARCH_ESP32
if (psramFound()) oappend(SET_F(",16,17")); // GPIO16 & GPIO17 reserved for SPI RAM
#endif
//TODO: add reservations for Ethernet shield pins
#ifdef WLED_USE_ETHERNET
#endif
}
oappend(SET_F("];"));
// set limits
oappend(SET_F("bLimits(")); oappend(SET_F("bLimits("));
oappend(itoa(WLED_MAX_BUSSES,nS,10)); oappend(itoa(WLED_MAX_BUSSES,nS,10)); oappend(",");
oappend(","); oappend(itoa(MAX_LEDS_PER_BUS,nS,10)); oappend(",");
oappend(itoa(MAX_LEDS_PER_BUS,nS,10));
oappend(",");
oappend(itoa(MAX_LED_MEMORY,nS,10)); oappend(itoa(MAX_LED_MEMORY,nS,10));
oappend(SET_F(");")); oappend(SET_F(");"));
@ -286,7 +331,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("LC"),ledCount); sappend('v',SET_F("LC"),ledCount);
for (uint8_t s=0; s < busses.getNumBusses(); s++){ for (uint8_t s=0; s < busses.getNumBusses(); s++) {
Bus* bus = busses.getBus(s); Bus* bus = busses.getBus(s);
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length
@ -320,7 +365,6 @@ void getSettingsJS(byte subPage, char* dest)
} }
sappend('v',SET_F("CA"),briS); sappend('v',SET_F("CA"),briS);
sappend('v',SET_F("AW"),strip.rgbwMode); sappend('v',SET_F("AW"),strip.rgbwMode);
sappend('c',SET_F("BO"),turnOnAtBoot); sappend('c',SET_F("BO"),turnOnAtBoot);
@ -338,8 +382,16 @@ void getSettingsJS(byte subPage, char* dest)
sappend('i',SET_F("PB"),strip.paletteBlend); sappend('i',SET_F("PB"),strip.paletteBlend);
sappend('v',SET_F("RL"),rlyPin); sappend('v',SET_F("RL"),rlyPin);
sappend('c',SET_F("RM"),rlyMde); sappend('c',SET_F("RM"),rlyMde);
sappend('v',SET_F("BT"),btnPin); for (uint8_t i=0; i<WLED_MAX_BUTTONS; i++) {
oappend(SET_F("addBtn("));
oappend(itoa(i,nS,10)); oappend(",");
oappend(itoa(btnPin[i],nS,10)); oappend(",");
oappend(itoa(buttonType[i],nS,10));
oappend(SET_F(");"));
}
sappend('v',SET_F("TT"),touchThreshold);
sappend('v',SET_F("IR"),irPin); sappend('v',SET_F("IR"),irPin);
sappend('v',SET_F("IT"),irEnabled);
} }
if (subPage == 3) if (subPage == 3)
@ -350,8 +402,6 @@ void getSettingsJS(byte subPage, char* dest)
if (subPage == 4) if (subPage == 4)
{ {
sappend('v',SET_F("BT"),buttonType);
sappend('v',SET_F("IR"),irEnabled);
sappend('v',SET_F("UP"),udpPort); sappend('v',SET_F("UP"),udpPort);
sappend('v',SET_F("U2"),udpPort2); sappend('v',SET_F("U2"),udpPort2);
sappend('c',SET_F("RB"),receiveNotificationBrightness); sappend('c',SET_F("RB"),receiveNotificationBrightness);
@ -381,8 +431,10 @@ void getSettingsJS(byte subPage, char* dest)
sappends('s',SET_F("AI"),alexaInvocationName); sappends('s',SET_F("AI"),alexaInvocationName);
sappend('c',SET_F("SA"),notifyAlexa); sappend('c',SET_F("SA"),notifyAlexa);
sappends('s',SET_F("BK"),(char*)((blynkEnabled)?SET_F("Hidden"):"")); sappends('s',SET_F("BK"),(char*)((blynkEnabled)?SET_F("Hidden"):""));
#ifndef WLED_DISABLE_BLYNK
sappends('s',SET_F("BH"),blynkHost); sappends('s',SET_F("BH"),blynkHost);
sappend('v',SET_F("BP"),blynkPort); sappend('v',SET_F("BP"),blynkPort);
#endif
#ifdef WLED_ENABLE_MQTT #ifdef WLED_ENABLE_MQTT
sappend('c',SET_F("MQ"),mqttEnabled); sappend('c',SET_F("MQ"),mqttEnabled);
@ -451,8 +503,10 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("OM"),analogClock12pixel); sappend('v',SET_F("OM"),analogClock12pixel);
sappend('c',SET_F("OS"),analogClockSecondsTrail); sappend('c',SET_F("OS"),analogClockSecondsTrail);
sappend('c',SET_F("O5"),analogClock5MinuteMarks); sappend('c',SET_F("O5"),analogClock5MinuteMarks);
#ifndef WLED_DISABLE_CRONIXIE
sappends('s',SET_F("CX"),cronixieDisplay); sappends('s',SET_F("CX"),cronixieDisplay);
sappend('c',SET_F("CB"),cronixieBacklight); sappend('c',SET_F("CB"),cronixieBacklight);
#endif
sappend('c',SET_F("CE"),countdownMode); sappend('c',SET_F("CE"),countdownMode);
sappend('v',SET_F("CY"),countdownYear); sappend('v',SET_F("CY"),countdownYear);
sappend('v',SET_F("CI"),countdownMonth); sappend('v',SET_F("CI"),countdownMonth);
@ -463,11 +517,16 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("A0"),macroAlexaOn); sappend('v',SET_F("A0"),macroAlexaOn);
sappend('v',SET_F("A1"),macroAlexaOff); sappend('v',SET_F("A1"),macroAlexaOff);
sappend('v',SET_F("MP"),macroButton);
sappend('v',SET_F("ML"),macroLongPress);
sappend('v',SET_F("MC"),macroCountdown); sappend('v',SET_F("MC"),macroCountdown);
sappend('v',SET_F("MN"),macroNl); sappend('v',SET_F("MN"),macroNl);
sappend('v',SET_F("MD"),macroDoublePress); for (uint8_t i=0; i<WLED_MAX_BUTTONS; i++) {
oappend(SET_F("addRow("));
oappend(itoa(i,tm,10)); oappend(",");
oappend(itoa(macroButton[i],tm,10)); oappend(",");
oappend(itoa(macroLongPress[i],tm,10)); oappend(",");
oappend(itoa(macroDoublePress[i],tm,10));
oappend(SET_F(");"));
}
char k[4]; char k[4];
k[2] = 0; //Time macros k[2] = 0; //Time macros