Merge branch 'master' into toki

This commit is contained in:
Christian Schwinne 2021-05-30 13:22:42 +02:00 committed by GitHub
commit 9f13763637
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1058 additions and 701 deletions

View File

@ -16,7 +16,7 @@ This file should be placed in the same directory as `platformio.ini`.
### Define Your Options
* `USERMOD_ROTARY_ENCODER_UI` - define this to have this user mod included wled00\usermods_list.cpp
* `USERMOD_FOUR_LINE_DISLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp - also tells this usermod that the display is available (see the Four Line Display usermod `readme.md` for more details)
* `USERMOD_FOUR_LINE_DISPLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp - also tells this usermod that the display is available (see the Four Line Display usermod `readme.md` for more details)
* `ENCODER_DT_PIN` - The encoders DT pin, defaults to 12
* `ENCODER_CLK_PIN` - The encoders CLK pin, defaults to 14
* `ENCODER_SW_PIN` - The encoders SW pin, defaults to 13

View File

@ -37,7 +37,7 @@
#define ENCODER_SW_PIN 13
#endif
#ifndef USERMOD_FOUR_LINE_DISLAY
#ifndef USERMOD_FOUR_LINE_DISPLAY
// These constants won't be defined if we aren't using FourLineDisplay.
#define FLD_LINE_3_BRIGHTNESS 0
#define FLD_LINE_3_EFFECT_SPEED 0
@ -62,7 +62,7 @@ private:
unsigned char button_state = HIGH;
unsigned char prev_button_state = HIGH;
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
FourLineDisplayUsermod *display;
#else
void* display = nullptr;
@ -96,7 +96,7 @@ public:
modes_alpha_indexes = modeSortUsermod->getModesAlphaIndexes();
palettes_alpha_indexes = modeSortUsermod->getPalettesAlphaIndexes();
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
// This Usermod uses FourLineDisplayUsermod for the best experience.
// But it's optional. But you want it.
display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP);
@ -248,7 +248,7 @@ public:
}
boolean changeState(const char *stateName, byte lineThreeMode, byte markedLine) {
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display != nullptr) {
if (display->wakeDisplay()) {
// Throw away wake up input
@ -272,7 +272,7 @@ public:
}
void changeBrightness(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) {
// Throw away wake up input
return;
@ -288,7 +288,7 @@ public:
}
void changeEffect(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) {
// Throw away wake up input
return;
@ -305,7 +305,7 @@ public:
}
void changeEffectSpeed(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) {
// Throw away wake up input
return;
@ -321,7 +321,7 @@ public:
}
void changeEffectIntensity(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) {
// Throw away wake up input
return;
@ -337,7 +337,7 @@ public:
}
void changePalette(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) {
// Throw away wake up input
return;

View File

@ -6,105 +6,210 @@
#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();
colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
} else {
applyPreset(macroButton);
applyPreset(macroButton[b]);
}
}
bool isButtonPressed()
bool isButtonPressed(uint8_t i)
{
if (btnPin>=0 && digitalRead(btnPin) == LOW) return true;
#ifdef TOUCHPIN
if (touchRead(TOUCHPIN) <= TOUCH_THRESHOLD) return true;
if (btnPin[i]<0) return false;
switch (buttonType[i]) {
case BTN_TYPE_NONE:
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;
#endif
break;
}
return false;
}
void handleSwitch()
void handleSwitch(uint8_t b)
{
if (buttonPressedBefore != isButtonPressed()) {
buttonPressedTime = millis();
buttonPressedBefore = !buttonPressedBefore;
if (buttonPressedBefore[b] != isButtonPressed(b)) {
buttonPressedTime[b] = millis();
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 (buttonPressedBefore) { //LOW, falling edge, switch closed
if (macroButton) applyPreset(macroButton);
if (millis() - buttonPressedTime[b] > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce)
if (buttonPressedBefore[b]) { //LOW, falling edge, switch closed
if (macroButton[b]) applyPreset(macroButton[b]);
else { //turn on
if (!bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);}
}
} else { //HIGH, rising edge, switch opened
if (macroLongPress) applyPreset(macroLongPress);
if (macroLongPress[b]) applyPreset(macroLongPress[b]);
else { //turn off
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 handleAnalog(uint8_t b)
{
static uint8_t oldRead[WLED_MAX_BUTTONS];
#ifdef ESP8266
uint16_t aRead = analogRead(A0) >> 2; // convert 10bit read to 8bit
#else
uint16_t aRead = analogRead(btnPin[b]) >> 4; // convert 12bit read to 8bit
#endif
// remove noise & reduce frequency of UI updates
aRead &= 0xFC;
if (oldRead[b] == aRead) return; // no change in reading
oldRead[b] = aRead;
// if no macro for "short press" and "long press" is defined use brightness control
if (!macroButton[b] && !macroLongPress[b]) {
// if "double press" macro defines which option to change
if (macroDoublePress[b] >= 250) {
// global brightness
if (aRead == 0) {
briLast = bri;
bri = 0;
} else{
bri = aRead;
}
} else if (macroDoublePress[b] == 249) {
// effect speed
effectSpeed = aRead;
effectChanged = true;
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isSelected()) continue;
seg.speed = effectSpeed;
}
} else if (macroDoublePress[b] == 248) {
// effect intensity
effectIntensity = aRead;
effectChanged = true;
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isSelected()) continue;
seg.intensity = effectIntensity;
}
} else if (macroDoublePress[b] == 247) {
// selected palette
effectPalette = map(aRead, 0, 252, 0, strip.getPaletteCount()-1);
effectChanged = true;
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isSelected()) continue;
seg.palette = effectPalette;
}
} else if (macroDoublePress[b] == 200) {
// primary color, hue, full saturation
colorHStoRGB(aRead*256,255,col);
} else {
// otherwise use "double press" for segment selection
//uint8_t mainSeg = strip.getMainSegmentId();
WS2812FX::Segment& seg = strip.getSegment(macroDoublePress[b]);
if (aRead == 0) {
seg.setOption(SEG_OPTION_ON, 0); // off
} else {
seg.setOpacity(aRead, macroDoublePress[b]);
seg.setOption(SEG_OPTION_ON, 1);
}
// this will notify clients of update (websockets,mqtt,etc)
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
updateInterfaces(NOTIFIER_CALL_MODE_BUTTON);
}
} else {
//TODO:
// we can either trigger a preset depending on the level (between short and long entries)
// or use it for RGBW direct control
}
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
}
void handleButton()
{
if (btnPin<0 || buttonType < BTN_TYPE_PUSH) return;
static unsigned long lastRead = 0UL;
for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) {
#ifdef ESP8266
if ((btnPin[b]<0 && buttonType[b] != BTN_TYPE_ANALOG) || buttonType[b] == BTN_TYPE_NONE) continue;
#else
if (btnPin[b]<0 || buttonType[b] == BTN_TYPE_NONE) continue;
#endif
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)
handleSwitch(); return;
if (buttonType[b] == BTN_TYPE_ANALOG && millis() - lastRead > 250) { // button is not a button but a potentiometer
if (b+1 == WLED_MAX_BUTTONS) lastRead = millis();
handleAnalog(b); continue;
}
if (buttonType[b] == BTN_TYPE_SWITCH || buttonType[b] == BTN_TYPE_SWITCH_ACT_HIGH) { //button is not momentary, but switch. This is only suitable on pins whose on-boot state does not matter (NOT gpio0)
handleSwitch(b); continue;
}
//momentary button logic
if (isButtonPressed()) //pressed
if (isButtonPressed(b)) //pressed
{
if (!buttonPressedBefore) buttonPressedTime = millis();
buttonPressedBefore = true;
if (!buttonPressedBefore[b]) buttonPressedTime[b] = millis();
buttonPressedBefore[b] = true;
if (millis() - buttonPressedTime > 600) //long press
if (millis() - buttonPressedTime[b] > 600) //long press
{
if (!buttonLongPressed)
if (!buttonLongPressed[b])
{
if (macroLongPress) {applyPreset(macroLongPress);}
if (macroLongPress[b]) {applyPreset(macroLongPress[b]);}
else _setRandomColor(false,true);
buttonLongPressed = true;
buttonLongPressed[b] = true;
}
}
}
else if (!isButtonPressed() && buttonPressedBefore) //released
else if (!isButtonPressed(b) && buttonPressedBefore[b]) //released
{
long dur = millis() - buttonPressedTime;
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore = false; return;} //too short "press", debounce
bool doublePress = buttonWaitTime;
buttonWaitTime = 0;
long dur = millis() - buttonPressedTime[b];
if (dur < WLED_DEBOUNCE_THRESHOLD) {buttonPressedBefore[b] = false; continue;} //too short "press", debounce
bool doublePress = buttonWaitTime[b];
buttonWaitTime[b] = 0;
if (dur > 6000) //long press
if (dur > 6000 && b==0) //long press on button 0
{
WLED::instance().initAP(true);
}
else if (!buttonLongPressed) { //short press
if (macroDoublePress)
else if (!buttonLongPressed[b]) { //short press
if (macroDoublePress[b])
{
if (doublePress) applyPreset(macroDoublePress);
else buttonWaitTime = millis();
} else shortPressAction();
if (doublePress) applyPreset(macroDoublePress[b]);
else buttonWaitTime[b] = millis();
} else shortPressAction(b);
}
buttonPressedBefore = false;
buttonLongPressed = false;
buttonPressedBefore[b] = false;
buttonLongPressed[b] = false;
}
if (buttonWaitTime && millis() - buttonWaitTime > 450 && !buttonPressedBefore)
if (buttonWaitTime[b] && millis() - buttonWaitTime[b] > 450 && !buttonPressedBefore[b])
{
buttonWaitTime = 0;
shortPressAction();
buttonWaitTime[b] = 0;
shortPressAction(b);
}
}
}
@ -128,7 +233,8 @@ void handleIO()
{
if (!offMode) {
#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);
digitalWrite(LED_BUILTIN, HIGH);
#endif

View File

@ -62,7 +62,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonArray ap_ip = ap["ip"];
for (byte i = 0; i < 4; i++) {
apIP[i] = ap_ip;
}*/
}
*/
noWifiSleep = doc[F("wifi")][F("sleep")] | !noWifiSleep; // inverted
noWifiSleep = !noWifiSleep;
@ -89,13 +90,12 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
for (JsonObject elm : ins) {
if (s >= WLED_MAX_BUSSES) break;
uint8_t pins[5] = {255, 255, 255, 255, 255};
JsonArray pinArr = elm[F("pin")];
JsonArray pinArr = elm["pin"];
if (pinArr.size() == 0) continue;
pins[0] = pinArr[0];
uint8_t i = 0;
for (int p : pinArr) {
pins[i] = p;
i++;
pins[i++] = p;
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
JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0];
CJSON(buttonType, hw_btn_ins_0["type"]);
int hw_btn_pin = hw_btn_ins_0[F("pin")][0] | -2; //-2 = not present in doc, keep current. -1 = disable
if (hw_btn_pin > -2) {
if (pinManager.allocatePin(hw_btn_pin,false)) {
btnPin = hw_btn_pin;
pinMode(btnPin, INPUT_PULLUP);
// read multiple button configuration
JsonArray hw_btn_ins = hw[F("btn")][F("ins")];
if (!hw_btn_ins.isNull()) {
uint8_t s = 0;
for (JsonObject btn : hw_btn_ins) {
CJSON(buttonType[s], btn["type"]);
int8_t pin = btn[F("pin")][0] | -1;
if (pin > -1) {
if (pinManager.allocatePin(pin,false)) {
btnPin[s] = pin;
pinMode(btnPin[s], INPUT_PULLUP);
} else {
btnPin = -1;
btnPin[s] = -1;
}
}
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]);
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")]);
int hw_ir_pin = hw["ir"]["pin"] | -2; // 4
if (hw_ir_pin > -2) {
@ -164,7 +189,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
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")];
CJSON(briMultiplier, light[F("scale-bri")]);
@ -179,7 +204,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonObject light_tr = light[F("tr")];
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;
CJSON(strip.paletteFade, light_tr["pal"]);
@ -203,7 +228,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(presetCycleMin, def_cy[F("range")][0]);
CJSON(presetCycleMax, def_cy[F("range")][1]);
tdd = def_cy[F("dur")] | -1;
tdd = def_cy["dur"] | -1;
if (tdd > 0) presetCycleTime = tdd;
JsonObject interfaces = doc["if"];
@ -255,6 +280,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(macroAlexaOn, interfaces[F("va")][F("macros")][0]);
CJSON(macroAlexaOff, interfaces[F("va")][F("macros")][1]);
#ifndef WLED_DISABLE_BLYNK
const char* apikey = interfaces["blynk"][F("token")] | "Hidden";
tdd = strnlen(apikey, 36);
if (tdd > 20 || tdd == 0)
@ -263,7 +289,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonObject if_blynk = interfaces["blynk"];
getStringFromJson(blynkHost, if_blynk[F("host")], 33);
CJSON(blynkPort, if_blynk["port"]);
#endif
#ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces["mqtt"];
CJSON(mqttEnabled, if_mqtt["en"]);
getStringFromJson(mqttServer, if_mqtt[F("broker")], 33);
@ -274,7 +302,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test"
getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // ""
#endif
#ifndef WLED_DISABLE_HUESYNC
JsonObject if_hue = interfaces[F("hue")];
CJSON(huePollingEnabled, if_hue["en"]);
CJSON(huePollLightId, if_hue["id"]);
@ -290,6 +320,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
for (byte i = 0; i < 4; i++)
CJSON(hueIP[i], if_hue_ip[i]);
#endif
JsonObject if_ntp = interfaces[F("ntp")];
CJSON(ntpEnabled, if_ntp["en"]);
@ -306,7 +337,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(countdownMode, ol[F("cntdwn")]);
if (prev != overlayDefault) overlayCurrent = overlayDefault;
CJSON(overlayMin, ol[F("min")]);
CJSON(overlayMin, ol["min"]);
CJSON(overlayMax, ol[F("max")]);
CJSON(analogClock12pixel, ol[F("o12pix")]);
CJSON(analogClock5MinuteMarks, ol[F("o5m")]);
@ -331,7 +362,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
if (it > 9) break;
if (it<8 && timer[F("hour")]==255) it=8; // hour==255 -> sunrise/sunset
CJSON(timerHours[it], timer[F("hour")]);
CJSON(timerMinutes[it], timer[F("min")]);
CJSON(timerMinutes[it], timer["min"]);
CJSON(timerMacro[it], timer[F("macro")]);
byte dowPrev = timerWeekday[it];
@ -377,6 +408,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
}
#endif
DEBUG_PRINTLN(F("Starting usermod config."));
JsonObject usermods_settings = doc["um"];
if (!usermods_settings.isNull()) usermods.readFromConfig(usermods_settings);
@ -490,21 +522,34 @@ void serializeConfig() {
ins["type"] = bus->getType();
}
// button(s)
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");
// button BTNPIN
// there is always at least one button
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");
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");
hw_btn_ins_0_macros.add(macroButton);
hw_btn_ins_0_macros.add(macroLongPress);
hw_btn_ins_0_macros.add(macroDoublePress);
hw_btn_ins_0_macros.add(macroButton[0]);
hw_btn_ins_0_macros.add(macroLongPress[0]);
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;
JsonObject hw_ir = hw.createNestedObject("ir");
hw_ir["pin"] = irPin;
@ -527,12 +572,12 @@ void serializeConfig() {
JsonObject light_tr = light.createNestedObject("tr");
light_tr[F("mode")] = fadeTransition;
light_tr[F("dur")] = transitionDelayDefault / 100;
light_tr["dur"] = transitionDelayDefault / 100;
light_tr["pal"] = strip.paletteFade;
JsonObject light_nl = light.createNestedObject("nl");
light_nl[F("mode")] = nightlightMode;
light_nl[F("dur")] = nightlightDelayMinsDefault;
light_nl["dur"] = nightlightDelayMinsDefault;
light_nl[F("tbri")] = nightlightTargetBri;
light_nl[F("macro")] = macroNl;
@ -549,7 +594,7 @@ void serializeConfig() {
JsonArray def_cy_range = def_cy.createNestedArray(F("range"));
def_cy_range.add(presetCycleMin);
def_cy_range.add(presetCycleMax);
def_cy[F("dur")] = presetCycleTime;
def_cy["dur"] = presetCycleTime;
}
JsonObject interfaces = doc.createNestedObject("if");
@ -561,7 +606,7 @@ void serializeConfig() {
JsonObject if_sync_recv = if_sync.createNestedObject("recv");
if_sync_recv["bri"] = receiveNotificationBrightness;
if_sync_recv["col"] = receiveNotificationColor;
if_sync_recv[F("fx")] = receiveNotificationEffects;
if_sync_recv["fx"] = receiveNotificationEffects;
JsonObject if_sync_send = if_sync.createNestedObject("send");
if_sync_send[F("dir")] = notifyDirect;
@ -596,11 +641,15 @@ void serializeConfig() {
JsonArray if_va_macros = if_va.createNestedArray("macros");
if_va_macros.add(macroAlexaOn);
if_va_macros.add(macroAlexaOff);
#ifndef WLED_DISABLE_BLYNK
JsonObject if_blynk = interfaces.createNestedObject("blynk");
if_blynk[F("token")] = strlen(blynkApiKey) ? "Hidden":"";
if_blynk[F("host")] = blynkHost;
if_blynk["port"] = blynkPort;
#endif
#ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
if_mqtt["en"] = mqttEnabled;
if_mqtt[F("broker")] = mqttServer;
@ -612,7 +661,9 @@ void serializeConfig() {
JsonObject if_mqtt_topics = if_mqtt.createNestedObject(F("topics"));
if_mqtt_topics[F("device")] = mqttDeviceTopic;
if_mqtt_topics[F("group")] = mqttGroupTopic;
#endif
#ifndef WLED_DISABLE_HUESYNC
JsonObject if_hue = interfaces.createNestedObject("hue");
if_hue["en"] = huePollingEnabled;
if_hue["id"] = huePollLightId;
@ -627,6 +678,7 @@ void serializeConfig() {
for (byte i = 0; i < 4; i++) {
if_hue_ip.add(hueIP[i]);
}
#endif
JsonObject if_ntp = interfaces.createNestedObject("ntp");
if_ntp["en"] = ntpEnabled;
@ -641,7 +693,7 @@ void serializeConfig() {
ol[F("clock")] = overlayDefault;
ol[F("cntdwn")] = countdownMode;
ol[F("min")] = overlayMin;
ol["min"] = overlayMin;
ol[F("max")] = overlayMax;
ol[F("o12pix")] = analogClock12pixel;
ol[F("o5m")] = analogClock5MinuteMarks;
@ -662,7 +714,7 @@ void serializeConfig() {
JsonObject timers_ins0 = timers_ins.createNestedObject();
timers_ins0["en"] = (timerWeekday[i] & 0x01);
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("dow")] = timerWeekday[i] >> 1;
}
@ -684,7 +736,6 @@ void serializeConfig() {
for (byte i = 0; i < 15; i++)
dmx_fixmap.add(DMXFixtureMap[i]);
#endif
//}
JsonObject usermods_settings = doc.createNestedObject("um");
usermods.addToConfig(usermods_settings);
@ -711,15 +762,21 @@ bool deserializeConfigSec() {
JsonObject interfaces = doc["if"];
#ifndef WLED_DISABLE_BLYNK
const char* apikey = interfaces["blynk"][F("token")] | "Hidden";
int tdd = strnlen(apikey, 36);
if (tdd > 20 || tdd == 0)
getStringFromJson(blynkApiKey, apikey, 36);
#endif
#ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces["mqtt"];
getStringFromJson(mqttPass, if_mqtt["psk"], 41);
#endif
#ifndef WLED_DISABLE_HUESYNC
getStringFromJson(hueApiKey, interfaces[F("hue")][F("key")], 47);
#endif
JsonObject ota = doc["ota"];
getStringFromJson(otaPass, ota[F("pwd")], 33);
@ -746,12 +803,18 @@ void serializeConfigSec() {
ap["psk"] = apPass;
JsonObject interfaces = doc.createNestedObject("if");
#ifndef WLED_DISABLE_BLYNK
JsonObject if_blynk = interfaces.createNestedObject("blynk");
if_blynk[F("token")] = blynkApiKey;
#endif
#ifdef WLED_ENABLE_MQTT
JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
if_mqtt["psk"] = mqttPass;
#endif
#ifndef WLED_DISABLE_HUESYNC
JsonObject if_hue = interfaces.createNestedObject("hue");
if_hue[F("key")] = hueApiKey;
#endif
JsonObject ota = doc.createNestedObject("ota");
ota[F("pwd")] = otaPass;

View File

@ -31,6 +31,14 @@
#endif
#endif
#ifndef WLED_MAX_BUTTONS
#ifdef ESP8266
#define WLED_MAX_BUTTONS 2
#else
#define WLED_MAX_BUTTONS 4
#endif
#endif
//Usermod IDs
#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
@ -45,10 +53,10 @@
#define USERMOD_ID_DHT 10 //Usermod "usermod_dht.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_RTC 13 //Usermod "usermod_rtc.h"
#define USERMOD_ID_ELEKSTUBE_IPS 14 //Usermod "usermod_elekstube_ips.h"
#define USERMOD_ID_MULTI_RELAY 101 //Usermod "usermod_multi_relay.h"
#define USERMOD_ID_ANIMATED_STAIRCASE 102 //Usermod "Animated_Staircase.h"
#define USERMOD_ID_MULTI_RELAY 13 //Usermod "usermod_multi_relay.h"
#define USERMOD_ID_ANIMATED_STAIRCASE 14 //Usermod "Animated_Staircase.h"
#define USERMOD_ID_RTC 15 //Usermod "usermod_rtc.h"
#define USERMOD_ID_ELEKSTUBE_IPS 16 //Usermod "usermod_elekstube_ips.h"
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
@ -150,9 +158,11 @@
#define BTN_TYPE_NONE 0
#define BTN_TYPE_RESERVED 1
#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_ACT_HIGH 5 //not implemented
#define BTN_TYPE_SWITCH_ACT_HIGH 5
#define BTN_TYPE_TOUCH 6
#define BTN_TYPE_ANALOG 7
//Ethernet board types
#define WLED_NUM_ETH_TYPES 5
@ -205,7 +215,7 @@
// 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
#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
#define MAX_LEDS 8192
#endif
@ -245,7 +255,7 @@
#ifdef ESP8266
#define JSON_BUFFER_SIZE 9216
#else
#define JSON_BUFFER_SIZE 16384
#define JSON_BUFFER_SIZE 20480
#endif
// Maximum size of node map (list of other WLED instances)

View File

@ -14,71 +14,74 @@
{
window.open("/settings","_self");
}
function gId(n){return d.getElementById(n);}
function off(n){
d.getElementsByName(n)[0].value = -1;
}
function bLimits(b,p,m) {
maxB = b; maxM = m; maxPB = p;
}
function trySubmit(event) {
event.preventDefault();
function pinsOK() {
var LCs = d.getElementsByTagName("input");
for (i=0; i<LCs.length; i++) {
var nm = LCs[i].name.substring(0,2);
//check for pin conflicts
if (nm=="L0" || nm=="L1" || nm=="RL" || nm=="BT" || nm=="IR" || nm=="AX")
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
if (LCs[i].value!="" && LCs[i].value!="-1") {
if (LCs[i].value > 5 && LCs[i].value < 12) {alert("Sorry, pins 6-11 can not be used.");LCs[i].focus();return;}
if (d.um_p && d.um_p.some((e)=>e==parseInt(LCs[i].value,10))) {alert("Usermod pin conflict!");LCs[i].focus();return;}
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;}
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;}
for (j=i+1; j<LCs.length; j++)
{
var n2 = LCs[j].name.substring(0,2);
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!");LCs[i].focus();return;}
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR")
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 (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += " Consider using an ESP32."; alert(msg); return;}
return true;
}
function trySubmit(e) {
e.preventDefault();
if (!pinsOK()) {e.stopPropagation();return false;} // Prevent form submission and contact with server
if (bquot > 100) {var msg = "Too many LEDs for me to handle!"; if (maxM < 10000) msg += "\n\rConsider using an ESP32."; alert(msg);}
if (d.Sf.checkValidity()) d.Sf.submit(); //https://stackoverflow.com/q/37323914
if (d.Sf.reportValidity()) d.Sf.submit();
}
function S(){GetV();setABL();}
function enABL()
{
var en = d.getElementById('able').checked;
var en = gId('able').checked;
d.Sf.LA.value = (en) ? laprev:0;
d.getElementById('abl').style.display = (en) ? 'inline':'none';
d.getElementById('psu2').style.display = (en) ? 'inline':'none';
gId('abl').style.display = (en) ? 'inline':'none';
gId('psu2').style.display = (en) ? 'inline':'none';
if (d.Sf.LA.value > 0) setABL();
}
function enLA()
{
var val = d.Sf.LAsel.value;
d.Sf.LA.value = val;
d.getElementById('LAdis').style.display = (val == 50) ? 'inline':'none';
gId('LAdis').style.display = (val == 50) ? 'inline':'none';
UI();
}
function setABL()
{
d.getElementById('able').checked = true;
gId('able').checked = true;
d.Sf.LAsel.value = 50;
switch (parseInt(d.Sf.LA.value)) {
case 0: d.getElementById('able').checked = false; enABL(); break;
case 0: gId('able').checked = false; enABL(); break;
case 30: d.Sf.LAsel.value = 30; break;
case 35: d.Sf.LAsel.value = 35; break;
case 55: d.Sf.LAsel.value = 55; break;
case 255: d.Sf.LAsel.value = 255; break;
default: d.getElementById('LAdis').style.display = 'inline';
default: gId('LAdis').style.display = 'inline';
}
d.getElementById('m1').innerHTML = maxM;
gId('m1').innerHTML = maxM;
d.getElementsByName("Sf")[0].addEventListener("submit", trySubmit);
UI();
}
//returns mem usage
function getMem(type, len, p0) {
//len = parseInt(len);
if (type < 32) {
if (maxM < 10000 && p0 ==3) { //8266 DMA uses 5x the mem
if (maxM < 10000 && p0==3) { //8266 DMA uses 5x the mem
if (type > 29) return len*20; //RGBW
return len*15;
} else if (maxM >= 10000) //ESP32 RMT uses double buffer?
@ -93,11 +96,11 @@
if (type == 44 || type == 45) return len*4; //RGBW
return len*3;
}
function UI()
function UI(change=false)
{
var isRGBW = false, memu = 0;
d.getElementById('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none';
gId('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none';
if (d.Sf.LA.value == 255) laprev = 12;
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
@ -106,9 +109,9 @@
for (i=0; i<s.length; i++) {
if (s[i].name.substring(0,2)=="LT") {
n=s[i].name.substring(2);
var type = s[i].value;
d.getElementById("p0d"+n).innerHTML = (type > 49) ? "Data pin:" : (type >41) ? "Pins:" : "Pin:";
d.getElementById("p1d"+n).innerHTML = (type > 49) ? "Clk:" : "";
var type = parseInt(s[i].value,10);
gId("p0d"+n).innerHTML = (type > 49) ? "Data:" : (type >41) ? "Pins:" : "Pin:";
gId("p1d"+n).innerHTML = (type > 49) ? "Clk:" : "";
var LK = d.getElementsByName("L1"+n)[0];
memu += getMem(type, d.getElementsByName("LC"+n)[0].value, d.getElementsByName("L0"+n)[0].value);
@ -127,8 +130,8 @@
}
}
if (type == 30 || type == 31 || (type > 40 && type < 46 && type != 43)) isRGBW = true;
d.getElementById("dig"+n).style.display = (type > 31 && type < 48) ? "none":"inline";
d.getElementById("psd"+n).innerHTML = (type > 31 && type < 48) ? "Index:":"Start:";
gId("dig"+n).style.display = (type > 31 && type < 48) ? "none":"inline";
gId("psd"+n).innerHTML = (type > 31 && type < 48) ? "Index:":"Start:";
}
}
@ -148,17 +151,37 @@
var sLC = 0, maxLC = 0;
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;}
if (nm=="LC" && LCs[i].name !== "LC") {
var n=LCs[i].name.substring(2);
var c=parseInt(LCs[i].value,10);
if(gId("ls"+n).readOnly) gId("ls"+n).value=sLC;
if(c){sLC+=c;if(c>maxLC)maxLC=c;}
continue;
}
if (nm=="L0" || nm=="L1") {
var lc=d.getElementsByName("LC"+LCs[i].name.substring(2))[0];
lc.max=maxPB;
}
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
if (LCs[i].value!="" && LCs[i].value!="-1") {
var p = [];
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++) {
if (i==j) continue;
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 (LCs[j].value!="" && LCs[j].value!="-1") p.push(parseInt(LCs[j].value,10));
}
if (p.some((e)=>e==parseInt(LCs[i].value,10))) LCs[i].style.color="red"; else LCs[i].style.color="#fff";
}
}
d.getElementById('m0').innerHTML = memu;
gId('m0').innerHTML = memu;
bquot = memu / maxM * 100;
d.getElementById('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? bquot > 90 ? "red":"orange":"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`;
d.getElementById('ledwarning').style.display = (maxLC > 800 || bquot > 80) ? 'inline':'none';
//TODO add warning "Recommended pins on ESP8266 are 1 and 2 (3 only with low LED count)"
//TODO add overmemory warning
//TODO block disallowed pins 6-11
d.getElementById('wreason').innerHTML = (bquot > 80) ? "than 60%% of max. LED memory" : "800 LEDs per pin";
gId('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? (bquot > 90 ? "red":"orange"):"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`;
gId('ledwarning').style.display = (sLC > maxPB || maxLC > 800 || bquot > 80) ? 'inline':'none';
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";
//var val = Math.ceil((100 + d.Sf.LC.value * laprev)/500)/2;
var val = Math.ceil((100 + sLC * laprev)/500)/2;
@ -180,8 +203,8 @@
var s2 = "(for most effects, ~";
s2 += val2;
s2 += "A is enough)<br>";
d.getElementById('psu').innerHTML = s;
d.getElementById('psu2').innerHTML = isWS2815 ? "" : s2;
gId('psu').innerHTML = s;
gId('psu2').innerHTML = isWS2815 ? "" : s2;
}
function lastEnd(i) {
if (i<1) return 0;
@ -191,70 +214,88 @@
}
function addLEDs(n)
{
if (n>1) {maxB=n; d.getElementById("+").style.display="inline"; return;}
if (n>1) {maxB=n; gId("+").style.display="inline"; return;}
var o = d.getElementsByClassName("iST");
var i = o.length;
if ((n==1 && i>=maxB) || (n==-1 && i==0)) return;
var f = d.getElementById("mLC");
var f = gId("mLC");
if (n==1) {
// npm run build has trouble minimizing spaces inside string
var cn = `<div class="iST">
${i>0?'<hr style="width:260px">':''}
${i+1}:
<select name="LT${i}" onchange="UI()">
<option value="22">WS281x</option>
<option value="30">SK6812 RGBW</option>
<option value="31">TM1814</option>
<option value="24">400kHz</option>
<option value="50">WS2801</option>
<option value="51">APA102</option>
<option value="52">LPD8806</option>
<option value="53">P9813</option>
<option value="41">PWM White</option>
<option value="42">PWM WWCW</option>
<option value="43">PWM RGB</option>
<option value="44">PWM RGBW</option>
<option value="45">PWM RGBWC</option>
</select>&nbsp;
Color Order:
<select name="CO${i}">
<option value="0">GRB</option>
<option value="1">RGB</option>
<option value="2">BRG</option>
<option value="3">RBG</option>
<option value="4">BGR</option>
<option value="5">GBR</option>
</select><br>
<span id="p0d${i}">Pin:</span> <input type="number" name="L0${i}" min="0" max="40" required style="width:35px" oninput="UI()"/>
<span id="p1d${i}">Clock:</span> <input type="number" name="L1${i}" min="0" max="40" style="width:35px"/>
<span id="p2d${i}"></span><input type="number" name="L2${i}" min="0" max="40" style="width:35px"/>
<span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="40" style="width:35px"/>
<span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="40" style="width:35px"/>
<br>
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" min="0" max="8191" value="${lastEnd(i)}" required />&nbsp;
<div id="dig${i}" style="display:inline">
Count: <input type="number" name="LC${i}" min="0" max="${maxPB}" value="1" required oninput="UI()" /><br>
Skip 1<sup>st</sup> LED: <input id="sl${i}" type="checkbox" name="SL${i}">&nbsp;
</div>
Reverse: <input type="checkbox" name="CV${i}"><br>
</div>`;
${i>0?'<hr style="width:260px">':''}
${i+1}:
<select name="LT${i}" onchange="UI()">
<option value="22">WS281x</option>
<option value="30">SK6812 RGBW</option>
<option value="31">TM1814</option>
<option value="24">400kHz</option>
<option value="50">WS2801</option>
<option value="51">APA102</option>
<option value="52">LPD8806</option>
<option value="53">P9813</option>
<option value="41">PWM White</option>
<option value="42">PWM WWCW</option>
<option value="43">PWM RGB</option>
<option value="44">PWM RGBW</option>
<option value="45">PWM RGBWC</option>
</select>&nbsp;
Color Order:
<select name="CO${i}">
<option value="0">GRB</option>
<option value="1">RGB</option>
<option value="2">BRG</option>
<option value="3">RBG</option>
<option value="4">BGR</option>
<option value="5">GBR</option>
</select><br>
<span id="p0d${i}">Pin:</span> <input type="number" name="L0${i}" min="0" max="40" required style="width:35px" onchange="UI()"/>
<span id="p1d${i}">Clock:</span> <input type="number" name="L1${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
<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()"/>
<span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="40" style="width:35px" onchange="UI()"/>
<br>
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" min="0" max="8191" value="${lastEnd(i)}" required />&nbsp;
<div id="dig${i}" style="display:inline">
Count: <input type="number" name="LC${i}" min="0" max="${maxPB}" value="1" required oninput="UI()" /><br>
Reverse (rotated 180°): <input type="checkbox" name="CV${i}">
&nbsp;Skip 1<sup>st</sup> LED: <input id="sl${i}" type="checkbox" name="SL${i}"><br>
</div>
</div>`;
f.insertAdjacentHTML("beforeend", cn);
}
if (n==-1) {
o[--i].remove();--i;
}
d.getElementById("+").style.display = (i<maxB-1) ? "inline":"none";
d.getElementById("-").style.display = (i>0) ? "inline":"none";
gId("+").style.display = (i<maxB-1) ? "inline":"none";
gId("-").style.display = (i>0) ? "inline":"none";
UI();
}
function addBtn(i,p,t) {
var c = gId("btns").innerHTML;
var bt = "BT" + i;
var be = "BE" + i;
c += `Button ${i} pin: <input type="number" min="-1" max="40" name="${bt}" onchange="UI()" style="width:35px" value="${p}">&nbsp;`;
c += `<select name="${be}">`
c += `<option value="0" ${t==0?"selected":""}>Disabled</option>`;
c += `<option value="2" ${t==2?"selected":""}>Pushbutton</option>`;
c += `<option value="2" ${t==3?"selected":""}>Push inverted</option>`;
c += `<option value="4" ${t==4?"selected":""}>Switch</option>`;
c += `<option value="5" ${t==4?"selected":""}>Switch inverted</option>`;
c += `<option value="6" ${t==6?"selected":""}>Touch</option>`;
c += `<option value="7" ${t==7?"selected":""}>Analog</option>`;
c += `</select>`;
c += `<span style="cursor: pointer;" onclick="off('${bt}')">&nbsp;&#215;</span><br>`;
gId("btns").innerHTML = c;
}
function GetV()
{
//values injected by server while sending HTML
//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;
//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;
}
</script>
<style>
@ -262,11 +303,11 @@
</style>
</head>
<body onload="S()">
<form id="form_s" name="Sf" method="post" onsubmit="trySubmit(event)">
<form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<h2>LED &amp; Hardware setup</h2>
Total LED count: <input name="LC" type="number" min="1" max="8192" oninput="UI()" required><br>
Total LED count: <input name="LC" id="LC" type="number" min="1" max="8192" oninput="UI()" required><br>
<i>Recommended power supply for brightest white:</i><br>
<b><span id="psu">?</span></b><br>
<span id="psu2"><br></span>
@ -304,11 +345,22 @@
<div id="ledwarning" style="color: orange; display: none;">
&#9888; You might run into stability or lag issues.<br>
Use less than <span id="wreason">800 LEDs per pin</span> for the best experience!<br>
</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>
IR pin: <input type="number" min="-1" max="40" name="IR" onchange="UI()"><span style="cursor: pointer;" onclick="off('IR')">&nbsp;&#215;</span><br>
Relay pin: <input type="number" min="-1" max="40" name="RL" onchange="UI()"><span style="cursor: pointer;" onclick="off('RL')">&nbsp;&#215;</span><br>
Active high <input type="checkbox" name="RM">
</div><hr style="width:260px">
<div id="btns"></div>
Touch threshold: <input type="number" min="0" max="100" name="TT" required><br>
IR pin: <input type="number" min="-1" max="40" name="IR" onchange="UI()" style="width:35px">&nbsp;<select name="IT">
<option value="0">Remote 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><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()" style="width:35px"> 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>

View File

@ -15,29 +15,10 @@ function GetV(){var d=document;}
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<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>
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>
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 button press or IR: <input type="checkbox" name="SB"><br>
Send Alexa notifications: <input type="checkbox" name="SA"><br>

View File

@ -74,6 +74,21 @@
}
gId("W"+i).value=a[i];
}
}
function addRow(i,p,l,d) {
var t = gId("macros"); // table
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()
{
@ -148,10 +163,22 @@
Just enter the preset id below!</i>
<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>
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>
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>
<a href="https://github.com/Aircoookie/WLED/wiki/Macros#analog-button" target="_blank">Analog Button setup</a>
<h3>Time-controlled presets</h3>
<div style="display: inline-block">
<table id="TMT">

View File

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

File diff suppressed because one or more lines are too long

View File

@ -79,9 +79,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (rlyPin>=0 && pinManager.isPinAllocated(rlyPin)) pinManager.deallocatePin(rlyPin);
if (irPin>=0 && pinManager.isPinAllocated(irPin)) pinManager.deallocatePin(irPin);
if (btnPin>=0 && pinManager.isPinAllocated(btnPin)) pinManager.deallocatePin(btnPin);
//TODO remove all busses, but not in this system call
//busses->removeAll();
for (uint8_t s=0; s<WLED_MAX_BUTTONS; s++)
if (btnPin[s]>=0 && pinManager.isPinAllocated(btnPin[s]))
pinManager.deallocatePin(btnPin[s]);
strip.isRgbw = false;
uint8_t colorOrder, type, skip;
@ -97,7 +97,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
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
if (!request->hasArg(lp)) {
DEBUG_PRINTLN("No data."); break;
DEBUG_PRINTLN(F("No data.")); break;
}
for (uint8_t i = 0; i < 5; i++) {
lp[1] = 48+i;
@ -127,11 +127,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
// upate other pins
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;
} else {
irPin = -1;
}
irEnabled = request->arg(F("IT")).toInt();
int hw_rly_pin = request->arg(F("RL")).toInt();
if (pinManager.allocatePin(hw_rly_pin,true)) {
@ -141,13 +142,20 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
}
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++) {
char bt[4] = "BT"; bt[2] = 48+i; bt[3] = 0; // button pin
char be[4] = "BE"; be[2] = 48+i; be[3] = 0; // button type
int hw_btn_pin = request->arg(bt).toInt();
if (pinManager.allocatePin(hw_btn_pin,false)) {
btnPin = hw_btn_pin;
pinMode(btnPin, INPUT_PULLUP);
btnPin[i] = hw_btn_pin;
pinMode(btnPin[i], INPUT_PULLUP);
buttonType[i] = request->arg(be).toInt();
} else {
btnPin = -1;
btnPin[i] = -1;
buttonType[i] = BTN_TYPE_NONE;
}
}
touchThreshold = request->arg(F("TT")).toInt();
strip.ablMilliampsMax = request->arg(F("MA")).toInt();
strip.milliampsPerLed = request->arg(F("LA")).toInt();
@ -191,8 +199,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
//SYNC
if (subPage == 4)
{
buttonType = request->arg(F("BT")).toInt();
irEnabled = request->arg(F("IR")).toInt();
int t = request->arg(F("UP")).toInt();
if (t > 0) udpPort = t;
t = request->arg(F("U2")).toInt();
@ -234,6 +240,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
alexaEnabled = request->hasArg(F("AL"));
strlcpy(alexaInvocationName, request->arg(F("AI")).c_str(), 33);
#ifndef WLED_DISABLE_BLYNK
strlcpy(blynkHost, request->arg("BH").c_str(), 33);
t = request->arg(F("BP")).toInt();
if (t > 0) blynkPort = t;
@ -241,6 +248,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
if (request->hasArg("BK") && !request->arg("BK").equals(F("Hidden"))) {
strlcpy(blynkApiKey, request->arg("BK").c_str(), 36); initBlynk(blynkApiKey, blynkHost, blynkPort);
}
#endif
#ifdef WLED_ENABLE_MQTT
mqttEnabled = request->hasArg(F("MQ"));
@ -303,8 +311,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
analogClock5MinuteMarks = request->hasArg(F("O5"));
analogClockSecondsTrail = request->hasArg(F("OS"));
#ifndef WLED_DISABLE_CRONIXIE
strcpy(cronixieDisplay,request->arg(F("CX")).c_str());
cronixieBacklight = request->hasArg(F("CB"));
#endif
countdownMode = request->hasArg(F("CE"));
countdownYear = request->arg(F("CY")).toInt();
countdownMonth = request->arg(F("CI")).toInt();
@ -316,11 +326,17 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
macroAlexaOn = request->arg(F("A0")).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();
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;
for (int i = 0; i<10; i++)

View File

@ -75,7 +75,6 @@ ethernet_settings ethernetBoards[] = {
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
}
};
#endif
// turns all LEDs off and restarts ESP
@ -90,7 +89,7 @@ void WLED::reset()
yield(); // enough time to send response to client
}
setAllLeds();
DEBUG_PRINTLN("MODULE RESET");
DEBUG_PRINTLN(F("MODULE RESET"));
ESP.restart();
}
@ -148,10 +147,10 @@ void WiFiEvent(WiFiEvent_t event)
switch (event) {
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
case SYSTEM_EVENT_ETH_START:
DEBUG_PRINT("ETH Started");
DEBUG_PRINT(F("ETH Started"));
break;
case SYSTEM_EVENT_ETH_CONNECTED:
DEBUG_PRINT("ETH Connected");
DEBUG_PRINT(F("ETH Connected"));
if (!apActive) {
WiFi.disconnect(true);
}
@ -166,7 +165,7 @@ void WiFiEvent(WiFiEvent_t event)
showWelcomePage = false;
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
DEBUG_PRINT("ETH Disconnected");
DEBUG_PRINT(F("ETH Disconnected"));
forceReconnect = true;
break;
#endif
@ -178,7 +177,6 @@ void WiFiEvent(WiFiEvent_t event)
void WLED::loop()
{
handleTime();
handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too
handleConnection();
handleSerial();
@ -232,10 +230,17 @@ void WLED::loop()
#ifdef ESP8266
MDNS.update();
#endif
//millis() rolls over every 50 days
if (lastMqttReconnectAttempt > millis()) {
rolloverMillis++;
lastMqttReconnectAttempt = 0;
}
if (millis() - lastMqttReconnectAttempt > 30000) {
if (lastMqttReconnectAttempt > millis()) rolloverMillis++; //millis() rolls over every 50 days
lastMqttReconnectAttempt = millis();
initMqtt();
yield();
// refresh WLED nodes list
refreshNodeList();
if (nodeBroadcastEnabled) sendSysInfoUDP();
yield();
@ -245,6 +250,7 @@ void WLED::loop()
//This code block causes severe FPS drop on ESP32 with the original "if (busConfigs[0] != nullptr)" conditional. Investigate!
if (doInitBusses) {
doInitBusses = false;
DEBUG_PRINTLN(F("Re-init busses."));
busses.removeAll();
uint32_t mem = 0;
strip.isRgbw = false;
@ -268,20 +274,27 @@ void WLED::loop()
// DEBUG serial logging
#ifdef WLED_DEBUG
if (millis() - debugTime > 9999) {
DEBUG_PRINTLN("---DEBUG INFO---");
DEBUG_PRINT("Runtime: "); DEBUG_PRINTLN(millis());
DEBUG_PRINT("Unix time: "); toki.printTime(toki.getTime());
DEBUG_PRINT("Free heap: "); DEBUG_PRINTLN(ESP.getFreeHeap());
DEBUG_PRINT("Wifi state: "); DEBUG_PRINTLN(WiFi.status());
DEBUG_PRINTLN(F("---DEBUG INFO---"));
DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis());
DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime());
DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(ESP.getFreeHeap());
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
if (psramFound()) {
DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB");
DEBUG_PRINT(F("Free PSRAM: ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB");
} else
DEBUG_PRINTLN(F("No PSRAM"));
#endif
DEBUG_PRINT(F("Wifi state: ")); DEBUG_PRINTLN(WiFi.status());
if (WiFi.status() != lastWifiState) {
wifiStateChangedTime = millis();
}
lastWifiState = WiFi.status();
DEBUG_PRINT("State time: "); DEBUG_PRINTLN(wifiStateChangedTime);
DEBUG_PRINT("NTP last sync: "); DEBUG_PRINTLN(ntpLastSyncTime);
DEBUG_PRINT("Client IP: "); DEBUG_PRINTLN(Network.localIP());
DEBUG_PRINT("Loops/sec: "); DEBUG_PRINTLN(loops / 10);
DEBUG_PRINT(F("State time: ")); DEBUG_PRINTLN(wifiStateChangedTime);
DEBUG_PRINT(F("NTP last sync: ")); DEBUG_PRINTLN(ntpLastSyncTime);
DEBUG_PRINT(F("Client IP: ")); DEBUG_PRINTLN(Network.localIP());
DEBUG_PRINT(F("Loops/sec: ")); DEBUG_PRINTLN(loops / 10);
loops = 0;
debugTime = millis();
}
@ -299,25 +312,35 @@ void WLED::setup()
Serial.begin(115200);
Serial.setTimeout(50);
DEBUG_PRINTLN();
DEBUG_PRINT("---WLED ");
DEBUG_PRINT(F("---WLED "));
DEBUG_PRINT(versionString);
DEBUG_PRINT(" ");
DEBUG_PRINT(VERSION);
DEBUG_PRINTLN(" INIT---");
DEBUG_PRINTLN(F(" INIT---"));
#ifdef ARDUINO_ARCH_ESP32
DEBUG_PRINT("esp32 ");
DEBUG_PRINT(F("esp32 "));
DEBUG_PRINTLN(ESP.getSdkVersion());
#else
DEBUG_PRINT("esp8266 ");
DEBUG_PRINT(F("esp8266 "));
DEBUG_PRINTLN(ESP.getCoreVersion());
#endif
DEBUG_PRINT("heap ");
DEBUG_PRINT(F("heap "));
DEBUG_PRINTLN(ESP.getFreeHeap());
registerUsermods();
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
if (psramFound()) {
pinManager.allocatePin(16); // GPIO16 reserved for SPI RAM
pinManager.allocatePin(17); // GPIO17 reserved for SPI RAM
}
#endif
//DEBUG_PRINT(F("LEDs inited. heap usage ~"));
//DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap());
#ifdef WLED_DEBUG
pinManager.allocatePin(1,true); // GPIO1 reserved for debug output
#endif
#ifdef WLED_USE_DMX //reserve GPIO2 as hardcoded DMX pin
pinManager.allocatePin(2);
#endif
@ -334,21 +357,18 @@ void WLED::setup()
errorFlag = ERR_FS_BEGIN;
} else deEEP();
updateFSInfo();
DEBUG_PRINTLN(F("Reading config"));
deserializeConfigFromFS();
#if STATUSLED
bool lStatusLed = false;
for (uint8_t i=0; i<strip.numStrips; i++) {
if (strip.getStripPin(i)==STATUSLED) {
lStatusLed = true;
break;
}
}
if (!lStatusLed)
pinMode(STATUSLED, OUTPUT);
if (!pinManager.isPinAllocated(STATUSLED)) pinMode(STATUSLED, OUTPUT);
#endif
DEBUG_PRINTLN(F("Initializing strip"));
beginStrip();
DEBUG_PRINTLN(F("Usermods setup"));
userSetup();
usermods.setup();
if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0)
@ -358,7 +378,11 @@ void WLED::setup()
WiFi.onEvent(WiFiEvent);
#endif
#ifdef WLED_ENABLE_ADALIGHT
if (!pinManager.isPinAllocated(3)) {
Serial.println(F("Ada"));
}
#endif
// generate module IDs
escapedMac = WiFi.macAddress();
@ -397,6 +421,10 @@ void WLED::setup()
#endif
// HTTP server page init
initServer();
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET)
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); //enable brownout detector
#endif
}
void WLED::beginStrip()
@ -410,8 +438,9 @@ void WLED::beginStrip()
strip.setBrightness(0);
strip.setShowCallback(handleOverlayDraw);
if (bootPreset > 0) applyPreset(bootPreset);
if (turnOnAtBoot) {
if (bootPreset > 0) {
applyPreset(bootPreset);
} else if (turnOnAtBoot) {
if (briS > 0) bri = briS;
else if (bri == 0) bri = 128;
} else {
@ -424,8 +453,8 @@ void WLED::beginStrip()
digitalWrite(rlyPin, (rlyMde ? bri : !bri));
// disable button if it is "pressed" unintentionally
if (btnPin>=0 && buttonType == BTN_TYPE_PUSH && isButtonPressed())
buttonType = BTN_TYPE_NONE;
//if (btnPin>=0 && buttonType == BTN_TYPE_PUSH && isButtonPressed())
// buttonType = BTN_TYPE_NONE;
}
void WLED::initAP(bool resetAP)
@ -539,11 +568,13 @@ void WLED::initInterfaces()
{
DEBUG_PRINTLN(F("Init STA interfaces"));
#ifndef WLED_DISABLE_HUESYNC
if (hueIP[0] == 0) {
hueIP[0] = Network.localIP()[0];
hueIP[1] = Network.localIP()[1];
hueIP[2] = Network.localIP()[2];
}
#endif
// init Alexa hue emulation
if (alexaEnabled)
@ -581,7 +612,9 @@ void WLED::initInterfaces()
if (ntpEnabled)
ntpConnected = ntpUdp.begin(ntpLocalPort);
#ifndef WLED_DISABLE_BLYNK
initBlynk(blynkApiKey, blynkHost, blynkPort);
#endif
e131.begin(e131Multicast, e131Port, e131Universe, E131_MAX_UNIVERSE_COUNT);
reconnectHue();
initMqtt();
@ -603,7 +636,7 @@ void WLED::handleConnection()
// reconnect WiFi to clear stale allocations if heap gets too low
if (millis() - heapTime > 5000) {
uint32_t heap = ESP.getFreeHeap();
if (heap < 9000 && lastHeap < 9000) {
if (heap < JSON_BUFFER_SIZE+512 && lastHeap < JSON_BUFFER_SIZE+512) {
DEBUG_PRINT(F("Heap too low! "));
DEBUG_PRINTLN(heap);
forceReconnect = true;
@ -672,11 +705,7 @@ void WLED::handleConnection()
void WLED::handleStatusLED()
{
#if STATUSLED
for (uint8_t s=0; s<strip.numStrips; s++) {
if (strip.getStripPin(s)==STATUSLED) {
return; // pin used for strip
}
}
if (pinManager.isPinAllocated(STATUSLED)) return; //lower priority if something else uses the same pin
ledStatusType = WLED_CONNECTED ? 0 : 2;
if (mqttEnabled && ledStatusType != 2) // Wi-Fi takes presendence over MQTT

View File

@ -114,6 +114,26 @@
#include "src/dependencies/json/AsyncJson-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)
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
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 "html_ui.h"
#include "html_settings.h"
@ -189,9 +209,9 @@ WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS);
// Hardware CONFIG (only changeble HERE, not at runtime)
// LED strip pin, button pin and IR pin changeable in NpbWrapper.h!
#ifndef BTNPIN
WLED_GLOBAL int8_t btnPin _INIT(0);
WLED_GLOBAL int8_t btnPin[WLED_MAX_BUTTONS] _INIT({0});
#else
WLED_GLOBAL int8_t btnPin _INIT(BTNPIN);
WLED_GLOBAL int8_t btnPin[WLED_MAX_BUTTONS] _INIT({BTNPIN});
#endif
#ifndef RLYPIN
WLED_GLOBAL int8_t rlyPin _INIT(12);
@ -264,7 +284,7 @@ WLED_GLOBAL NodesMap Nodes;
WLED_GLOBAL bool nodeListEnabled _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 uint16_t udpPort _INIT(21324); // WLED notifier default port
@ -284,9 +304,11 @@ WLED_GLOBAL bool notifyTwice _INIT(false); // notificatio
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
#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 blynkHost[33] _INIT("blynk-cloud.com"); // Default Blynk host
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 int arlsOffset _INIT(0); // realtime LED offset
@ -316,6 +338,7 @@ WLED_GLOBAL char mqttPass[41] _INIT(""); // optional: password
WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID
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 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
@ -324,6 +347,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 hueApplyBri _INIT(true);
WLED_GLOBAL bool hueApplyColor _INIT(true);
#endif
// Time CONFIG
WLED_GLOBAL bool ntpEnabled _INIT(false); // get internet time. Only required if you use clock overlays or time-activated macros
@ -338,8 +362,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 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 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 byte countdownYear _INIT(20), countdownMonth _INIT(1); // Countdown target date, year is last two digits
@ -349,7 +375,9 @@ WLED_GLOBAL byte countdownMin _INIT(0) , countdownSec _INIT(0);
WLED_GLOBAL byte macroNl _INIT(0); // after nightlight delay over
WLED_GLOBAL byte macroCountdown _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
WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks
@ -410,10 +438,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
// button
WLED_GLOBAL bool buttonPressedBefore _INIT(false);
WLED_GLOBAL bool buttonLongPressed _INIT(false);
WLED_GLOBAL unsigned long buttonPressedTime _INIT(0);
WLED_GLOBAL unsigned long buttonWaitTime _INIT(0);
WLED_GLOBAL bool buttonPressedBefore[WLED_MAX_BUTTONS] _INIT({false});
WLED_GLOBAL bool buttonLongPressed[WLED_MAX_BUTTONS] _INIT({false});
WLED_GLOBAL unsigned long buttonPressedTime[WLED_MAX_BUTTONS] _INIT({0});
WLED_GLOBAL unsigned long buttonWaitTime[WLED_MAX_BUTTONS] _INIT({0});
WLED_GLOBAL byte touchThreshold _INIT(TOUCH_THRESHOLD);
// notifications
WLED_GLOBAL bool notifyDirectDefault _INIT(notifyDirect);

View File

@ -93,7 +93,7 @@ void loadSettingsFromEEPROM()
notifyButton = EEPROM.read(230);
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[1] = EEPROM.read(235);
@ -157,6 +157,7 @@ void loadSettingsFromEEPROM()
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
if (lastEEPROMversion > 4) {
#ifndef WLED_DISABLE_HUESYNC
huePollingEnabled = EEPROM.read(2048);
//hueUpdatingEnabled = EEPROM.read(2049);
for (int i = 2050; i < 2054; ++i)
@ -172,6 +173,7 @@ void loadSettingsFromEEPROM()
hueApplyBri = EEPROM.read(2104);
hueApplyColor = EEPROM.read(2105);
huePollLightId = EEPROM.read(2106);
#endif
}
if (lastEEPROMversion > 5) {
overlayMin = EEPROM.read(2150);
@ -188,18 +190,20 @@ void loadSettingsFromEEPROM()
countdownSec = EEPROM.read(2161);
setCountdown();
#ifndef WLED_DISABLE_CRONIXIE
readStringFromEEPROM(2165, cronixieDisplay, 6);
cronixieBacklight = EEPROM.read(2171);
#endif
//macroBoot = EEPROM.read(2175);
macroAlexaOn = EEPROM.read(2176);
macroAlexaOff = EEPROM.read(2177);
macroButton = EEPROM.read(2178);
macroLongPress = EEPROM.read(2179);
macroButton[0] = EEPROM.read(2178);
macroLongPress[0] = EEPROM.read(2179);
macroCountdown = EEPROM.read(2180);
macroNl = EEPROM.read(2181);
macroDoublePress = EEPROM.read(2182);
if (macroDoublePress > 16) macroDoublePress = 0;
macroDoublePress[0] = EEPROM.read(2182);
if (macroDoublePress[0] > 16) macroDoublePress[0] = 0;
}
if (lastEEPROMversion > 6)
@ -237,7 +241,7 @@ void loadSettingsFromEEPROM()
if (lastEEPROMversion > 9)
{
strip.setColorOrder(EEPROM.read(383));
//strip.setColorOrder(EEPROM.read(383));
irEnabled = EEPROM.read(385);
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
@ -343,8 +347,10 @@ void loadSettingsFromEEPROM()
//custom macro memory (16 slots/ each 64byte)
//1024-2047 reserved
#ifndef WLED_DISABLE_BLYNK
readStringFromEEPROM(2220, blynkApiKey, 35);
if (strlen(blynkApiKey) < 25) blynkApiKey[0] = 0;
#endif
#ifdef WLED_ENABLE_DMX
// DMX (2530 - 2549)2535
@ -417,10 +423,10 @@ void deEEP() {
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("ix")] = EEPROM.read(i+16);
segObj[F("pal")] = EEPROM.read(i+17);
segObj["pal"] = EEPROM.read(i+17);
} else {
WS2812FX::Segment* seg = strip.getSegments();
memcpy(seg, EEPROM.getDataPtr() +i+2, 240);

View File

@ -256,27 +256,53 @@ void getSettingsJS(byte subPage, char* dest)
if (subPage == 2) {
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)
/*DynamicJsonDocument doc(JSON_BUFFER_SIZE);
JsonObject mods = doc.createNestedObject(F("mods"));
usermods.addToJsonState(mods);
// add reserved and usermod pins as d.um_p array
DynamicJsonDocument doc(JSON_BUFFER_SIZE/2);
JsonObject mods = doc.createNestedObject(F("um"));
usermods.addToConfig(mods);
oappend(SET_F("d.um_p=["));
if (!mods.isNull()) {
uint8_t i=0;
oappend(SET_F("d.um_p=["));
for (JsonPair kv : mods) {
if (strncmp_P(kv.key().c_str(),PSTR("pin_"),4) == 0) {
if (!kv.value().isNull()) {
// element is an JsonObject
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(","));
oappend(itoa((int)kv.value(),nS,10));
oappendi(pv.as<int>());
}
} else {
if (i++) oappend(SET_F(","));
oappendi(obj["pin"].as<int>());
}
}
}
}
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
//Adalight / Serial in requires pin 3 to be unused. However, Serial input can not be prevented by WLED
#ifdef WLED_DEBUG
oappend(SET_F(",1")); // debug output (TX) pin
#endif
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
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(itoa(WLED_MAX_BUSSES,nS,10));
oappend(",");
oappend(itoa(MAX_LEDS_PER_BUS,nS,10));
oappend(",");
oappend(itoa(WLED_MAX_BUSSES,nS,10)); oappend(",");
oappend(itoa(MAX_LEDS_PER_BUS,nS,10)); oappend(",");
oappend(itoa(MAX_LED_MEMORY,nS,10));
oappend(SET_F(");"));
@ -286,7 +312,7 @@ void getSettingsJS(byte subPage, char* dest)
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);
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
@ -320,7 +346,6 @@ void getSettingsJS(byte subPage, char* dest)
}
sappend('v',SET_F("CA"),briS);
sappend('v',SET_F("AW"),strip.rgbwMode);
sappend('c',SET_F("BO"),turnOnAtBoot);
@ -338,8 +363,16 @@ void getSettingsJS(byte subPage, char* dest)
sappend('i',SET_F("PB"),strip.paletteBlend);
sappend('v',SET_F("RL"),rlyPin);
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("IT"),irEnabled);
}
if (subPage == 3)
@ -350,8 +383,6 @@ void getSettingsJS(byte subPage, char* dest)
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("U2"),udpPort2);
sappend('c',SET_F("RB"),receiveNotificationBrightness);
@ -381,8 +412,10 @@ void getSettingsJS(byte subPage, char* dest)
sappends('s',SET_F("AI"),alexaInvocationName);
sappend('c',SET_F("SA"),notifyAlexa);
sappends('s',SET_F("BK"),(char*)((blynkEnabled)?SET_F("Hidden"):""));
#ifndef WLED_DISABLE_BLYNK
sappends('s',SET_F("BH"),blynkHost);
sappend('v',SET_F("BP"),blynkPort);
#endif
#ifdef WLED_ENABLE_MQTT
sappend('c',SET_F("MQ"),mqttEnabled);
@ -451,8 +484,10 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("OM"),analogClock12pixel);
sappend('c',SET_F("OS"),analogClockSecondsTrail);
sappend('c',SET_F("O5"),analogClock5MinuteMarks);
#ifndef WLED_DISABLE_CRONIXIE
sappends('s',SET_F("CX"),cronixieDisplay);
sappend('c',SET_F("CB"),cronixieBacklight);
#endif
sappend('c',SET_F("CE"),countdownMode);
sappend('v',SET_F("CY"),countdownYear);
sappend('v',SET_F("CI"),countdownMonth);
@ -463,11 +498,16 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("A0"),macroAlexaOn);
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("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];
k[2] = 0; //Time macros