Merge branch 'master' into dev
Minor tweaks.
This commit is contained in:
commit
3066a142b8
19
CHANGELOG.md
19
CHANGELOG.md
@ -2,6 +2,25 @@
|
||||
|
||||
### Builds after release 0.12.0
|
||||
|
||||
#### Build 2107021
|
||||
|
||||
- Added WebSockets support to UI
|
||||
|
||||
#### Build 2107020
|
||||
|
||||
- Send websockets on every state change
|
||||
- Improved Aurora effect
|
||||
|
||||
#### Build 2107011
|
||||
|
||||
- Added MQTT button feedback option (PR #2011)
|
||||
|
||||
#### Build 2107010
|
||||
|
||||
- Added JSON IR codes (PR #1941)
|
||||
- Adjusted the width of WiFi and LED settings input fields
|
||||
- Fixed a minor visual issue with slider trail not reaching thumb on low values
|
||||
|
||||
#### Build 2106302
|
||||
|
||||
- Fixed settings page broken by using "%" in input fields
|
||||
|
@ -185,18 +185,18 @@ upload_speed = 115200
|
||||
# ------------------------------------------------------------------------------
|
||||
lib_compat_mode = strict
|
||||
lib_deps =
|
||||
fastled/FastLED @ 3.3.2
|
||||
NeoPixelBus @ ^2.6.0
|
||||
fastled/FastLED @ 3.4.0
|
||||
NeoPixelBus @ 2.6.4
|
||||
ESPAsyncTCP @ 1.2.0
|
||||
ESPAsyncUDP
|
||||
AsyncTCP @ 1.0.3
|
||||
IRremoteESP8266 @ 2.7.3
|
||||
IRremoteESP8266 @ 2.7.18
|
||||
https://github.com/lorol/LITTLEFS.git
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.2
|
||||
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
||||
#TFT_eSPI
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
U8g2@~2.27.2
|
||||
U8g2@~2.28.8
|
||||
#For Dallas sensor uncomment following 2 lines
|
||||
OneWire@~2.3.5
|
||||
; milesburton/DallasTemperature@^3.9.0
|
||||
|
@ -193,16 +193,16 @@ public:
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||
if (!pinManager.allocatePin(PIRsensorPin,false)) {
|
||||
PIRsensorPin = -1; // allocation failed
|
||||
enabled = false;
|
||||
DEBUG_PRINTLN(F("PIRSensorSwitch pin allocation failed."));
|
||||
} else {
|
||||
// PIR Sensor mode INPUT_PULLUP
|
||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||
if (enabled) {
|
||||
if (enabled) {
|
||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||
if (PIRsensorPin >= 0 && pinManager.allocatePin(PIRsensorPin,false)) {
|
||||
// PIR Sensor mode INPUT_PULLUP
|
||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||
sensorPinState = digitalRead(PIRsensorPin);
|
||||
} else {
|
||||
if (PIRsensorPin >= 0) DEBUG_PRINTLN(F("PIRSensorSwitch pin allocation failed."));
|
||||
PIRsensorPin = -1; // allocation failed
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
initDone = true;
|
||||
@ -221,8 +221,8 @@ public:
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
// only check sensors 10x/s
|
||||
if (millis() - lastLoop < 100 || strip.isUpdating()) return;
|
||||
// only check sensors 4x/s
|
||||
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
||||
lastLoop = millis();
|
||||
|
||||
if (!updatePIRsensorState()) {
|
||||
|
@ -107,19 +107,20 @@ class UsermodTemperature : public Usermod {
|
||||
|
||||
void setup() {
|
||||
int retries = 10;
|
||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||
if (!pinManager.allocatePin(temperaturePin,false)) {
|
||||
temperaturePin = -1; // allocation failed
|
||||
enabled = false;
|
||||
DEBUG_PRINTLN(F("Temperature pin allocation failed."));
|
||||
} else {
|
||||
if (enabled) {
|
||||
// config says we are enabled
|
||||
if (enabled) {
|
||||
// config says we are enabled
|
||||
DEBUG_PRINTLN(F("Allocating temperature pin..."));
|
||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||
if (temperaturePin >= 0 && pinManager.allocatePin(temperaturePin)) {
|
||||
oneWire = new OneWire(temperaturePin);
|
||||
if (!oneWire->reset())
|
||||
enabled = false; // resetting 1-Wire bus yielded an error
|
||||
else
|
||||
while ((enabled=findSensor()) && retries--) delay(25); // try to find sensor
|
||||
} else {
|
||||
if (temperaturePin >= 0) DEBUG_PRINTLN(F("Temperature pin allocation failed."));
|
||||
temperaturePin = -1; // allocation failed
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
initDone = true;
|
||||
|
@ -133,6 +133,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
if (type == NONE) return;
|
||||
if (!pinManager.allocatePin(sclPin)) { sclPin = -1; type = NONE; return;}
|
||||
if (!pinManager.allocatePin(sdaPin)) { pinManager.deallocatePin(sclPin); sclPin = sdaPin = -1; type = NONE; return; }
|
||||
DEBUG_PRINTLN(F("Allocating display."));
|
||||
switch (type) {
|
||||
case SSD1306:
|
||||
#ifdef ESP8266
|
||||
@ -184,12 +185,19 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
type = NONE;
|
||||
return;
|
||||
}
|
||||
(static_cast<U8X8*>(u8x8))->begin();
|
||||
initDone = true;
|
||||
if (u8x8 != nullptr) {
|
||||
DEBUG_PRINTLN(F("Starting display."));
|
||||
(static_cast<U8X8*>(u8x8))->begin();
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("Display init failed."));
|
||||
type = NONE;
|
||||
return;
|
||||
}
|
||||
setFlipMode(flip);
|
||||
setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||
setPowerSave(0);
|
||||
drawString(0, 0, "Loading...");
|
||||
initDone = true;
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
@ -648,6 +656,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
type = newType;
|
||||
DEBUG_PRINTLN(F(" config loaded."));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
// changing parameters from settings page
|
||||
if (sclPin!=newScl || sdaPin!=newSda || type!=newType) {
|
||||
if (type != NONE) delete (static_cast<U8X8*>(u8x8));
|
||||
@ -665,7 +674,6 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
setContrast(contrast);
|
||||
setFlipMode(flip);
|
||||
if (needsRedraw && !wakeDisplay()) redraw(true);
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return true;
|
||||
|
@ -3926,7 +3926,6 @@ uint16_t WS2812FX::mode_tv_simulator(void) {
|
||||
*/
|
||||
|
||||
//CONFIG
|
||||
#define BACKLIGHT 5
|
||||
#define W_MAX_COUNT 20 //Number of simultaneous waves
|
||||
#define W_MAX_SPEED 6 //Higher number, higher speed
|
||||
#define W_WIDTH_FACTOR 6 //Higher number, smaller waves
|
||||
@ -4051,9 +4050,13 @@ uint16_t WS2812FX::mode_aurora(void) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t backlight = 1; //dimmer backlight if less active colors
|
||||
if (SEGCOLOR(0)) backlight++;
|
||||
if (SEGCOLOR(1)) backlight++;
|
||||
if (SEGCOLOR(2)) backlight++;
|
||||
//Loop through LEDs to determine color
|
||||
for(int i = 0; i < SEGLEN; i++) {
|
||||
CRGB mixedRgb = CRGB(BACKLIGHT, BACKLIGHT, BACKLIGHT);
|
||||
CRGB mixedRgb = CRGB(backlight, backlight, backlight);
|
||||
|
||||
//For each LED we must check each wave if it is "active" at this position.
|
||||
//If there are multiple waves active on a LED we multiply their values.
|
||||
@ -4065,7 +4068,7 @@ uint16_t WS2812FX::mode_aurora(void) {
|
||||
}
|
||||
}
|
||||
|
||||
setPixelColor(i, mixedRgb[0], mixedRgb[1], mixedRgb[2], BACKLIGHT);
|
||||
setPixelColor(i, mixedRgb[0], mixedRgb[1], mixedRgb[2]);
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
|
22
wled00/FX.h
22
wled00/FX.h
@ -319,6 +319,27 @@ class WS2812FX {
|
||||
vLength = (vLength + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
return vLength;
|
||||
}
|
||||
uint8_t differs(Segment& b) {
|
||||
uint8_t d = 0;
|
||||
if (start != b.start) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (offset != b.offset) d |= SEG_DIFFERS_GSO;
|
||||
if (grouping != b.grouping) d |= SEG_DIFFERS_GSO;
|
||||
if (spacing != b.spacing) d |= SEG_DIFFERS_GSO;
|
||||
if (opacity != b.opacity) d |= SEG_DIFFERS_BRI;
|
||||
if (mode != b.mode) d |= SEG_DIFFERS_FX;
|
||||
if (speed != b.speed) d |= SEG_DIFFERS_FX;
|
||||
if (intensity != b.intensity) d |= SEG_DIFFERS_FX;
|
||||
if (palette != b.palette) d |= SEG_DIFFERS_FX;
|
||||
|
||||
if ((options & 0b00101111) != (b.options & 0b00101111)) d |= SEG_DIFFERS_OPT;
|
||||
for (uint8_t i = 0; i < NUM_COLORS; i++)
|
||||
{
|
||||
if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
} segment;
|
||||
|
||||
// segment runtime parameters
|
||||
@ -619,7 +640,6 @@ class WS2812FX {
|
||||
gammaCorrectBri = false,
|
||||
gammaCorrectCol = true,
|
||||
applyToAllSelected = true,
|
||||
segmentsAreIdentical(Segment* a, Segment* b),
|
||||
setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p),
|
||||
// return true if the strip is being sent pixel updates
|
||||
isUpdating(void);
|
||||
|
@ -1018,23 +1018,6 @@ uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8
|
||||
return crgb_to_col(fastled_col);
|
||||
}
|
||||
|
||||
//@returns `true` if color, mode, speed, intensity and palette match
|
||||
bool WS2812FX::segmentsAreIdentical(Segment* a, Segment* b)
|
||||
{
|
||||
//if (a->start != b->start) return false;
|
||||
//if (a->stop != b->stop) return false;
|
||||
for (uint8_t i = 0; i < NUM_COLORS; i++)
|
||||
{
|
||||
if (a->colors[i] != b->colors[i]) return false;
|
||||
}
|
||||
if (a->mode != b->mode) return false;
|
||||
if (a->speed != b->speed) return false;
|
||||
if (a->intensity != b->intensity) return false;
|
||||
if (a->palette != b->palette) return false;
|
||||
//if (a->getOption(SEG_OPTION_REVERSED) != b->getOption(SEG_OPTION_REVERSED)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//load custom mapping table from JSON file
|
||||
void WS2812FX::deserializeMap(uint8_t n) {
|
||||
|
@ -19,7 +19,7 @@ void shortPressAction(uint8_t b)
|
||||
}
|
||||
|
||||
// publish MQTT message
|
||||
if (WLED_MQTT_CONNECTED) {
|
||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||
char subuf[64];
|
||||
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||
mqtt->publish(subuf, 0, false, "short");
|
||||
@ -74,7 +74,7 @@ void handleSwitch(uint8_t b)
|
||||
}
|
||||
|
||||
// publish MQTT message
|
||||
if (WLED_MQTT_CONNECTED) {
|
||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||
char subuf[64];
|
||||
if (buttonType[b] == BTN_TYPE_PIR_SENSOR) sprintf_P(subuf, PSTR("%s/motion/%d"), mqttDeviceTopic, (int)b);
|
||||
else sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||
@ -96,7 +96,7 @@ void handleAnalog(uint8_t b)
|
||||
|
||||
if (buttonType[b] == BTN_TYPE_ANALOG_INVERTED) aRead = 255 - aRead;
|
||||
|
||||
// remove noise & reduce frequency of UI updates (3*13mV)
|
||||
// remove noise & reduce frequency of UI updates
|
||||
aRead &= 0xFC;
|
||||
|
||||
if (oldRead[b] == aRead) return; // no change in reading
|
||||
@ -199,7 +199,7 @@ void handleButton()
|
||||
else _setRandomColor(false,true);
|
||||
|
||||
// publish MQTT message
|
||||
if (WLED_MQTT_CONNECTED) {
|
||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||
char subuf[64];
|
||||
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||
mqtt->publish(subuf, 0, false, "long");
|
||||
@ -227,7 +227,7 @@ void handleButton()
|
||||
applyPreset(macroDoublePress[b]);
|
||||
|
||||
// publish MQTT message
|
||||
if (WLED_MQTT_CONNECTED) {
|
||||
if (buttonPublishMqtt && WLED_MQTT_CONNECTED) {
|
||||
char subuf[64];
|
||||
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
|
||||
mqtt->publish(subuf, 0, false, "double");
|
||||
|
@ -121,7 +121,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
if (lC > ledCount) ledCount = lC; // fix incorrect total length (honour analog setup)
|
||||
|
||||
// read multiple button configuration
|
||||
JsonArray hw_btn_ins = hw[F("btn")]["ins"];
|
||||
JsonObject btn_obj = hw["btn"];
|
||||
JsonArray hw_btn_ins = btn_obj[F("ins")];
|
||||
if (!hw_btn_ins.isNull()) {
|
||||
uint8_t s = 0;
|
||||
for (JsonObject btn : hw_btn_ins) {
|
||||
@ -133,7 +134,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
} else {
|
||||
btnPin[s] = -1;
|
||||
}
|
||||
JsonArray hw_btn_ins_0_macros = btn[F("macros")];
|
||||
JsonArray hw_btn_ins_0_macros = btn["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]);
|
||||
@ -158,7 +159,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
macroDoublePress[s] = 0;
|
||||
}
|
||||
}
|
||||
CJSON(touchThreshold,hw[F("btn")][F("tt")]);
|
||||
CJSON(touchThreshold,btn_obj[F("tt")]);
|
||||
CJSON(buttonPublishMqtt,btn_obj["mqtt"]);
|
||||
|
||||
int hw_ir_pin = hw["ir"]["pin"] | -2; // 4
|
||||
if (hw_ir_pin > -2) {
|
||||
@ -190,8 +192,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
CJSON(briMultiplier, light[F("scale-bri")]);
|
||||
CJSON(strip.paletteBlend, light[F("pal-mode")]);
|
||||
|
||||
float light_gc_bri = light[F("gc")]["bri"];
|
||||
float light_gc_col = light[F("gc")]["col"]; // 2.8
|
||||
float light_gc_bri = light["gc"]["bri"];
|
||||
float light_gc_col = light["gc"]["col"]; // 2.8
|
||||
if (light_gc_bri > 1.5) strip.gammaCorrectBri = true;
|
||||
else if (light_gc_bri > 0.5) strip.gammaCorrectBri = false;
|
||||
if (light_gc_col > 1.5) strip.gammaCorrectCol = true;
|
||||
@ -210,7 +212,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
if (nightlightDelayMinsDefault != prev) nightlightDelayMins = nightlightDelayMinsDefault;
|
||||
|
||||
CJSON(nightlightTargetBri, light_nl[F("tbri")]);
|
||||
CJSON(macroNl, light_nl[F("macro")]);
|
||||
CJSON(macroNl, light_nl["macro"]);
|
||||
|
||||
JsonObject def = doc[F("def")];
|
||||
CJSON(bootPreset, def[F("ps")]);
|
||||
@ -234,10 +236,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
prev = notifyDirectDefault;
|
||||
CJSON(notifyDirectDefault, if_sync_send[F("dir")]);
|
||||
if (notifyDirectDefault != prev) notifyDirect = notifyDirectDefault;
|
||||
CJSON(notifyButton, if_sync_send[F("btn")]);
|
||||
CJSON(notifyAlexa, if_sync_send[F("va")]);
|
||||
CJSON(notifyHue, if_sync_send[F("hue")]);
|
||||
CJSON(notifyMacro, if_sync_send[F("macro")]);
|
||||
CJSON(notifyButton, if_sync_send["btn"]);
|
||||
CJSON(notifyAlexa, if_sync_send["va"]);
|
||||
CJSON(notifyHue, if_sync_send["hue"]);
|
||||
CJSON(notifyMacro, if_sync_send["macro"]);
|
||||
CJSON(notifyTwice, if_sync_send[F("twice")]);
|
||||
|
||||
JsonObject if_nodes = interfaces["nodes"];
|
||||
@ -261,10 +263,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
CJSON(arlsDisableGammaCorrection, if_live[F("no-gc")]); // false
|
||||
CJSON(arlsOffset, if_live[F("offset")]); // 0
|
||||
|
||||
CJSON(alexaEnabled, interfaces[F("va")][F("alexa")]); // false
|
||||
CJSON(alexaEnabled, interfaces["va"][F("alexa")]); // false
|
||||
|
||||
CJSON(macroAlexaOn, interfaces[F("va")][F("macros")][0]);
|
||||
CJSON(macroAlexaOff, interfaces[F("va")][F("macros")][1]);
|
||||
CJSON(macroAlexaOn, interfaces["va"]["macros"][0]);
|
||||
CJSON(macroAlexaOff, interfaces["va"]["macros"][1]);
|
||||
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
const char* apikey = interfaces["blynk"][F("token")] | "Hidden";
|
||||
@ -291,7 +293,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
JsonObject if_hue = interfaces[F("hue")];
|
||||
JsonObject if_hue = interfaces["hue"];
|
||||
CJSON(huePollingEnabled, if_hue["en"]);
|
||||
CJSON(huePollLightId, if_hue["id"]);
|
||||
tdd = if_hue[F("iv")] | -1;
|
||||
@ -339,7 +341,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
CJSON(countdownHour, cntdwn_goal[3]);
|
||||
CJSON(countdownMin, cntdwn_goal[4]);
|
||||
CJSON(countdownSec, cntdwn_goal[5]);
|
||||
CJSON(macroCountdown, cntdwn[F("macro")]);
|
||||
CJSON(macroCountdown, cntdwn["macro"]);
|
||||
setCountdown();
|
||||
|
||||
JsonArray timers = tm["ins"];
|
||||
@ -349,7 +351,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
if (it<8 && timer[F("hour")]==255) it=8; // hour==255 -> sunrise/sunset
|
||||
CJSON(timerHours[it], timer[F("hour")]);
|
||||
CJSON(timerMinutes[it], timer["min"]);
|
||||
CJSON(timerMacro[it], timer[F("macro")]);
|
||||
CJSON(timerMacro[it], timer["macro"]);
|
||||
|
||||
byte dowPrev = timerWeekday[it];
|
||||
//note: act is currently only 0 or 1.
|
||||
@ -538,6 +540,7 @@ void serializeConfig() {
|
||||
hw_btn_ins_0_macros.add(macroDoublePress[i]);
|
||||
}
|
||||
hw_btn[F("tt")] = touchThreshold;
|
||||
hw_btn["mqtt"] = buttonPublishMqtt;
|
||||
|
||||
JsonObject hw_ir = hw.createNestedObject("ir");
|
||||
hw_ir["pin"] = irPin;
|
||||
@ -567,7 +570,7 @@ void serializeConfig() {
|
||||
light_nl[F("mode")] = nightlightMode;
|
||||
light_nl["dur"] = nightlightDelayMinsDefault;
|
||||
light_nl[F("tbri")] = nightlightTargetBri;
|
||||
light_nl[F("macro")] = macroNl;
|
||||
light_nl["macro"] = macroNl;
|
||||
|
||||
JsonObject def = doc.createNestedObject("def");
|
||||
def[F("ps")] = bootPreset;
|
||||
@ -587,10 +590,10 @@ void serializeConfig() {
|
||||
|
||||
JsonObject if_sync_send = if_sync.createNestedObject("send");
|
||||
if_sync_send[F("dir")] = notifyDirect;
|
||||
if_sync_send[F("btn")] = notifyButton;
|
||||
if_sync_send[F("va")] = notifyAlexa;
|
||||
if_sync_send[F("hue")] = notifyHue;
|
||||
if_sync_send[F("macro")] = notifyMacro;
|
||||
if_sync_send["btn"] = notifyButton;
|
||||
if_sync_send["va"] = notifyAlexa;
|
||||
if_sync_send["hue"] = notifyHue;
|
||||
if_sync_send["macro"] = notifyMacro;
|
||||
if_sync_send[F("twice")] = notifyTwice;
|
||||
|
||||
JsonObject if_nodes = interfaces.createNestedObject("nodes");
|
||||
@ -682,7 +685,7 @@ void serializeConfig() {
|
||||
JsonArray goal = cntdwn.createNestedArray(F("goal"));
|
||||
goal.add(countdownYear); goal.add(countdownMonth); goal.add(countdownDay);
|
||||
goal.add(countdownHour); goal.add(countdownMin); goal.add(countdownSec);
|
||||
cntdwn[F("macro")] = macroCountdown;
|
||||
cntdwn["macro"] = macroCountdown;
|
||||
|
||||
JsonArray timers_ins = timers.createNestedArray("ins");
|
||||
|
||||
@ -692,7 +695,7 @@ void serializeConfig() {
|
||||
timers_ins0["en"] = (timerWeekday[i] & 0x01);
|
||||
timers_ins0[F("hour")] = timerHours[i];
|
||||
timers_ins0["min"] = timerMinutes[i];
|
||||
timers_ins0[F("macro")] = timerMacro[i];
|
||||
timers_ins0["macro"] = timerMacro[i];
|
||||
timers_ins0[F("dow")] = timerWeekday[i] >> 1;
|
||||
}
|
||||
|
||||
@ -752,7 +755,7 @@ bool deserializeConfigSec() {
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
getStringFromJson(hueApiKey, interfaces[F("hue")][F("key")], 47);
|
||||
getStringFromJson(hueApiKey, interfaces["hue"][F("key")], 47);
|
||||
#endif
|
||||
|
||||
JsonObject ota = doc["ota"];
|
||||
|
@ -77,6 +77,7 @@
|
||||
#define NOTIFIER_CALL_MODE_PRESET_CYCLE 8
|
||||
#define NOTIFIER_CALL_MODE_BLYNK 9
|
||||
#define NOTIFIER_CALL_MODE_ALEXA 10
|
||||
#define NOTIFIER_CALL_MODE_WS_SEND 11 //special call mode, not for notifier, updates websocket only
|
||||
|
||||
//RGB to RGBW conversion mode
|
||||
#define RGBW_MODE_MANUAL_ONLY 0 //No automatic white channel calculation. Manual white channel slider
|
||||
@ -195,6 +196,14 @@
|
||||
#define SEG_OPTION_FREEZE 5 //Segment contents will not be refreshed
|
||||
#define SEG_OPTION_TRANSITIONAL 7
|
||||
|
||||
//Segment differs return byte
|
||||
#define SEG_DIFFERS_BRI 0x01
|
||||
#define SEG_DIFFERS_OPT 0x02
|
||||
#define SEG_DIFFERS_COL 0x04
|
||||
#define SEG_DIFFERS_FX 0x08
|
||||
#define SEG_DIFFERS_BOUNDS 0x10
|
||||
#define SEG_DIFFERS_GSO 0x20
|
||||
|
||||
//Playlist option byte
|
||||
#define PL_OPTION_SHUFFLE 0x01
|
||||
|
||||
|
@ -140,6 +140,10 @@ button {
|
||||
padding: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.segt TD.h {
|
||||
font-size: 13px;
|
||||
padding: 2px 0 0;
|
||||
}
|
||||
|
||||
.keytd {
|
||||
text-align: left;
|
||||
@ -573,6 +577,8 @@ input[type=range]::-moz-range-thumb {
|
||||
transition-duration: 0.5s;
|
||||
-webkit-backface-visibility: hidden;
|
||||
-webkit-transform:translate3d(0,0,0);
|
||||
overflow: clip;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
.btn-s {
|
||||
@ -595,9 +601,11 @@ input[type=range]::-moz-range-thumb {
|
||||
}
|
||||
.btn-xs, .btn-pl-del, .btn-pl-add {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
}
|
||||
.btn-pl-del, .btn-pl-add {
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#qcs-w {
|
||||
margin-top: 10px;
|
||||
@ -975,13 +983,13 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#selectPalette .lstI.selected {
|
||||
top: 80px;
|
||||
bottom: 0;
|
||||
#pallist .lstI.selected {
|
||||
top: 27px;
|
||||
bottom: -11px;
|
||||
}
|
||||
|
||||
#selectPalette .lstI.sticky {
|
||||
top: 40px;
|
||||
#pallist .lstI.sticky {
|
||||
top: -11px;
|
||||
}
|
||||
|
||||
.lstI.sticky {
|
||||
|
@ -102,11 +102,11 @@
|
||||
<p class="labels"><i class="icons sel-icon" onclick="tglHex()"></i> Color palette</p>
|
||||
<div class="il">
|
||||
<div class="staytop fnd">
|
||||
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'selectPalette')" onfocus="search(this)" />
|
||||
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'pallist')" onfocus="search(this)" />
|
||||
<span onclick="clean(this)" class="icons"></span>
|
||||
<div class="icons"><svg xmlns='http://www.w3.org/2000/svg' class='fndIcn'><circle cx='8' cy='8' r='6' /><line x1='12' y1='12' x2='24' y2='12' transform='rotate(45,12,12)' /></svg></div>
|
||||
</div>
|
||||
<div id="selectPalette" class="list">
|
||||
<div id="pallist" class="list">
|
||||
<div class="lstI" data-id="0">
|
||||
<label class="radio schkl">
|
||||
|
||||
|
@ -7,7 +7,7 @@ var selColors;
|
||||
var expanded = [false];
|
||||
var powered = [true];
|
||||
var nlDur = 60, nlTar = 0;
|
||||
var nlFade = false;
|
||||
var nlMode = false;
|
||||
var selectedFx = 0;
|
||||
var selectedPal = 0;
|
||||
var csel = 0;
|
||||
@ -16,19 +16,18 @@ var lastUpdate = 0;
|
||||
var segCount = 0, ledCount = 0, lowestUnused = 0, maxSeg = 0, lSeg = 0;
|
||||
var pcMode = false, pcModeA = false, lastw = 0;
|
||||
var tr = 7;
|
||||
var pNum = 0;
|
||||
var d = document;
|
||||
const ranges = RangeTouch.setup('input[type="range"]', {});
|
||||
var palettesData;
|
||||
var pJson = {}, eJson = {}, lJson = {};
|
||||
var pN = "", pI = 0;
|
||||
var pN = "", pI = 0, pNum = 0;
|
||||
var pmt = 1, pmtLS = 0, pmtLast = 0;
|
||||
var lastinfo = {};
|
||||
var ws, noWS = false;
|
||||
var cfg = {
|
||||
theme:{base:"dark", bg:{url:""}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}},
|
||||
comp :{colors:{picker: true, rgb: false, quick: true, hex: false}, labels:true, pcmbot:false, pid:true, seglen:false}
|
||||
};
|
||||
var myWS, noWS = false;
|
||||
|
||||
var cpick = new iro.ColorPicker("#picker", {
|
||||
width: 260,
|
||||
@ -257,16 +256,6 @@ function onLoad()
|
||||
sl.addEventListener('touchstart', toggleBubble);
|
||||
sl.addEventListener('touchend', toggleBubble);
|
||||
}
|
||||
|
||||
// Create UI update WS handler
|
||||
myWS = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws');
|
||||
// myWS.onopen = function () {
|
||||
// myWS.send("{'v':true}");
|
||||
// }
|
||||
myWS.onmessage = function(event) {
|
||||
var json = JSON.parse(event.data);
|
||||
if (handleJson(json.state)) updateUI(true);
|
||||
}
|
||||
}
|
||||
|
||||
function updateTablinks(tabI)
|
||||
@ -557,6 +546,7 @@ function loadInfo(callback=null)
|
||||
return res.json();
|
||||
})
|
||||
.then(json => {
|
||||
clearErrorToast();
|
||||
lastinfo = json;
|
||||
var name = json.name;
|
||||
gId('namelabel').innerHTML = name;
|
||||
@ -569,8 +559,11 @@ function loadInfo(callback=null)
|
||||
syncTglRecv = json.str;
|
||||
maxSeg = json.leds.maxseg;
|
||||
pmt = json.fs.pmt;
|
||||
gId('buttonNodes').style.display = showNodes() ? "block":"none";
|
||||
showNodes();
|
||||
populateInfo(json);
|
||||
// Create UI update WS handler
|
||||
if (!ws && json.ws > -1) setTimeout(makeWS,1000);
|
||||
reqsLegal = true;
|
||||
if (callback) callback();
|
||||
})
|
||||
.catch(function (error) {
|
||||
@ -813,10 +806,10 @@ function populatePalettes()
|
||||
"name": "Default",
|
||||
});
|
||||
|
||||
var paletteHtml = "";
|
||||
var html = "";
|
||||
for (let i = 0; i < palettes.length; i++) {
|
||||
let previewCss = genPalPrevCss(palettes[i].id);
|
||||
paletteHtml += generateListItemHtml(
|
||||
html += generateListItemHtml(
|
||||
'palette',
|
||||
palettes[i].id,
|
||||
palettes[i].name,
|
||||
@ -825,12 +818,12 @@ function populatePalettes()
|
||||
);
|
||||
}
|
||||
|
||||
gId('selectPalette').innerHTML=paletteHtml;
|
||||
gId('pallist').innerHTML=html;
|
||||
}
|
||||
|
||||
function redrawPalPrev()
|
||||
{
|
||||
let palettes = d.querySelectorAll('#selectPalette .lstI');
|
||||
let palettes = d.querySelectorAll('#pallist .lstI');
|
||||
for (let i = 0; i < palettes.length; i++) {
|
||||
let id = palettes[i].dataset.id;
|
||||
let lstPrev = palettes[i].querySelector('.lstIprev');
|
||||
@ -899,10 +892,10 @@ function genPalPrevCss(id)
|
||||
|
||||
function generateListItemHtml(listName, id, name, clickAction, extraHtml = '')
|
||||
{
|
||||
return `<div class="lstI${id==0?' sticky':''}" data-id="${id}">
|
||||
return `<div class="lstI${id==0?' sticky':''}" data-id="${id}" onClick="${clickAction}()">
|
||||
<label class="radio schkl">
|
||||
|
||||
<input type="radio" value="${id}" name="${listName}" onChange="${clickAction}()">
|
||||
<input type="radio" value="${id}" name="${listName}">
|
||||
<span class="radiomark schk"></span>
|
||||
</label>
|
||||
<div class="lstIcontent" onClick="${clickAction}(${id})">
|
||||
@ -918,8 +911,9 @@ function updateTrail(e, slidercol)
|
||||
{
|
||||
if (e==null) return;
|
||||
var max = e.hasAttribute('max') ? e.attributes.max.value : 255;
|
||||
var progress = e.value * 100 / max;
|
||||
progress = parseInt(progress);
|
||||
var perc = e.value * 100 / max;
|
||||
perc = parseInt(perc);
|
||||
if (perc < 50) perc += 2;
|
||||
var scol;
|
||||
switch (slidercol) {
|
||||
case 1: scol = "#f00"; break;
|
||||
@ -927,7 +921,7 @@ function updateTrail(e, slidercol)
|
||||
case 3: scol = "#00f"; break;
|
||||
default: scol = "var(--c-f)";
|
||||
}
|
||||
var val = `linear-gradient(90deg, ${scol} ${progress}%, var(--c-4) ${progress}%)`;
|
||||
var val = `linear-gradient(90deg, ${scol} ${perc}%, var(--c-4) ${perc}%)`;
|
||||
e.parentNode.getElementsByClassName('sliderdisplay')[0].style.background = val;
|
||||
var bubble = e.parentNode.parentNode.getElementsByTagName('output')[0];
|
||||
if (bubble) bubble.innerHTML = e.value;
|
||||
@ -993,12 +987,12 @@ function updatePA(scrollto=false)
|
||||
|
||||
function updateUI(scrollto=false)
|
||||
{
|
||||
noWS = (!myWS || myWS.readyState === WebSocket.CLOSED);
|
||||
noWS = (!ws || ws.readyState === WebSocket.CLOSED);
|
||||
|
||||
gId('buttonPower').className = (isOn) ? "active":"";
|
||||
gId('buttonNl').className = (nlA) ? "active":"";
|
||||
gId('buttonSync').className = (syncSend) ? "active":"";
|
||||
gId('buttonNodes').style.display = showNodes() ? "block":"none";
|
||||
showNodes();
|
||||
|
||||
updateSelectedPalette(scrollto);
|
||||
updateSelectedFx(scrollto);
|
||||
@ -1016,7 +1010,7 @@ function updateUI(scrollto=false)
|
||||
|
||||
function updateSelectedPalette(scrollto=false)
|
||||
{
|
||||
var parent = gId('selectPalette');
|
||||
var parent = gId('pallist');
|
||||
var selPaletteInput = parent.querySelector(`input[name="palette"][value="${selectedPal}"]`);
|
||||
if (selPaletteInput) selPaletteInput.checked = true;
|
||||
|
||||
@ -1030,7 +1024,6 @@ function updateSelectedPalette(scrollto=false)
|
||||
function updateSelectedFx(scrollto=false)
|
||||
{
|
||||
var parent = gId('fxlist');
|
||||
|
||||
var selEffectInput = parent.querySelector(`input[name="fx"][value="${selectedFx}"]`);
|
||||
if (selEffectInput) selEffectInput.checked = true;
|
||||
|
||||
@ -1055,7 +1048,34 @@ function cmpP(a, b)
|
||||
return a[1].n.localeCompare(b[1].n,undefined, {numeric: true});
|
||||
}
|
||||
|
||||
function handleJson(s)
|
||||
function makeWS() {
|
||||
if (ws) return;
|
||||
ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws');
|
||||
ws.onmessage = function(event) {
|
||||
clearTimeout(jsonTimeout);
|
||||
jsonTimeout = null;
|
||||
clearErrorToast();
|
||||
gId('connind').style.backgroundColor = "#079";
|
||||
var json = JSON.parse(event.data);
|
||||
var info = json.info;
|
||||
if (info) {
|
||||
lastinfo = info;
|
||||
showNodes();
|
||||
if (isInfo) {
|
||||
populateInfo(info);
|
||||
}
|
||||
}
|
||||
var s = json.state ? json.state : json;
|
||||
displayRover(info, s);
|
||||
readState(s);
|
||||
};
|
||||
ws.onclose = function(event) {
|
||||
gId('connind').style.backgroundColor = "#831";
|
||||
ws = null;
|
||||
}
|
||||
}
|
||||
|
||||
function readState(s,command=false)
|
||||
{
|
||||
if (!s) return false;
|
||||
|
||||
@ -1076,7 +1096,11 @@ function handleJson(s)
|
||||
if(s.seg[i].sel) {selc = ind; break;} ind++;
|
||||
}
|
||||
var i=s.seg[selc];
|
||||
if (!i) return false; // no segments!
|
||||
if (!i) {
|
||||
showToast('No Segments!', true);
|
||||
updateUI();
|
||||
return;
|
||||
}
|
||||
|
||||
selColors = i.col;
|
||||
var cd = gId('csl').children;
|
||||
@ -1104,21 +1128,37 @@ function handleJson(s)
|
||||
gId('sliderSpeed').value = i.sx;
|
||||
gId('sliderIntensity').value = i.ix;
|
||||
|
||||
if (s.error && s.error != 0) {
|
||||
var errstr = "";
|
||||
switch (s.error) {
|
||||
case 10:
|
||||
errstr = "Could not mount filesystem!";
|
||||
break;
|
||||
case 11:
|
||||
errstr = "Not enough space to save preset!";
|
||||
break;
|
||||
case 12:
|
||||
errstr = "Preset not found.";
|
||||
break;
|
||||
case 19:
|
||||
errstr = "A filesystem error has occured.";
|
||||
break;
|
||||
}
|
||||
showToast('Error ' + s.error + ": " + errstr, true);
|
||||
}
|
||||
|
||||
selectedPal = i.pal;
|
||||
selectedFx = i.fx;
|
||||
|
||||
//if (!gId('fxlist').querySelector(`input[name="fx"][value="${i.fx}"]`)) location.reload(); //effect list is gone (e.g. if restoring tab). Reload.
|
||||
|
||||
displayRover(lastinfo, s);
|
||||
clearErrorToast();
|
||||
|
||||
return true;
|
||||
updateUI(true);
|
||||
}
|
||||
|
||||
var jsonTimeout;
|
||||
var reqsLegal = false;
|
||||
|
||||
function requestJson(command, rinfo = true, verbose = true, callback = null)
|
||||
{
|
||||
gId('connind').style.backgroundColor = "#a90";
|
||||
if (command && !reqsLegal) return; //stop post requests from chrome onchange event on page restore
|
||||
lastUpdate = new Date();
|
||||
if (!jsonTimeout) jsonTimeout = setTimeout(showErrorToast, 3000);
|
||||
var req = null;
|
||||
@ -1131,6 +1171,12 @@ function requestJson(command, rinfo = true, verbose = true, callback = null)
|
||||
command.time = Math.floor(Date.now() / 1000);
|
||||
req = JSON.stringify(command);
|
||||
}
|
||||
|
||||
if ((command || rinfo) && ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(req?req:'{"v":true}');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
method: type,
|
||||
headers: {
|
||||
@ -1153,24 +1199,8 @@ function requestJson(command, rinfo = true, verbose = true, callback = null)
|
||||
return;
|
||||
}
|
||||
var s = json.state ? json.state : json;
|
||||
if (!handleJson(s)) {
|
||||
showToast('No Segments!', true);
|
||||
updateUI(false);
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
|
||||
if (s.error && s.error != 0) {
|
||||
var errstr = "";
|
||||
switch (s.error) {
|
||||
case 10: errstr = "Could not mount filesystem!"; break;
|
||||
case 11: errstr = "Not enough space to save preset!"; break;
|
||||
case 12: errstr = "The requested preset does not exist."; break;
|
||||
case 19: errstr = "A filesystem error has occured."; break;
|
||||
}
|
||||
showToast('Error ' + s.error + ": " + errstr, true);
|
||||
}
|
||||
updateUI(true);
|
||||
readState(s);
|
||||
reqsLegal = true;
|
||||
if (callback) callback();
|
||||
})
|
||||
.catch(function (error) {
|
||||
@ -1191,8 +1221,12 @@ function togglePower()
|
||||
function toggleNl()
|
||||
{
|
||||
nlA = !nlA;
|
||||
if (nlA) showToast(`Timer active. Your light will turn ${nlTar > 0 ? "on":"off"} ${nlFade ? "over":"after"} ${nlDur} minutes.`);
|
||||
else showToast('Timer deactivated.');
|
||||
if (nlA)
|
||||
{
|
||||
showToast(`Timer active. Your light will turn ${nlTar > 0 ? "on":"off"} ${nlMode ? "over":"after"} ${nlDur} minutes.`);
|
||||
} else {
|
||||
showToast('Timer deactivated.');
|
||||
}
|
||||
var obj = {"nl": {"on": nlA}};
|
||||
requestJson(obj, false);
|
||||
}
|
||||
@ -1291,7 +1325,7 @@ function makePlSel(arr) {
|
||||
function refreshPlE(p) {
|
||||
var plEDiv = gId(`ple${p}`);
|
||||
if (!plEDiv) return;
|
||||
var content = "";
|
||||
var content = "<div class=\"c\">Playlist entries</div>";
|
||||
for (var i = 0; i < plJson[p].ps.length; i++) {
|
||||
content += makePlEntry(p,i);
|
||||
}
|
||||
@ -1408,7 +1442,7 @@ ${plSelContent}
|
||||
<div class="c">Save to ID <input class="noslide" id="p${i}id" type="number" oninput="checkUsed(${i})" max=250 min=1 value=${(i>0)?i:getLowestUnusedP()}></div>
|
||||
<div class="c">
|
||||
<button class="btn btn-i btn-p" onclick="saveP(${i},${pl})"><i class="icons btn-icon"></i>Save</button>
|
||||
${(i>0)?'<button class="btn btn-i btn-pl-del" id="p'+i+'del" onclick="delP('+i+')"><i class="icons btn-icon"></i>':'<button class="btn btn-p" onclick="resetPUtil()">Cancel'}</button>
|
||||
${(i>0)?'<button class="btn btn-i btn-pl-del" id="p'+i+'del" onclick="delP('+i+')"><i class="icons btn-icon"></i>Delete':'<button class="btn btn-p" onclick="resetPUtil()">Cancel'}</button>
|
||||
</div>
|
||||
<div class="pwarn ${(i>0)?"bp":""} c" id="p${i}warn"></div>
|
||||
${(i>0)? ('<div class="h">ID ' +i+ '</div>'):""}`;
|
||||
@ -1432,6 +1466,11 @@ function makePlEntry(p,i) {
|
||||
</td>
|
||||
<td><button class="btn btn-i btn-pl-add" onclick="addPl(${p},${i})"><i class="icons btn-icon"></i></button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="h">Duration</td>
|
||||
<td class="h">Transition</td>
|
||||
<td class="h">#${i+1}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%"><input class="noslide segn" type="number" placeholder="Duration" max=6553.0 min=0.2 step=0.1 oninput="pleDur(${p},${i},this)" value="${plJson[p].dur[i]/10.0}">s</td>
|
||||
<td width="40%"><input class="noslide segn" type="number" placeholder="Transition" max=65.0 min=0.0 step=0.1 oninput="pleTr(${p},${i},this)" value="${plJson[p].transition[i]/10.0}">s</td>
|
||||
@ -1555,14 +1594,15 @@ function setX(ind = null)
|
||||
function setPalette(paletteId = null)
|
||||
{
|
||||
if (paletteId === null) {
|
||||
paletteId = parseInt(d.querySelector('#selectPalette input[name="palette"]:checked').value);
|
||||
paletteId = parseInt(d.querySelector('#pallist input[name="palette"]:checked').value);
|
||||
} else {
|
||||
d.querySelector(`#selectPalette input[name="palette"][value="${paletteId}`).checked = true;
|
||||
d.querySelector(`#pallist input[name="palette"][value="${paletteId}`).checked = true;
|
||||
}
|
||||
var selElement = d.querySelector('#selectPalette .selected');
|
||||
if (selElement) selElement.classList.remove('selected');
|
||||
|
||||
d.querySelector(`#selectPalette .lstI[data-id="${paletteId}"]`).classList.add('selected');
|
||||
var selElement = d.querySelector('#pallist .selected');
|
||||
if (selElement) {
|
||||
selElement.classList.remove('selected')
|
||||
}
|
||||
d.querySelector(`#pallist .lstI[data-id="${paletteId}"]`).classList.add('selected');
|
||||
var obj = {"seg": {"pal": paletteId}};
|
||||
requestJson(obj, false, noWS);
|
||||
}
|
||||
@ -2026,13 +2066,13 @@ function move(e)
|
||||
}
|
||||
|
||||
function showNodes() {
|
||||
return (lastinfo.ndc > 0 && (w > 797 || (w > 539 && w < 720)));
|
||||
gId('buttonNodes').style.display = (lastinfo.ndc > 0 && (w > 797 || (w > 539 && w < 720))) ? "block":"none";
|
||||
}
|
||||
|
||||
function size()
|
||||
{
|
||||
w = window.innerWidth;
|
||||
gId('buttonNodes').style.display = showNodes() ? "block":"none";
|
||||
showNodes();
|
||||
var h = gId('top').clientHeight;
|
||||
sCol('--th', h + "px");
|
||||
sCol('--bh', gId('bot').clientHeight + "px");
|
||||
|
@ -92,7 +92,6 @@
|
||||
}
|
||||
//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 (type > 29) return len*20; //RGBW
|
||||
@ -154,7 +153,7 @@
|
||||
}
|
||||
// gId("ew"+n).onclick = (type > 31 && type < 48) ? (function(){return false}) : (function(){}); // prevent change for analog
|
||||
// isRGBW |= gId("ew"+n).checked;
|
||||
isRGBW |= (type == 30 || type == 31 || type == 44 || type == 45); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||
isRGBW |= (type == 30 || type == 31 || (type > 40 && type < 46 && type != 43)); // RGBW checkbox, TYPE_xxxx values from const.h
|
||||
gId("dig"+n).style.display = (type > 31 && type < 48) ? "none":"inline"; // hide reverse, skip 1st & count for analog
|
||||
gId("psd"+n).innerHTML = (type > 31 && type < 48) ? "Index:":"Start:"; // change analog start description
|
||||
}
|
||||
@ -240,6 +239,8 @@
|
||||
function lastEnd(i) {
|
||||
if (i<1) return 0;
|
||||
v = parseInt(d.getElementsByName("LS"+(i-1))[0].value) + parseInt(d.getElementsByName("LC"+(i-1))[0].value);
|
||||
var type = parseInt(d.getElementsByName("LT"+(i-1))[0].value);
|
||||
if (type > 31 && type < 48) v = 1; //PWM busses
|
||||
if (isNaN(v)) return 0;
|
||||
return v;
|
||||
}
|
||||
@ -288,9 +289,9 @@ Color Order:
|
||||
<span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="33" class="s" onchange="UI()"/>
|
||||
<span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="33" class="s" 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)}" readonly required />
|
||||
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" class="l" min="0" max="8191" value="${lastEnd(i)}" readonly required />
|
||||
<div id="dig${i}" style="display:inline">
|
||||
Count: <input type="number" name="LC${i}" min="0" max="${maxPB}" value="1" required oninput="UI()" /><br>
|
||||
Count: <input type="number" name="LC${i}" class="l" min="0" max="${maxPB}" value="1" required oninput="UI()" /><br>
|
||||
Reverse (rotated 180°): <input type="checkbox" name="CV${i}">
|
||||
Skip 1<sup>st</sup> LED: <input id="sl${i}" type="checkbox" name="SL${i}"><br>
|
||||
</div>
|
||||
@ -358,7 +359,7 @@ Reverse (rotated 180°): <input type="checkbox" name="CV${i}">
|
||||
<br>
|
||||
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
|
||||
<div id="abl">
|
||||
Maximum Current: <input name="MA" type="number" min="250" max="65000" oninput="UI()" required> mA<br>
|
||||
Maximum Current: <input name="MA" type="number" class="l" min="250" max="65000" oninput="UI()" required> mA<br>
|
||||
<div id="ampwarning" style="color: orange; display: none;">
|
||||
⚠ Your power supply provides high current.<br>
|
||||
To improve the safety of your setup,<br>
|
||||
@ -393,37 +394,36 @@ Reverse (rotated 180°): <input type="checkbox" name="CV${i}">
|
||||
<div id="btns"></div>
|
||||
Touch threshold: <input type="number" min="0" max="100" name="TT" required><br>
|
||||
IR GPIO: <input type="number" min="-1" max="40" name="IR" onchange="UI()" class="s"><select name="IT" onchange="UI()">
|
||||
<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>
|
||||
<option value="8">JSON remote</option>
|
||||
<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>
|
||||
<option value=8>JSON remote</option>
|
||||
</select><span style="cursor: pointer;" onclick="off('IR')"> ×</span><br>
|
||||
<div id="json" style="display:none;">JSON file: <input type="file" name="data" accept=".json"> <input type="button" value="Upload" onclick="uploadFile('/ir.json');"><br></div>
|
||||
<div id="toast"></div>
|
||||
<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()" class="s"> invert <input type="checkbox" name="RM"><span style="cursor: pointer;" onclick="off('RL')"> ×</span><br>
|
||||
Relay pin: <input type="number" min="-1" max="33" name="RL" onchange="UI()" class="s"> invert <input type="checkbox" name="RM"><span style="cursor: pointer;" onclick="off('RL')"> ×</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>
|
||||
Default brightness: <input name="CA" type="number" class="m" min="0" max="255" required> (0-255)<br><br>
|
||||
Apply preset <input name="BP" type="number" class="m" min="0" max="250" required> at boot (0 uses defaults)
|
||||
<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> %
|
||||
Brightness factor: <input name="BF" type="number" class="m" 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>
|
||||
Transition Time: <input name="TD" type="number" class="xl" min="0" max="65500"> 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>
|
||||
Default Duration: <input name="TL" type="number" class="m" min="1" max="255" required> min<br>
|
||||
Default Target brightness: <input name="TB" type="number" class="m" min="0" max="255" required><br>
|
||||
Mode:
|
||||
<select name="TW">
|
||||
<option value="0">Wait and set</option>
|
||||
|
@ -87,6 +87,7 @@ Password: <input type="password" name="MQPASS" maxlength="64"><br>
|
||||
Client ID: <input name="MQCID" maxlength="40"><br>
|
||||
Device Topic: <input name="MD" maxlength="32"><br>
|
||||
Group Topic: <input name="MG" maxlength="32"><br>
|
||||
Publish on button press: <input type="checkbox" name="BM"><br>
|
||||
<i>Reboot required to apply changes. </i><a href="https://github.com/Aircoookie/WLED/wiki/MQTT" target="_blank">MQTT info</a>
|
||||
<h3>Philips Hue</h3>
|
||||
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
|
||||
|
@ -54,16 +54,16 @@ input[type="number"].xl {
|
||||
width: 85px;
|
||||
}
|
||||
input[type="number"].l {
|
||||
width: 60px;
|
||||
width: 63px;
|
||||
}
|
||||
input[type="number"].m {
|
||||
width: 55px;
|
||||
width: 56px;
|
||||
}
|
||||
input[type="number"].s {
|
||||
width: 42px;
|
||||
width: 49px;
|
||||
}
|
||||
input[type="number"].xs {
|
||||
width: 35px;
|
||||
width: 42px;
|
||||
}
|
||||
select {
|
||||
margin: 2px;
|
||||
|
File diff suppressed because one or more lines are too long
4413
wled00/html_ui.h
4413
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -161,7 +161,7 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
||||
hueColormode = 1;
|
||||
} else //hs mode
|
||||
{
|
||||
hueHue = root[F("hue")];
|
||||
hueHue = root["hue"];
|
||||
hueSat = root[F("sat")];
|
||||
hueColormode = 2;
|
||||
}
|
||||
|
285
wled00/json.cpp
285
wled00/json.cpp
@ -9,11 +9,14 @@
|
||||
void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
{
|
||||
byte id = elem["id"] | it;
|
||||
if (id < strip.getMaxSegments())
|
||||
{
|
||||
WS2812FX::Segment& seg = strip.getSegment(id);
|
||||
uint16_t start = elem[F("start")] | seg.start;
|
||||
int stop = elem["stop"] | -1;
|
||||
if (id >= strip.getMaxSegments()) return;
|
||||
|
||||
WS2812FX::Segment& seg = strip.getSegment(id);
|
||||
//WS2812FX::Segment prev;
|
||||
//prev = seg; //make a backup so we can tell if something changed
|
||||
|
||||
uint16_t start = elem[F("start")] | seg.start;
|
||||
int stop = elem["stop"] | -1;
|
||||
|
||||
if (elem["n"]) {
|
||||
// name field exists
|
||||
@ -38,64 +41,64 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
}
|
||||
}
|
||||
|
||||
if (stop < 0) {
|
||||
uint16_t len = elem[F("len")];
|
||||
stop = (len > 0) ? start + len : seg.stop;
|
||||
}
|
||||
uint16_t grp = elem[F("grp")] | seg.grouping;
|
||||
uint16_t spc = elem[F("spc")] | seg.spacing;
|
||||
strip.setSegment(id, start, stop, grp, spc);
|
||||
seg.offset = elem[F("of")] | seg.offset;
|
||||
if (stop > start && seg.offset > stop - start -1) seg.offset = stop - start -1;
|
||||
if (stop < 0) {
|
||||
uint16_t len = elem[F("len")];
|
||||
stop = (len > 0) ? start + len : seg.stop;
|
||||
}
|
||||
uint16_t grp = elem[F("grp")] | seg.grouping;
|
||||
uint16_t spc = elem[F("spc")] | seg.spacing;
|
||||
strip.setSegment(id, start, stop, grp, spc);
|
||||
seg.offset = elem[F("of")] | seg.offset;
|
||||
if (stop > start && seg.offset > stop - start -1) seg.offset = stop - start -1;
|
||||
|
||||
int segbri = elem["bri"] | -1;
|
||||
if (segbri == 0) {
|
||||
seg.setOption(SEG_OPTION_ON, 0, id);
|
||||
} else if (segbri > 0) {
|
||||
seg.setOpacity(segbri, id);
|
||||
seg.setOption(SEG_OPTION_ON, 1, id);
|
||||
}
|
||||
int segbri = elem["bri"] | -1;
|
||||
if (segbri == 0) {
|
||||
seg.setOption(SEG_OPTION_ON, 0, id);
|
||||
} else if (segbri > 0) {
|
||||
seg.setOpacity(segbri, id);
|
||||
seg.setOption(SEG_OPTION_ON, 1, id);
|
||||
}
|
||||
|
||||
seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON), id);
|
||||
seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON), id);
|
||||
|
||||
JsonArray colarr = elem["col"];
|
||||
if (!colarr.isNull())
|
||||
JsonArray colarr = elem["col"];
|
||||
if (!colarr.isNull())
|
||||
{
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
{
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
{
|
||||
int rgbw[] = {0,0,0,0};
|
||||
bool colValid = false;
|
||||
if (colarr[i].is<unsigned long>()) {
|
||||
// unsigned long RGBW (@blazoncek v2 experimental API implementation)
|
||||
uint32_t colX = colarr[i];
|
||||
rgbw[0] = (colX >> 16) & 0xFF;
|
||||
rgbw[1] = (colX >> 8) & 0xFF;
|
||||
rgbw[2] = (colX ) & 0xFF;
|
||||
rgbw[3] = (colX >> 24) & 0xFF;
|
||||
colValid = true;
|
||||
} else {
|
||||
JsonArray colX = colarr[i];
|
||||
if (colX.isNull()) {
|
||||
byte brgbw[] = {0,0,0,0};
|
||||
const char* hexCol = colarr[i];
|
||||
if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400
|
||||
int kelvin = colarr[i] | -1;
|
||||
if (kelvin < 0) continue;
|
||||
if (kelvin == 0) seg.setColor(i, 0, id);
|
||||
if (kelvin > 0) colorKtoRGB(kelvin, brgbw);
|
||||
colValid = true;
|
||||
} else { //HEX string, e.g. "FFAA00"
|
||||
colValid = colorFromHexString(brgbw, hexCol);
|
||||
}
|
||||
for (uint8_t c = 0; c < 4; c++) rgbw[c] = brgbw[c];
|
||||
} else { //Array of ints (RGB or RGBW color), e.g. [255,160,0]
|
||||
byte sz = colX.size();
|
||||
if (sz == 0) continue; //do nothing on empty array
|
||||
byte cp = copyArray(colX, rgbw, 4);
|
||||
if (cp == 1 && rgbw[0] == 0)
|
||||
seg.setColor(i, 0, id);
|
||||
int rgbw[] = {0,0,0,0};
|
||||
bool colValid = false;
|
||||
if (colarr[i].is<unsigned long>()) {
|
||||
// unsigned long RGBW (@blazoncek v2 experimental API implementation)
|
||||
uint32_t colX = colarr[i];
|
||||
rgbw[0] = (colX >> 16) & 0xFF;
|
||||
rgbw[1] = (colX >> 8) & 0xFF;
|
||||
rgbw[2] = (colX ) & 0xFF;
|
||||
rgbw[3] = (colX >> 24) & 0xFF;
|
||||
colValid = true;
|
||||
} else {
|
||||
JsonArray colX = colarr[i];
|
||||
if (colX.isNull()) {
|
||||
byte brgbw[] = {0,0,0,0};
|
||||
const char* hexCol = colarr[i];
|
||||
if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400
|
||||
int kelvin = colarr[i] | -1;
|
||||
if (kelvin < 0) continue;
|
||||
if (kelvin == 0) seg.setColor(i, 0, id);
|
||||
if (kelvin > 0) colorKtoRGB(kelvin, brgbw);
|
||||
colValid = true;
|
||||
} else { //HEX string, e.g. "FFAA00"
|
||||
colValid = colorFromHexString(brgbw, hexCol);
|
||||
}
|
||||
for (uint8_t c = 0; c < 4; c++) rgbw[c] = brgbw[c];
|
||||
} else { //Array of ints (RGB or RGBW color), e.g. [255,160,0]
|
||||
byte sz = colX.size();
|
||||
if (sz == 0) continue; //do nothing on empty array
|
||||
|
||||
byte cp = copyArray(colX, rgbw, 4);
|
||||
if (cp == 1 && rgbw[0] == 0)
|
||||
seg.setColor(i, 0, id);
|
||||
colValid = true;
|
||||
}
|
||||
|
||||
if (!colValid) continue;
|
||||
@ -109,90 +112,90 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lx parser
|
||||
#ifdef WLED_ENABLE_LOXONE
|
||||
int lx = elem[F("lx")] | -1;
|
||||
if (lx > 0) {
|
||||
parseLxJson(lx, id, false);
|
||||
}
|
||||
int ly = elem[F("ly")] | -1;
|
||||
if (ly > 0) {
|
||||
parseLxJson(ly, id, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
//if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
|
||||
seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED));
|
||||
seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
|
||||
seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR ));
|
||||
|
||||
//temporary, strip object gets updated via colorUpdated()
|
||||
if (id == strip.getMainSegmentId()) {
|
||||
byte effectPrev = effectCurrent;
|
||||
effectCurrent = elem[F("fx")] | effectCurrent;
|
||||
if (!presetId && effectCurrent != effectPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
|
||||
effectSpeed = elem[F("sx")] | effectSpeed;
|
||||
effectIntensity = elem[F("ix")] | effectIntensity;
|
||||
effectPalette = elem["pal"] | effectPalette;
|
||||
} else { //permanent
|
||||
byte fx = elem[F("fx")] | seg.mode;
|
||||
if (fx != seg.mode && fx < strip.getModeCount()) {
|
||||
strip.setMode(id, fx);
|
||||
if (!presetId) unloadPlaylist(); //stop playlist if active and FX changed manually
|
||||
}
|
||||
seg.speed = elem[F("sx")] | seg.speed;
|
||||
seg.intensity = elem[F("ix")] | seg.intensity;
|
||||
seg.palette = elem["pal"] | seg.palette;
|
||||
}
|
||||
|
||||
JsonArray iarr = elem[F("i")]; //set individual LEDs
|
||||
if (!iarr.isNull()) {
|
||||
strip.setPixelSegment(id);
|
||||
|
||||
//freeze and init to black
|
||||
if (!seg.getOption(SEG_OPTION_FREEZE)) {
|
||||
seg.setOption(SEG_OPTION_FREEZE, true);
|
||||
strip.fill(0);
|
||||
}
|
||||
|
||||
uint16_t start = 0, stop = 0;
|
||||
byte set = 0; //0 nothing set, 1 start set, 2 range set
|
||||
|
||||
for (uint16_t i = 0; i < iarr.size(); i++) {
|
||||
if(iarr[i].is<JsonInteger>()) {
|
||||
if (!set) {
|
||||
start = iarr[i];
|
||||
set = 1;
|
||||
} else {
|
||||
stop = iarr[i];
|
||||
set = 2;
|
||||
}
|
||||
} else {
|
||||
JsonArray icol = iarr[i];
|
||||
if (icol.isNull()) break;
|
||||
|
||||
byte sz = icol.size();
|
||||
if (sz == 0 || sz > 4) break;
|
||||
|
||||
int rgbw[] = {0,0,0,0};
|
||||
copyArray(icol, rgbw);
|
||||
|
||||
if (set < 2) stop = start + 1;
|
||||
for (uint16_t i = start; i < stop; i++) {
|
||||
strip.setPixelColor(i, rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
|
||||
}
|
||||
if (!set) start++;
|
||||
set = 0;
|
||||
}
|
||||
}
|
||||
strip.setPixelSegment(255);
|
||||
strip.trigger();
|
||||
} else { //return to regular effect
|
||||
seg.setOption(SEG_OPTION_FREEZE, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// lx parser
|
||||
#ifdef WLED_ENABLE_LOXONE
|
||||
int lx = elem[F("lx")] | -1;
|
||||
if (lx > 0) {
|
||||
parseLxJson(lx, id, false);
|
||||
}
|
||||
int ly = elem[F("ly")] | -1;
|
||||
if (ly > 0) {
|
||||
parseLxJson(ly, id, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
//if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
|
||||
seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED));
|
||||
seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
|
||||
seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR ));
|
||||
|
||||
//temporary, strip object gets updated via colorUpdated()
|
||||
if (id == strip.getMainSegmentId()) {
|
||||
byte effectPrev = effectCurrent;
|
||||
effectCurrent = elem[F("fx")] | effectCurrent;
|
||||
if (!presetId && effectCurrent != effectPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
|
||||
effectSpeed = elem[F("sx")] | effectSpeed;
|
||||
effectIntensity = elem[F("ix")] | effectIntensity;
|
||||
effectPalette = elem["pal"] | effectPalette;
|
||||
} else { //permanent
|
||||
byte fx = elem[F("fx")] | seg.mode;
|
||||
if (fx != seg.mode && fx < strip.getModeCount()) {
|
||||
strip.setMode(id, fx);
|
||||
if (!presetId) unloadPlaylist(); //stop playlist if active and FX changed manually
|
||||
}
|
||||
seg.speed = elem[F("sx")] | seg.speed;
|
||||
seg.intensity = elem[F("ix")] | seg.intensity;
|
||||
seg.palette = elem["pal"] | seg.palette;
|
||||
}
|
||||
|
||||
JsonArray iarr = elem[F("i")]; //set individual LEDs
|
||||
if (!iarr.isNull()) {
|
||||
strip.setPixelSegment(id);
|
||||
|
||||
//freeze and init to black
|
||||
if (!seg.getOption(SEG_OPTION_FREEZE)) {
|
||||
seg.setOption(SEG_OPTION_FREEZE, true);
|
||||
strip.fill(0);
|
||||
}
|
||||
|
||||
uint16_t start = 0, stop = 0;
|
||||
byte set = 0; //0 nothing set, 1 start set, 2 range set
|
||||
|
||||
for (uint16_t i = 0; i < iarr.size(); i++) {
|
||||
if(iarr[i].is<JsonInteger>()) {
|
||||
if (!set) {
|
||||
start = iarr[i];
|
||||
set = 1;
|
||||
} else {
|
||||
stop = iarr[i];
|
||||
set = 2;
|
||||
}
|
||||
} else {
|
||||
JsonArray icol = iarr[i];
|
||||
if (icol.isNull()) break;
|
||||
|
||||
byte sz = icol.size();
|
||||
if (sz == 0 || sz > 4) break;
|
||||
|
||||
int rgbw[] = {0,0,0,0};
|
||||
copyArray(icol, rgbw);
|
||||
|
||||
if (set < 2) stop = start + 1;
|
||||
for (uint16_t i = start; i < stop; i++) {
|
||||
strip.setPixelColor(i, rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
|
||||
}
|
||||
if (!set) start++;
|
||||
set = 0;
|
||||
}
|
||||
}
|
||||
strip.setPixelSegment(255);
|
||||
strip.trigger();
|
||||
} else { //return to regular effect
|
||||
seg.setOption(SEG_OPTION_FREEZE, false);
|
||||
}
|
||||
return; // seg.hasChanged(prev);
|
||||
}
|
||||
|
||||
bool deserializeState(JsonObject root, byte presetId)
|
||||
@ -337,6 +340,8 @@ bool deserializeState(JsonObject root, byte presetId)
|
||||
if (!playlist.isNull()) {
|
||||
loadPlaylist(playlist, presetId);
|
||||
noNotification = true; //do not notify both for this request and the first playlist entry
|
||||
} else {
|
||||
interfaceUpdateCallMode = NOTIFIER_CALL_MODE_WS_SEND;
|
||||
}
|
||||
|
||||
colorUpdated(noNotification ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
|
@ -115,7 +115,7 @@ void colorUpdated(int callMode)
|
||||
|
||||
notify(callMode);
|
||||
|
||||
//set flag to update blynk and mqtt
|
||||
//set flag to update blynk, ws and mqtt
|
||||
interfaceUpdateCallMode = callMode;
|
||||
} else {
|
||||
if (nightlightActive && !nightlightActiveOld &&
|
||||
@ -180,6 +180,11 @@ void colorUpdated(int callMode)
|
||||
void updateInterfaces(uint8_t callMode)
|
||||
{
|
||||
sendDataWs();
|
||||
if (callMode == NOTIFIER_CALL_MODE_WS_SEND) {
|
||||
lastInterfaceUpdate = millis();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
if (espalexaDevice != nullptr && callMode != NOTIFIER_CALL_MODE_ALEXA) {
|
||||
espalexaDevice->setValue(bri);
|
||||
|
@ -258,6 +258,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
strlcpy(mqttClientID, request->arg(F("MQCID")).c_str(), 41);
|
||||
strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), 33);
|
||||
strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), 33);
|
||||
buttonPublishMqtt = request->hasArg(F("BM"));
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
@ -550,13 +551,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
DEBUG_PRINTLN(req);
|
||||
|
||||
strip.applyToAllSelected = false;
|
||||
//snapshot to check if request changed values later, temporary.
|
||||
byte prevCol[4] = {col[0], col[1], col[2], col[3]};
|
||||
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
|
||||
byte prevEffect = effectCurrent;
|
||||
byte prevSpeed = effectSpeed;
|
||||
byte prevIntensity = effectIntensity;
|
||||
byte prevPalette = effectPalette;
|
||||
|
||||
//segment select (sets main segment)
|
||||
byte prevMain = strip.getMainSegmentId();
|
||||
@ -616,6 +610,14 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
pos = req.indexOf(F("PL="));
|
||||
if (pos > 0) applyPreset(getNumVal(&req, pos));
|
||||
|
||||
//snapshot to check if request changed values later, temporary.
|
||||
byte prevCol[4] = {col[0], col[1], col[2], col[3]};
|
||||
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
|
||||
byte prevEffect = effectCurrent;
|
||||
byte prevSpeed = effectSpeed;
|
||||
byte prevIntensity = effectIntensity;
|
||||
byte prevPalette = effectPalette;
|
||||
|
||||
//set brightness
|
||||
updateVal(&req, "&A=", &bri);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2107021
|
||||
#define VERSION 2107031
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@ -438,6 +438,7 @@ 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 buttonPublishMqtt _INIT(false);
|
||||
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});
|
||||
|
@ -40,7 +40,8 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
}
|
||||
verboseResponse = deserializeState(root);
|
||||
}
|
||||
if (verboseResponse || millis() - lastInterfaceUpdate < 1900) sendDataWs(client); //update if it takes longer than 100ms until next "broadcast"
|
||||
//update if it takes longer than 300ms until next "broadcast"
|
||||
if (verboseResponse && (millis() - lastInterfaceUpdate < 1700 || !interfaceUpdateCallMode)) sendDataWs(client);
|
||||
}
|
||||
} else {
|
||||
//message is comprised of multiple frames or the frame is split into multiple packets
|
||||
|
@ -474,6 +474,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappends('s',SET_F("MQCID"),mqttClientID);
|
||||
sappends('s',SET_F("MD"),mqttDeviceTopic);
|
||||
sappends('s',SET_F("MG"),mqttGroupTopic);
|
||||
sappend('c',SET_F("BM"),buttonPublishMqtt);
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
|
Loading…
Reference in New Issue
Block a user