Merge pull request #2547 from Aircoookie/sync-segbounds2

Sync segment bounds
This commit is contained in:
Christian Schwinne 2022-02-19 23:00:31 +01:00 committed by GitHub
commit 53abe36b83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1162 additions and 1208 deletions

View File

@ -61,7 +61,7 @@ arduino_core_develop = https://github.com/platformio/platform-espressif8266#deve
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
# Platform to use for ESP8266 # Platform to use for ESP8266
platform_wled_default = ${common.arduino_core_3_0_2} platform_wled_default = ${common.arduino_core_2_7_4}
# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization # We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7 platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
platformio/toolchain-xtensa @ ~2.40802.200502 platformio/toolchain-xtensa @ ~2.40802.200502

View File

@ -100,9 +100,9 @@ void userLoop() {
needRedraw = true; needRedraw = true;
} else if (knownBrightness != bri) { } else if (knownBrightness != bri) {
needRedraw = true; needRedraw = true;
} else if (knownMode != strip.getMode()) { } else if (knownMode != strip.getMainSegment().mode) {
needRedraw = true; needRedraw = true;
} else if (knownPalette != strip.getSegment(0).palette) { } else if (knownPalette != strip.getMainSegment().palette) {
needRedraw = true; needRedraw = true;
} }
@ -126,8 +126,8 @@ void userLoop() {
#endif #endif
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
knownBrightness = bri; knownBrightness = bri;
knownMode = strip.getMode(); knownMode = strip.getMainSegment().mode;
knownPalette = strip.getSegment(0).palette; knownPalette = strip.getMainSegment().palette;
u8x8.clear(); u8x8.clear();
u8x8.setFont(u8x8_font_chroma48medium8_r); u8x8.setFont(u8x8_font_chroma48medium8_r);

View File

@ -143,9 +143,9 @@ void userLoop() {
needRedraw = true; needRedraw = true;
} else if (knownBrightness != bri) { } else if (knownBrightness != bri) {
needRedraw = true; needRedraw = true;
} else if (knownMode != strip.getMode()) { } else if (knownMode != strip.getMainSegment().mode) {
needRedraw = true; needRedraw = true;
} else if (knownPalette != strip.getSegment(0).palette) { } else if (knownPalette != strip.getMainSegment().palette) {
needRedraw = true; needRedraw = true;
} }
@ -169,8 +169,8 @@ void userLoop() {
#endif #endif
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
knownBrightness = bri; knownBrightness = bri;
knownMode = strip.getMode(); knownMode = strip.getMainSegment().mode;
knownPalette = strip.getSegment(0).palette; knownPalette = strip.getMainSegment().palette;
u8x8.clear(); u8x8.clear();
u8x8.setFont(u8x8_font_chroma48medium8_r); u8x8.setFont(u8x8_font_chroma48medium8_r);

View File

@ -61,7 +61,7 @@ class PIRsensorSwitch : public Usermod {
private: private:
// PIR sensor pin // PIR sensor pin
const uint8_t PIRsensorPin = 13; // D7 on D1 mini const uint8_t PIRsensorPin = 13; // D7 on D1 mini
// notification mode for colorUpdated() // notification mode for stateUpdated()
const byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // CALL_MODE_DIRECT_CHANGE const byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // CALL_MODE_DIRECT_CHANGE
// 1 min delay before switch off after the sensor state goes LOW // 1 min delay before switch off after the sensor state goes LOW
uint32_t m_switchOffDelay = 60000; uint32_t m_switchOffDelay = 60000;
@ -127,7 +127,7 @@ class PIRsensorSwitch : public Usermod {
if (bri != briHighlight) { if (bri != briHighlight) {
bri = briHighlight; // set current highlight brightness to last set highlight brightness bri = briHighlight; // set current highlight brightness to last set highlight brightness
} }
colorUpdated(NotifyUpdateMode); stateUpdated(NotifyUpdateMode);
highlightActive = true; // flag highlight is on highlightActive = true; // flag highlight is on
} }
else { // **pir timer has elapsed** else { // **pir timer has elapsed**
@ -157,7 +157,7 @@ class PIRsensorSwitch : public Usermod {
} }
applyMacro(macroLongPress); // apply standby lighting without brightness applyMacro(macroLongPress); // apply standby lighting without brightness
} }
colorUpdated(NotifyUpdateMode); stateUpdated(NotifyUpdateMode);
highlightActive = false; // flag highlight is off highlightActive = false; // flag highlight is off
} }
} }

View File

@ -61,7 +61,7 @@ private:
bool savedState = false; bool savedState = false;
uint32_t offTimerStart = 0; // off timer start time uint32_t offTimerStart = 0; // off timer start time
byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // notification mode for colorUpdated(): CALL_MODE_NO_NOTIFY or CALL_MODE_DIRECT_CHANGE byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // notification mode for stateUpdated(): CALL_MODE_NO_NOTIFY or CALL_MODE_DIRECT_CHANGE
byte sensorPinState = LOW; // current PIR sensor pin state byte sensorPinState = LOW; // current PIR sensor pin state
bool initDone = false; // status of initialization bool initDone = false; // status of initialization
bool PIRtriggered = false; bool PIRtriggered = false;
@ -136,7 +136,7 @@ private:
// preset not assigned // preset not assigned
if (bri == 0) { if (bri == 0) {
bri = briLast; bri = briLast;
colorUpdated(NotifyUpdateMode); stateUpdated(NotifyUpdateMode);
} }
} else { } else {
if (m_offPreset) { if (m_offPreset) {
@ -159,7 +159,7 @@ private:
if (bri != 0) { if (bri != 0) {
briLast = bri; briLast = bri;
bri = 0; bri = 0;
colorUpdated(NotifyUpdateMode); stateUpdated(NotifyUpdateMode);
} }
} }
} }

View File

@ -118,11 +118,11 @@ class St7789DisplayUsermod : public Usermod {
{ {
needRedraw = true; needRedraw = true;
} }
else if (knownMode != strip.getMode()) else if (knownMode != strip.getMainSegment().mode)
{ {
needRedraw = true; needRedraw = true;
} }
else if (knownPalette != strip.getSegment(0).palette) else if (knownPalette != strip.getMainSegment().palette)
{ {
needRedraw = true; needRedraw = true;
} }
@ -148,8 +148,8 @@ class St7789DisplayUsermod : public Usermod {
#endif #endif
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
knownBrightness = bri; knownBrightness = bri;
knownMode = strip.getMode(); knownMode = strip.getMainSegment().mode;
knownPalette = strip.getSegment(0).palette; knownPalette = strip.getMainSegment().palette;
tft.fillScreen(TFT_BLACK); tft.fillScreen(TFT_BLACK);
tft.setTextSize(2); tft.setTextSize(2);

View File

@ -110,9 +110,9 @@ void userLoop() {
needRedraw = true; needRedraw = true;
} else if (knownBrightness != bri) { } else if (knownBrightness != bri) {
needRedraw = true; needRedraw = true;
} else if (knownMode != strip.getMode()) { } else if (knownMode != strip.getMainSegment().mode) {
needRedraw = true; needRedraw = true;
} else if (knownPalette != strip.getSegment(0).palette) { } else if (knownPalette != strip.getMainSegment().palette) {
needRedraw = true; needRedraw = true;
} }
@ -136,8 +136,8 @@ void userLoop() {
#endif #endif
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
knownBrightness = bri; knownBrightness = bri;
knownMode = strip.getMode(); knownMode = strip.getMainSegment().mode;
knownPalette = strip.getSegment(0).palette; knownPalette = strip.getMainSegment().palette;
tft.fillScreen(TFT_BLACK); tft.fillScreen(TFT_BLACK);
tft.setTextSize(2); tft.setTextSize(2);

View File

@ -106,7 +106,7 @@ class UsermodVL53L0XGestures : public Usermod {
// set brightness according to range // set brightness according to range
bri = (VL53L0X_MAX_RANGE_MM - max(range, VL53L0X_MIN_RANGE_OFFSET)) * 255 / (VL53L0X_MAX_RANGE_MM - VL53L0X_MIN_RANGE_OFFSET); bri = (VL53L0X_MAX_RANGE_MM - max(range, VL53L0X_MIN_RANGE_OFFSET)) * 255 / (VL53L0X_MAX_RANGE_MM - VL53L0X_MIN_RANGE_OFFSET);
DEBUG_PRINTF(F("new brightness: %d"), bri); DEBUG_PRINTF(F("new brightness: %d"), bri);
colorUpdated(1); stateUpdated(1);
} }
} else if (wasMotionBefore) { //released } else if (wasMotionBefore) { //released
long dur = millis() - motionStartTime; long dur = millis() - motionStartTime;

View File

@ -137,9 +137,9 @@ void userLoop() {
needRedraw = true; needRedraw = true;
} else if (knownBrightness != bri) { } else if (knownBrightness != bri) {
needRedraw = true; needRedraw = true;
} else if (knownMode != strip.getMode()) { } else if (knownMode != strip.getMainSegment().mode) {
needRedraw = true; needRedraw = true;
} else if (knownPalette != strip.getSegment(0).palette) { } else if (knownPalette != strip.getMainSegment().palette) {
needRedraw = true; needRedraw = true;
} }
@ -163,8 +163,8 @@ void userLoop() {
#endif #endif
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
knownBrightness = bri; knownBrightness = bri;
knownMode = strip.getMode(); knownMode = strip.getMainSegment().mode;
knownPalette = strip.getSegment(0).palette; knownPalette = strip.getMainSegment().palette;
u8x8.clear(); u8x8.clear();
u8x8.setFont(u8x8_font_chroma48medium8_r); u8x8.setFont(u8x8_font_chroma48medium8_r);

View File

@ -143,9 +143,9 @@ void userLoop() {
needRedraw = true; needRedraw = true;
} else if (knownBrightness != bri) { } else if (knownBrightness != bri) {
needRedraw = true; needRedraw = true;
} else if (knownMode != strip.getMode()) { } else if (knownMode != strip.getMainSegment().mode) {
needRedraw = true; needRedraw = true;
} else if (knownPalette != strip.getSegment(0).palette) { } else if (knownPalette != strip.getMainSegment().palette) {
needRedraw = true; needRedraw = true;
} }
@ -169,8 +169,8 @@ void userLoop() {
#endif #endif
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
knownBrightness = bri; knownBrightness = bri;
knownMode = strip.getMode(); knownMode = strip.getMainSegment().mode;
knownPalette = strip.getSegment(0).palette; knownPalette = strip.getMainSegment().palette;
u8x8.clear(); u8x8.clear();
u8x8.setFont(u8x8_font_chroma48medium8_r); u8x8.setFont(u8x8_font_chroma48medium8_r);

View File

@ -54,35 +54,27 @@ void userLoop()
switch (myKey) { switch (myKey) {
case '1': case '1':
applyPreset(1); applyPreset(1);
colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '2': case '2':
applyPreset(2); applyPreset(2);
colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '3': case '3':
applyPreset(3); applyPreset(3);
colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '4': case '4':
applyPreset(4); applyPreset(4);
colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '5': case '5':
applyPreset(5); applyPreset(5);
colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '6': case '6':
applyPreset(6); applyPreset(6);
colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case 'A': case 'A':
applyPreset(7); applyPreset(7);
colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case 'B': case 'B':
applyPreset(8); applyPreset(8);
colorUpdated(CALL_MODE_FX_CHANGED);
break; break;
case '7': case '7':

View File

@ -391,7 +391,7 @@ public:
uint16_t brightness = map(lux, 0, 1000, umSSDRBrightnessMin, umSSDRBrightnessMax); uint16_t brightness = map(lux, 0, 1000, umSSDRBrightnessMin, umSSDRBrightnessMax);
if (bri != brightness) { if (bri != brightness) {
bri = brightness; bri = brightness;
colorUpdated(1); stateUpdated(1);
} }
} }
umSSDRLastRefresh = millis(); umSSDRLastRefresh = millis();

View File

@ -111,7 +111,7 @@ class StairwayWipeUsermod : public Usermod {
transitionDelayTemp = 4000; //fade out slowly transitionDelayTemp = 4000; //fade out slowly
#endif #endif
bri = 0; bri = 0;
colorUpdated(CALL_MODE_NOTIFICATION); stateUpdated(CALL_MODE_NOTIFICATION);
wipeState = 0; wipeState = 0;
userVar0 = 0; userVar0 = 0;
previousUserVar0 = 0; previousUserVar0 = 0;

View File

@ -104,7 +104,7 @@ void turnOff()
transitionDelayTemp = 4000; //fade out slowly transitionDelayTemp = 4000; //fade out slowly
#endif #endif
bri = 0; bri = 0;
colorUpdated(CALL_MODE_NOTIFICATION); stateUpdated(CALL_MODE_NOTIFICATION);
wipeState = 0; wipeState = 0;
userVar0 = 0; userVar0 = 0;
previousUserVar0 = 0; previousUserVar0 = 0;

View File

@ -91,8 +91,8 @@ class AutoSaveUsermod : public Usermod {
knownBrightness = bri; knownBrightness = bri;
knownEffectSpeed = effectSpeed; knownEffectSpeed = effectSpeed;
knownEffectIntensity = effectIntensity; knownEffectIntensity = effectIntensity;
knownMode = strip.getMode(); knownMode = strip.getMainSegment().mode;
knownPalette = strip.getSegment(0).palette; knownPalette = strip.getMainSegment().palette;
} }
// gets called every time WiFi is (re-)connected. Initialize own network // gets called every time WiFi is (re-)connected. Initialize own network
@ -106,8 +106,8 @@ class AutoSaveUsermod : public Usermod {
if (!autoSaveAfterSec || !enabled || strip.isUpdating() || currentPreset>0) return; // setting 0 as autosave seconds disables autosave if (!autoSaveAfterSec || !enabled || strip.isUpdating() || currentPreset>0) return; // setting 0 as autosave seconds disables autosave
unsigned long now = millis(); unsigned long now = millis();
uint8_t currentMode = strip.getMode(); uint8_t currentMode = strip.getMainSegment().mode;
uint8_t currentPalette = strip.getSegment(0).palette; uint8_t currentPalette = strip.getMainSegment().palette;
unsigned long wouldAutoSaveAfter = now + autoSaveAfterSec*1000; unsigned long wouldAutoSaveAfter = now + autoSaveAfterSec*1000;
if (knownBrightness != bri) { if (knownBrightness != bri) {

View File

@ -349,8 +349,8 @@ class FourLineDisplayUsermod : public Usermod {
(knownBrightness != bri) || (knownBrightness != bri) ||
(knownEffectSpeed != effectSpeed) || (knownEffectSpeed != effectSpeed) ||
(knownEffectIntensity != effectIntensity) || (knownEffectIntensity != effectIntensity) ||
(knownMode != strip.getMode()) || (knownMode != strip.getMainSegment().mode) ||
(knownPalette != strip.getSegment(0).palette)) { (knownPalette != strip.getMainSegment().palette)) {
knownHour = 99; // force time update knownHour = 99; // force time update
lastRedraw = now; // update lastRedraw marker lastRedraw = now; // update lastRedraw marker
} else if (sleepMode && !displayTurnedOff && ((now - lastRedraw)/1000)%5 == 0) { } else if (sleepMode && !displayTurnedOff && ((now - lastRedraw)/1000)%5 == 0) {
@ -398,8 +398,8 @@ class FourLineDisplayUsermod : public Usermod {
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID(); knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
knownIp = apActive ? IPAddress(4, 3, 2, 1) : Network.localIP(); knownIp = apActive ? IPAddress(4, 3, 2, 1) : Network.localIP();
knownBrightness = bri; knownBrightness = bri;
knownMode = strip.getMode(); knownMode = strip.getMainSegment().mode;
knownPalette = strip.getSegment(0).palette; knownPalette = strip.getMainSegment().palette;
knownEffectSpeed = effectSpeed; knownEffectSpeed = effectSpeed;
knownEffectIntensity = effectIntensity; knownEffectIntensity = effectIntensity;

View File

@ -290,12 +290,8 @@ public:
} }
void lampUdated() { void lampUdated() {
bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette); colorUpdated(CALL_MODE_BUTTON);
updateInterfaces(CALL_MODE_BUTTON);
//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(CALL_MODE_DIRECT_CHANGE);
updateInterfaces(CALL_MODE_DIRECT_CHANGE);
} }
void changeBrightness(bool increase) { void changeBrightness(bool increase) {

View File

@ -466,12 +466,11 @@ public:
} }
void lampUdated() { void lampUdated() {
//bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette);
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification) //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 // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
setValuesFromMainSeg(); //to make transition work on main segment //setValuesFromMainSeg(); //to make transition work on main segment (should no longer be required)
colorUpdated(CALL_MODE_DIRECT_CHANGE); stateUpdated(CALL_MODE_BUTTON);
updateInterfaces(CALL_MODE_DIRECT_CHANGE); updateInterfaces(CALL_MODE_BUTTON);
} }
void changeBrightness(bool increase) { void changeBrightness(bool increase) {

View File

@ -347,7 +347,8 @@ class WS2812FX {
if (intensity != b.intensity) d |= SEG_DIFFERS_FX; if (intensity != b.intensity) d |= SEG_DIFFERS_FX;
if (palette != b.palette) d |= SEG_DIFFERS_FX; if (palette != b.palette) d |= SEG_DIFFERS_FX;
if ((options & 0b00101111) != (b.options & 0b00101111)) d |= SEG_DIFFERS_OPT; if ((options & 0b00101110) != (b.options & 0b00101110)) d |= SEG_DIFFERS_OPT;
if ((options & 0x01) != (b.options & 0x01)) d |= SEG_DIFFERS_SEL;
for (uint8_t i = 0; i < NUM_COLORS; i++) for (uint8_t i = 0; i < NUM_COLORS; i++)
{ {
if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL; if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;
@ -649,6 +650,7 @@ class WS2812FX {
calcGammaTable(float), calcGammaTable(float),
trigger(void), trigger(void),
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0, uint16_t offset = UINT16_MAX), setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0, uint16_t offset = UINT16_MAX),
setMainSegmentId(uint8_t n),
restartRuntime(), restartRuntime(),
resetSegments(), resetSegments(),
makeAutoSegments(), makeAutoSegments(),
@ -662,27 +664,21 @@ class WS2812FX {
bool bool
gammaCorrectBri = false, gammaCorrectBri = false,
gammaCorrectCol = true, gammaCorrectCol = true,
applyToAllSelected = true,
setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p),
checkSegmentAlignment(void), checkSegmentAlignment(void),
hasCCTBus(void), hasCCTBus(void),
// return true if the strip is being sent pixel updates // return true if the strip is being sent pixel updates
isUpdating(void); isUpdating(void);
uint8_t uint8_t
mainSegment = 0,
paletteFade = 0, paletteFade = 0,
paletteBlend = 0, paletteBlend = 0,
milliampsPerLed = 55, milliampsPerLed = 55,
cctBlending = 0, cctBlending = 0,
getBrightness(void), getBrightness(void),
getMode(void),
getSpeed(void),
getModeCount(void), getModeCount(void),
getPaletteCount(void), getPaletteCount(void),
getMaxSegments(void), getMaxSegments(void),
getActiveSegmentsNum(void), getActiveSegmentsNum(void),
//getFirstSelectedSegment(void),
getMainSegmentId(void), getMainSegmentId(void),
getTargetFps(void), getTargetFps(void),
setPixelSegment(uint8_t n), setPixelSegment(uint8_t n),
@ -714,11 +710,9 @@ class WS2812FX {
getPixelColor(uint16_t), getPixelColor(uint16_t),
getColor(void); getColor(void);
WS2812FX::Segment& WS2812FX::Segment
getSegment(uint8_t n); &getSegment(uint8_t n),
&getMainSegment(void);
WS2812FX::Segment_runtime
getSegmentRuntime(void);
WS2812FX::Segment* WS2812FX::Segment*
getSegments(void); getSegments(void);
@ -912,6 +906,8 @@ class WS2812FX {
uint8_t _segment_index = 0; uint8_t _segment_index = 0;
uint8_t _segment_index_palette_last = 99; uint8_t _segment_index_palette_last = 99;
uint8_t _mainSegment;
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 24 bytes per element segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 24 bytes per element
// start, stop, offset, speed, intensity, palette, mode, options, grouping, spacing, opacity (unused), color[] // start, stop, offset, speed, intensity, palette, mode, options, grouping, spacing, opacity (unused), color[]
{0, 7, 0, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}} {0, 7, 0, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}}

View File

@ -393,63 +393,20 @@ uint8_t WS2812FX::getPaletteCount()
return 13 + GRADIENT_PALETTE_COUNT; return 13 + GRADIENT_PALETTE_COUNT;
} }
//TODO effect transitions
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) {
Segment& seg = _segments[getMainSegmentId()];
uint8_t modePrev = seg.mode, speedPrev = seg.speed, intensityPrev = seg.intensity, palettePrev = seg.palette;
bool applied = false;
if (applyToAllSelected) {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isSelected())
{
_segments[i].speed = s;
_segments[i].intensity = in;
_segments[i].palette = p;
setMode(i, m);
applied = true;
}
}
}
if (!applyToAllSelected || !applied) {
seg.speed = s;
seg.intensity = in;
seg.palette = p;
setMode(mainSegment, m);
}
if (seg.mode != modePrev || seg.speed != speedPrev || seg.intensity != intensityPrev || seg.palette != palettePrev) return true;
return false;
}
void WS2812FX::setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w) { void WS2812FX::setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
setColor(slot, RGBW32(r, g, b, w)); setColor(slot, RGBW32(r, g, b, w));
} }
//applies to all active and selected segments
void WS2812FX::setColor(uint8_t slot, uint32_t c) { void WS2812FX::setColor(uint8_t slot, uint32_t c) {
if (slot >= NUM_COLORS) return; if (slot >= NUM_COLORS) return;
bool applied = false; for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (applyToAllSelected) { if (_segments[i].isActive() && _segments[i].isSelected()) {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) _segments[i].setColor(slot, c, i);
{
if (_segments[i].isSelected()) {
_segments[i].setColor(slot, c, i);
applied = true;
}
} }
} }
if (!applyToAllSelected || !applied) {
uint8_t mainseg = getMainSegmentId();
_segments[mainseg].setColor(slot, c, mainseg);
}
} }
void WS2812FX::setBrightness(uint8_t b) { void WS2812FX::setBrightness(uint8_t b) {
@ -466,14 +423,6 @@ void WS2812FX::setBrightness(uint8_t b) {
if (_segment_runtimes[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon if (_segment_runtimes[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon
} }
uint8_t WS2812FX::getMode(void) {
return _segments[getMainSegmentId()].mode;
}
uint8_t WS2812FX::getSpeed(void) {
return _segments[getMainSegmentId()].speed;
}
uint8_t WS2812FX::getBrightness(void) { uint8_t WS2812FX::getBrightness(void) {
return _brightness; return _brightness;
} }
@ -482,27 +431,33 @@ uint8_t WS2812FX::getMaxSegments(void) {
return MAX_NUM_SEGMENTS; return MAX_NUM_SEGMENTS;
} }
/*uint8_t WS2812FX::getFirstSelectedSegment(void) void WS2812FX::setMainSegmentId(uint8_t n) {
{ if (n >= MAX_NUM_SEGMENTS) return;
if (_segments[n].isActive() && _segments[n].isSelected()) {
_mainSegment = n; return;
}
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{ {
if (_segments[i].isActive() && _segments[i].isSelected()) return i; if (_segments[i].isActive() && _segments[i].isSelected()) {
_mainSegment = i; return;
}
} }
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) //if none selected, get first active //if none selected, use supplied n if active, or first active
if (_segments[n].isActive()) {
_mainSegment = n; return;
}
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{ {
if (_segments[i].isActive()) return i; if (_segments[i].isActive()) {
_mainSegment = i; return;
}
} }
return 0; _mainSegment = 0;
}*/ return;
}
uint8_t WS2812FX::getMainSegmentId(void) { uint8_t WS2812FX::getMainSegmentId(void) {
if (mainSegment >= MAX_NUM_SEGMENTS) return 0; return _mainSegment;
if (_segments[mainSegment].isActive()) return mainSegment;
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) //get first active
{
if (_segments[i].isActive()) return i;
}
return 0;
} }
uint8_t WS2812FX::getActiveSegmentsNum(void) { uint8_t WS2812FX::getActiveSegmentsNum(void) {
@ -539,8 +494,8 @@ WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) {
return _segments[id]; return _segments[id];
} }
WS2812FX::Segment_runtime WS2812FX::getSegmentRuntime(void) { WS2812FX::Segment& WS2812FX::getMainSegment(void) {
return SEGENV; return _segments[getMainSegmentId()];
} }
WS2812FX::Segment* WS2812FX::getSegments(void) { WS2812FX::Segment* WS2812FX::getSegments(void) {
@ -596,17 +551,8 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
delete[] seg.name; delete[] seg.name;
seg.name = nullptr; seg.name = nullptr;
} }
if (n == mainSegment) //if main segment is deleted, set first active as main segment //if main segment is deleted, set first selected/active as main segment
{ if (n == _mainSegment) setMainSegmentId(0);
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].isActive()) {
mainSegment = i;
return;
}
}
mainSegment = 0; //should not happen (always at least one active segment)
}
return; return;
} }
if (i1 < _length) seg.start = i1; if (i1 < _length) seg.start = i1;
@ -628,7 +574,7 @@ void WS2812FX::restartRuntime() {
void WS2812FX::resetSegments() { void WS2812FX::resetSegments() {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) if (_segments[i].name) delete[] _segments[i].name; for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) if (_segments[i].name) delete[] _segments[i].name;
mainSegment = 0; _mainSegment = 0;
memset(_segments, 0, sizeof(_segments)); memset(_segments, 0, sizeof(_segments));
//memset(_segment_runtimes, 0, sizeof(_segment_runtimes)); //memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
_segment_index = 0; _segment_index = 0;

View File

@ -44,7 +44,7 @@ void onAlexaChange(EspalexaDevice* dev)
if (bri == 0) if (bri == 0)
{ {
bri = briLast; bri = briLast;
colorUpdated(CALL_MODE_ALEXA); stateUpdated(CALL_MODE_ALEXA);
} }
} else { } else {
applyPreset(macroAlexaOn, CALL_MODE_ALEXA); applyPreset(macroAlexaOn, CALL_MODE_ALEXA);
@ -58,7 +58,7 @@ void onAlexaChange(EspalexaDevice* dev)
{ {
briLast = bri; briLast = bri;
bri = 0; bri = 0;
colorUpdated(CALL_MODE_ALEXA); stateUpdated(CALL_MODE_ALEXA);
} }
} else { } else {
applyPreset(macroAlexaOff, CALL_MODE_ALEXA); applyPreset(macroAlexaOff, CALL_MODE_ALEXA);
@ -67,7 +67,7 @@ void onAlexaChange(EspalexaDevice* dev)
} else if (m == EspalexaDeviceProperty::bri) } else if (m == EspalexaDeviceProperty::bri)
{ {
bri = espalexaDevice->getValue(); bri = espalexaDevice->getValue();
colorUpdated(CALL_MODE_ALEXA); stateUpdated(CALL_MODE_ALEXA);
} else //color } else //color
{ {
if (espalexaDevice->getColorMode() == EspalexaColorMode::ct) //shade of white if (espalexaDevice->getColorMode() == EspalexaColorMode::ct) //shade of white
@ -79,9 +79,7 @@ void onAlexaChange(EspalexaDevice* dev)
if (strip.hasCCTBus()) { if (strip.hasCCTBus()) {
uint8_t segid = strip.getMainSegmentId(); uint8_t segid = strip.getMainSegmentId();
WS2812FX::Segment& seg = strip.getSegment(segid); WS2812FX::Segment& seg = strip.getSegment(segid);
uint8_t cctPrev = seg.cct;
seg.setCCT(k, segid); seg.setCCT(k, segid);
if (seg.cct != cctPrev) effectChanged = true; //send UDP
col[0]= 0; col[1]= 0; col[2]= 0; col[3]= 255; col[0]= 0; col[1]= 0; col[2]= 0; col[3]= 255;
} else if (strip.hasWhiteChannel()) { } else if (strip.hasWhiteChannel()) {
switch (ct) { //these values empirically look good on RGBW switch (ct) { //these values empirically look good on RGBW

View File

@ -44,27 +44,27 @@ void updateBlynk()
BLYNK_WRITE(V0) BLYNK_WRITE(V0)
{ {
bri = param.asInt();//bri bri = param.asInt();//bri
colorUpdated(CALL_MODE_BLYNK); stateUpdated(CALL_MODE_BLYNK);
} }
BLYNK_WRITE(V1) BLYNK_WRITE(V1)
{ {
blHue = param.asInt();//hue blHue = param.asInt();//hue
colorHStoRGB(blHue*10,blSat,(false)? colSec:col); colorHStoRGB(blHue*10,blSat,col);
colorUpdated(CALL_MODE_BLYNK); colorUpdated(CALL_MODE_BLYNK);
} }
BLYNK_WRITE(V2) BLYNK_WRITE(V2)
{ {
blSat = param.asInt();//sat blSat = param.asInt();//sat
colorHStoRGB(blHue*10,blSat,(false)? colSec:col); colorHStoRGB(blHue*10,blSat,col);
colorUpdated(CALL_MODE_BLYNK); colorUpdated(CALL_MODE_BLYNK);
} }
BLYNK_WRITE(V3) BLYNK_WRITE(V3)
{ {
bool on = (param.asInt()>0); bool on = (param.asInt()>0);
if (!on != !bri) {toggleOnOff(); colorUpdated(CALL_MODE_BLYNK);} if (!on != !bri) {toggleOnOff(); stateUpdated(CALL_MODE_BLYNK);}
} }
BLYNK_WRITE(V4) BLYNK_WRITE(V4)

View File

@ -16,8 +16,8 @@ void shortPressAction(uint8_t b)
{ {
if (!macroButton[b]) { if (!macroButton[b]) {
switch (b) { switch (b) {
case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break; case 0: toggleOnOff(); stateUpdated(CALL_MODE_BUTTON); break;
case 1: ++effectCurrent %= strip.getModeCount(); effectChanged = true; colorUpdated(CALL_MODE_BUTTON); break; case 1: ++effectCurrent %= strip.getModeCount(); colorUpdated(CALL_MODE_BUTTON); break;
} }
} else { } else {
applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET); applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET);
@ -35,8 +35,8 @@ void longPressAction(uint8_t b)
{ {
if (!macroLongPress[b]) { if (!macroLongPress[b]) {
switch (b) { switch (b) {
case 0: _setRandomColor(false,true); break; case 0: setRandomColor(col); colorUpdated(CALL_MODE_BUTTON); break;
case 1: bri += 8; colorUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action case 1: bri += 8; stateUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action
} }
} else { } else {
applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET); applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET);
@ -55,7 +55,7 @@ void doublePressAction(uint8_t b)
if (!macroDoublePress[b]) { if (!macroDoublePress[b]) {
switch (b) { switch (b) {
//case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break; //instant short press on button 0 if no macro set //case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break; //instant short press on button 0 if no macro set
case 1: ++effectPalette %= strip.getPaletteCount(); effectChanged = true; colorUpdated(CALL_MODE_BUTTON); break; case 1: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break;
} }
} else { } else {
applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET); applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET);
@ -109,12 +109,12 @@ void handleSwitch(uint8_t b)
if (!buttonPressedBefore[b]) { // on -> off if (!buttonPressedBefore[b]) { // on -> off
if (macroButton[b]) applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET); if (macroButton[b]) applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET);
else { //turn on else { //turn on
if (!bri) {toggleOnOff(); colorUpdated(CALL_MODE_BUTTON);} if (!bri) {toggleOnOff(); stateUpdated(CALL_MODE_BUTTON);}
} }
} else { // off -> on } else { // off -> on
if (macroLongPress[b]) applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET); if (macroLongPress[b]) applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET);
else { //turn off else { //turn off
if (bri) {toggleOnOff(); colorUpdated(CALL_MODE_BUTTON);} if (bri) {toggleOnOff(); stateUpdated(CALL_MODE_BUTTON);}
} }
} }
@ -161,36 +161,17 @@ void handleAnalog(uint8_t b)
} else if (macroDoublePress[b] == 249) { } else if (macroDoublePress[b] == 249) {
// effect speed // effect speed
effectSpeed = aRead; 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) { } else if (macroDoublePress[b] == 248) {
// effect intensity // effect intensity
effectIntensity = aRead; 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) { } else if (macroDoublePress[b] == 247) {
// selected palette // selected palette
effectPalette = map(aRead, 0, 252, 0, strip.getPaletteCount()-1); 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) { } else if (macroDoublePress[b] == 200) {
// primary color, hue, full saturation // primary color, hue, full saturation
colorHStoRGB(aRead*256,255,col); colorHStoRGB(aRead*256,255,col);
} else { } else {
// otherwise use "double press" for segment selection // otherwise use "double press" for segment selection
//uint8_t mainSeg = strip.getMainSegmentId();
WS2812FX::Segment& seg = strip.getSegment(macroDoublePress[b]); WS2812FX::Segment& seg = strip.getSegment(macroDoublePress[b]);
if (aRead == 0) { if (aRead == 0) {
seg.setOption(SEG_OPTION_ON, 0); // off seg.setOption(SEG_OPTION_ON, 0); // off
@ -258,7 +239,7 @@ void handleButton()
if (b == 0 && dur > WLED_LONG_AP) { //long press on button 0 (when released) if (b == 0 && dur > WLED_LONG_AP) { //long press on button 0 (when released)
WLED::instance().initAP(true); WLED::instance().initAP(true);
} else if (!buttonLongPressed[b]) { //short press } else if (!buttonLongPressed[b]) { //short press
if (b == 0 && !macroDoublePress[b]) { //don't wait for double press on button 0 if no double press macro set if (b != 1 && !macroDoublePress[b]) { //don't wait for double press on buttons without a default action if no double press macro set
shortPressAction(b); shortPressAction(b);
} else { //double press if less than 350 ms between current press and previous short press release (buttonWaitTime!=0) } else { //double press if less than 350 ms between current press and previous short press release (buttonWaitTime!=0)
if (doublePress) { if (doublePress) {

View File

@ -261,6 +261,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(receiveNotificationEffects, if_sync_recv["fx"]); CJSON(receiveNotificationEffects, if_sync_recv["fx"]);
CJSON(receiveGroups, if_sync_recv["grp"]); CJSON(receiveGroups, if_sync_recv["grp"]);
CJSON(receiveSegmentOptions, if_sync_recv["seg"]); CJSON(receiveSegmentOptions, if_sync_recv["seg"]);
CJSON(receiveSegmentBounds, if_sync_recv["sb"]);
//! following line might be a problem if called after boot //! following line might be a problem if called after boot
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions); receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions);
@ -673,9 +674,10 @@ void serializeConfig() {
JsonObject if_sync_recv = if_sync.createNestedObject("recv"); JsonObject if_sync_recv = if_sync.createNestedObject("recv");
if_sync_recv["bri"] = receiveNotificationBrightness; if_sync_recv["bri"] = receiveNotificationBrightness;
if_sync_recv["col"] = receiveNotificationColor; if_sync_recv["col"] = receiveNotificationColor;
if_sync_recv["fx"] = receiveNotificationEffects; if_sync_recv["fx"] = receiveNotificationEffects;
if_sync_recv["grp"] = receiveGroups; if_sync_recv["grp"] = receiveGroups;
if_sync_recv["seg"] = receiveSegmentOptions; if_sync_recv["seg"] = receiveSegmentOptions;
if_sync_recv["sb"] = receiveSegmentBounds;
JsonObject if_sync_send = if_sync.createNestedObject("send"); JsonObject if_sync_send = if_sync.createNestedObject("send");
if_sync_send[F("dir")] = notifyDirect; if_sync_send[F("dir")] = notifyDirect;

View File

@ -4,6 +4,12 @@
* Color conversion methods * Color conversion methods
*/ */
void setRandomColor(byte* rgb)
{
lastRandomIndex = strip.get_random_wheel_index(lastRandomIndex);
colorHStoRGB(lastRandomIndex*256,255,rgb);
}
void colorFromUint32(uint32_t in, bool secondary) void colorFromUint32(uint32_t in, bool secondary)
{ {
byte *_col = secondary ? colSec : col; byte *_col = secondary ? colSec : col;

View File

@ -226,6 +226,7 @@
#define SEG_DIFFERS_FX 0x08 #define SEG_DIFFERS_FX 0x08
#define SEG_DIFFERS_BOUNDS 0x10 #define SEG_DIFFERS_BOUNDS 0x10
#define SEG_DIFFERS_GSO 0x20 #define SEG_DIFFERS_GSO 0x20
#define SEG_DIFFERS_SEL 0x80
//Playlist option byte //Playlist option byte
#define PL_OPTION_SHUFFLE 0x01 #define PL_OPTION_SHUFFLE 0x01
@ -344,4 +345,6 @@
#define DEFAULT_LED_COUNT 30 #define DEFAULT_LED_COUNT 30
#endif #endif
#define INTERFACE_UPDATE_COOLDOWN 2000 //time in ms to wait between websockets, alexa, and MQTT updates
#endif #endif

View File

@ -215,7 +215,7 @@ function onLoad() {
//TODO: do some parsing first //TODO: do some parsing first
}) })
.catch(function (error) { .catch(function (error) {
console.log("holidays.json does not contain array of holidays. Defaults loaded."); console.log("No array of holidays in holidays.json. Defaults loaded.");
}) })
.finally(function(){ .finally(function(){
loadBg(cfg.theme.bg.url); loadBg(cfg.theme.bg.url);
@ -280,6 +280,8 @@ function showToast(text, error = false) {
} }
function showErrorToast() { function showErrorToast() {
// if we received a timeout force WS reconnect
reconnectWS();
showToast('Connection to light failed!', true); showToast('Connection to light failed!', true);
} }
function clearErrorToast() { function clearErrorToast() {
@ -953,10 +955,17 @@ function cmpP(a, b) {
return a[1].n.localeCompare(b[1].n,undefined, {numeric: true}); return a[1].n.localeCompare(b[1].n,undefined, {numeric: true});
} }
//forces a WebSockets reconnect if timeout (error toast), or successful HTTP response to JSON request
function reconnectWS() {
if (ws) ws.close();
ws = null;
if (lastinfo && lastinfo.ws > -1) setTimeout(makeWS,500);
}
function makeWS() { function makeWS() {
if (ws) return; if (ws) return;
ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws'); ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws');
ws.binaryType = "arraybuffer"; ws.binaryType = "arraybuffer";
ws.onmessage = function(event) { ws.onmessage = function(event) {
if (event.data instanceof ArrayBuffer) return; //liveview packet if (event.data instanceof ArrayBuffer) return; //liveview packet
var json = JSON.parse(event.data); var json = JSON.parse(event.data);
@ -974,9 +983,16 @@ function makeWS() {
displayRover(info, s); displayRover(info, s);
readState(json.state); readState(json.state);
}; };
ws.onclose = function(event) { ws.onclose = (e)=>{
d.getElementById('connind').style.backgroundColor = "#831"; //if there is already a new web socket open, do not null ws
} if (ws && ws.readyState === WebSocket.OPEN) return;
d.getElementById('connind').style.backgroundColor = "#831";
ws = null;
}
ws.onopen = (e)=>{
reqsLegal = true;
}
} }
function readState(s,command=false) { function readState(s,command=false) {
@ -1128,6 +1144,7 @@ function requestJson(command, rinfo = true) {
return; return;
} }
var s = json; var s = json;
if (reqsLegal && !ws) reconnectWS();
if (!command || rinfo) { //we have info object if (!command || rinfo) { //we have info object
if (!rinfo) { //entire JSON (on load) if (!rinfo) { //entire JSON (on load)
@ -1143,7 +1160,7 @@ function requestJson(command, rinfo = true) {
}); });
},25); },25);
reqsLegal = true; reqsLegal = true;
} }
var info = json.info; var info = json.info;
@ -1176,7 +1193,7 @@ function requestJson(command, rinfo = true) {
displayRover(info, s); displayRover(info, s);
} }
readState(s,command); readState(s,command);
}) })
.catch(function (error) { .catch(function (error) {
showToast(error, true); showToast(error, true);
@ -1452,8 +1469,8 @@ function makePlEntry(p,i) {
} }
function makePlUtil() { function makePlUtil() {
if (pNum < 2) { if (pNum < 1) {
showToast("You need at least 2 presets to make a playlist!"); return; showToast("Please make a preset first!"); return;
} }
if (plJson[0].transition[0] < 0) plJson[0].transition[0] = tr; if (plJson[0].transition[0] < 0) plJson[0].transition[0] = tr;
d.getElementById('putil').innerHTML = `<div class="seg pres"> d.getElementById('putil').innerHTML = `<div class="seg pres">
@ -1507,7 +1524,7 @@ function rptSeg(s)
var rev = d.getElementById(`seg${s}rev`).checked; var rev = d.getElementById(`seg${s}rev`).checked;
var mi = d.getElementById(`seg${s}mi`).checked; var mi = d.getElementById(`seg${s}mi`).checked;
var sel = d.getElementById(`seg${s}sel`).checked; var sel = d.getElementById(`seg${s}sel`).checked;
var obj = {"seg": {"id": s, "n": name, "start": start, "stop": (cfg.comp.seglen?start:0)+stop, "rev": rev, "mi": mi, "on": !powered[s], "bri": parseInt(d.getElementById(`seg${s}bri`).value), "sel": sel}}; var obj = {"seg": {"id": s, "n": name, "start": start, "stop": (cfg.comp.seglen?start:0)+stop, "rev": rev, "mi": mi, "on": powered[s], "bri": parseInt(d.getElementById(`seg${s}bri`).value), "sel": sel}};
if (d.getElementById(`seg${s}grp`)) { if (d.getElementById(`seg${s}grp`)) {
var grp = parseInt(d.getElementById(`seg${s}grp`).value); var grp = parseInt(d.getElementById(`seg${s}grp`).value);
var spc = parseInt(d.getElementById(`seg${s}spc`).value); var spc = parseInt(d.getElementById(`seg${s}spc`).value);

View File

@ -83,7 +83,7 @@ UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required
</tr> </tr>
</table><br> </table><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>
<input type="checkbox" name="SO"> Segment options<br> <input type="checkbox" name="SO"> Segment options, <input type="checkbox" name="SG"> bounds<br>
Send notifications on direct change: <input type="checkbox" name="SD"><br> Send notifications on direct change: <input type="checkbox" name="SD"><br>
Send notifications on button press or IR: <input type="checkbox" name="SB"><br> Send notifications on button press or IR: <input type="checkbox" name="SB"><br>
Send Alexa notifications: <input type="checkbox" name="SA"><br> Send Alexa notifications: <input type="checkbox" name="SA"><br>

View File

@ -75,6 +75,8 @@ bool colorFromHexString(byte* rgb, const char* in);
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
uint16_t approximateKelvinFromRGB(uint32_t rgb); uint16_t approximateKelvinFromRGB(uint32_t rgb);
void setRandomColor(byte* rgb);
//dmx.cpp //dmx.cpp
void initDMX(); void initDMX();
void handleDMX(); void handleDMX();
@ -145,9 +147,10 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
void setValuesFromMainSeg(); void setValuesFromMainSeg();
void resetTimebase(); void resetTimebase();
void toggleOnOff(); void toggleOnOff();
void setAllLeds(); void applyBri();
void setLedsStandard(); void applyFinalBri();
void colorUpdated(int callMode); void colorUpdated(byte callMode);
void stateUpdated(byte callMode);
void updateInterfaces(uint8_t callMode); void updateInterfaces(uint8_t callMode);
void handleTransitions(); void handleTransitions();
void handleNightlight(); void handleNightlight();
@ -201,7 +204,6 @@ inline void saveTemporaryPreset() {savePreset(255, false);};
void deletePreset(byte index); void deletePreset(byte index);
//set.cpp //set.cpp
void _setRandomColor(bool _sec,bool fromButton=false);
bool isAsterisksOnly(const char* str, byte maxLen); bool isAsterisksOnly(const char* str, byte maxLen);
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage); void handleSettingsSet(AsyncWebServerRequest *request, byte subPage);
bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply=true); bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply=true);
@ -224,7 +226,6 @@ void sendSysInfoUDP();
//void sappend(char stype, const char* key, int val); //void sappend(char stype, const char* key, int val);
//void sappends(char stype, const char* key, char* val); //void sappends(char stype, const char* key, char* val);
//void prepareHostname(char* hostname); //void prepareHostname(char* hostname);
//void _setRandomColor(bool _sec, bool fromButton);
//bool isAsterisksOnly(const char* str, byte maxLen); //bool isAsterisksOnly(const char* str, byte maxLen);
bool requestJSONBufferLock(uint8_t module=255); bool requestJSONBufferLock(uint8_t module=255);
void releaseJSONBufferLock(); void releaseJSONBufferLock();

View File

@ -85,7 +85,7 @@ charset="utf-8"><meta name="theme-color" content="#222222"><title>
WLED Live Preview</title><style> WLED Live Preview</title><style>
body{margin:0}#canv{background:#000;filter:brightness(175%);width:100%;height:100%;position:absolute} body{margin:0}#canv{background:#000;filter:brightness(175%);width:100%;height:100%;position:absolute}
</style></head><body><div id="canv"><script> </style></head><body><div id="canv"><script>
function updatePreview(e){var n="linear-gradient(90deg,",t=e.length;for(i=2;i<t;i+=3)n+=`rgb(${e[i]},${e[i+1]},${e[i+2]})`,i<t-3&&(n+=",");n+=")",document.getElementById("canv").style.background=n}function getLiveJson(e){try{if(e.data instanceof ArrayBuffer||"[object ArrayBuffer]"===toString.call(e.data)){let e=new Uint8Array(event.data);if(76!=e[0])return;updatePreview(e)}}catch(e){console.error("Peek WS error:",e)}}var ws=top.window.ws;ws&&ws.readyState===WebSocket.OPEN?(console.info("Peek uses top WS"),ws.send("{'lv':true}")):(console.info("Peek WS opening"),(ws=new WebSocket("ws://"+document.location.host+"/ws")).onopen=function(){console.info("Peek WS open"),ws.send("{'lv':true}")}),ws.binaryType="arraybuffer",ws.addEventListener("message",getLiveJson) function updatePreview(e){var n="linear-gradient(90deg,",t=e.length;for(i=2;i<t;i+=3)n+=`rgb(${e[i]},${e[i+1]},${e[i+2]})`,i<t-3&&(n+=",");n+=")",document.getElementById("canv").style.background=n}function getLiveJson(e){try{if("[object ArrayBuffer]"===toString.call(e.data)){let e=new Uint8Array(event.data);if(76!=e[0])return;updatePreview(e)}}catch(e){console.error("Peek WS error:",e)}}var ws=top.window.ws;ws&&ws.readyState===WebSocket.OPEN?(console.info("Peek uses top WS"),ws.send("{'lv':true}")):(console.info("Peek WS opening"),(ws=new WebSocket("ws://"+document.location.host+"/ws")).onopen=function(){console.info("Peek WS open"),ws.send("{'lv':true}")}),ws.binaryType="arraybuffer",ws.addEventListener("message",getLiveJson)
</script></body></html>)====="; </script></body></html>)=====";

View File

@ -276,9 +276,10 @@ type="checkbox" id="R7" name="R7"></td><td><input type="checkbox" id="R8"
name="R8"></td></tr></table><br>Receive: <input type="checkbox" name="RB"> name="R8"></td></tr></table><br>Receive: <input type="checkbox" name="RB">
Brightness, <input type="checkbox" name="RC"> Color, and <input Brightness, <input type="checkbox" name="RC"> Color, and <input
type="checkbox" name="RX"> Effects<br><input type="checkbox" name="SO"> type="checkbox" name="RX"> Effects<br><input type="checkbox" name="SO">
Segment options<br>Send notifications on direct change: <input type="checkbox" Segment options, <input type="checkbox" name="SG"> bounds<br>
name="SD"><br>Send notifications on button press or IR: <input type="checkbox" Send notifications on direct change: <input type="checkbox" name="SD"><br>
name="SB"><br>Send Alexa notifications: <input type="checkbox" name="SA"><br> Send notifications on button press or IR: <input type="checkbox" name="SB"><br>
Send Alexa notifications: <input type="checkbox" name="SA"><br>
Send Philips Hue change notifications: <input type="checkbox" name="SH"><br> Send Philips Hue change notifications: <input type="checkbox" name="SH"><br>
Send Macro notifications: <input type="checkbox" name="SM"><br> Send Macro notifications: <input type="checkbox" name="SM"><br>
Send notifications twice: <input type="checkbox" name="S2"><br><i> Send notifications twice: <input type="checkbox" name="S2"><br><i>

File diff suppressed because it is too large Load Diff

View File

@ -27,8 +27,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
if (id >= strip.getMaxSegments()) return; if (id >= strip.getMaxSegments()) return;
WS2812FX::Segment& seg = strip.getSegment(id); WS2812FX::Segment& seg = strip.getSegment(id);
//WS2812FX::Segment prev; WS2812FX::Segment prev = seg; //make a backup so we can tell if something changed
//prev = seg; //make a backup so we can tell if something changed
uint16_t start = elem["start"] | seg.start; uint16_t start = elem["start"] | seg.start;
int stop = elem["stop"] | -1; int stop = elem["stop"] | -1;
@ -83,7 +82,6 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
uint16_t grp = elem["grp"] | seg.grouping; uint16_t grp = elem["grp"] | seg.grouping;
uint16_t spc = elem[F("spc")] | seg.spacing; uint16_t spc = elem[F("spc")] | seg.spacing;
uint16_t of = seg.offset; uint16_t of = seg.offset;
if (!(elem[F("spc")].isNull() && elem["grp"].isNull())) effectChanged = true; //send UDP
uint16_t len = 1; uint16_t len = 1;
if (stop > start) len = stop - start; if (stop > start) len = stop - start;
@ -110,9 +108,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
if (elem["frz"].is<const char*>() && elem["frz"].as<const char*>()[0] == 't') frz = !seg.getOption(SEG_OPTION_FREEZE); if (elem["frz"].is<const char*>() && elem["frz"].as<const char*>()[0] == 't') frz = !seg.getOption(SEG_OPTION_FREEZE);
seg.setOption(SEG_OPTION_FREEZE, frz, id); seg.setOption(SEG_OPTION_FREEZE, frz, id);
uint8_t cctPrev = seg.cct;
seg.setCCT(elem["cct"] | seg.cct, id); seg.setCCT(elem["cct"] | seg.cct, id);
if (seg.cct != cctPrev && id == strip.getMainSegmentId()) effectChanged = true; //send UDP
JsonArray colarr = elem["col"]; JsonArray colarr = elem["col"];
if (!colarr.isNull()) if (!colarr.isNull())
@ -166,26 +162,20 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
} }
#endif #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_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_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR )); seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR ));
if (!(elem[F("sel")].isNull() && elem["rev"].isNull() && elem["on"].isNull() && elem[F("mi")].isNull())) effectChanged = true; //send UDP
byte fx = seg.mode; byte fx = seg.mode;
byte fxPrev = fx;
if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value) if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value)
if (!presetId && currentPlaylist>=0) unloadPlaylist(); if (!presetId && currentPlaylist>=0) unloadPlaylist();
strip.setMode(id, fx); strip.setMode(id, fx);
if (!presetId && seg.mode != fxPrev) effectChanged = true; //send UDP
} }
byte prevSpd = seg.speed;
byte prevInt = seg.intensity; //getVal also supports inc/decrementing and random
byte prevPal = seg.palette; getVal(elem[F("sx")], &seg.speed, 0, 255);
if (getVal(elem[F("sx")], &seg.speed, 0, 255) && !presetId && prevSpd != seg.speed) effectChanged = true; //also supports inc/decrementing and random getVal(elem[F("ix")], &seg.intensity, 0, 255);
if (getVal(elem[F("ix")], &seg.intensity, 0, 255) && !presetId && prevInt != seg.intensity) effectChanged = true; //also supports inc/decrementing and random getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount());
if (getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount()) && !presetId && prevPal != seg.palette) effectChanged = true; //also supports inc/decrementing and random
JsonArray iarr = elem[F("i")]; //set individual LEDs JsonArray iarr = elem[F("i")]; //set individual LEDs
if (!iarr.isNull()) { if (!iarr.isNull()) {
@ -240,13 +230,14 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
} else if (!elem["frz"] && iarr.isNull()) { //return to regular effect } else if (!elem["frz"] && iarr.isNull()) { //return to regular effect
seg.setOption(SEG_OPTION_FREEZE, false); seg.setOption(SEG_OPTION_FREEZE, false);
} }
return; // seg.differs(prev); //send UDP if not in preset and something changed that is not just selection
if (!presetId && (seg.differs(prev) & 0x7F)) effectChanged = true;
return;
} }
// deserializes WLED state (fileDoc points to doc object if called from web server) // deserializes WLED state (fileDoc points to doc object if called from web server)
bool deserializeState(JsonObject root, byte callMode, byte presetId) bool deserializeState(JsonObject root, byte callMode, byte presetId)
{ {
strip.applyToAllSelected = false;
bool stateResponse = root[F("v")] | false; bool stateResponse = root[F("v")] | false;
getVal(root["bri"], &bri); getVal(root["bri"], &bri);
@ -307,9 +298,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
else realtimeTimeout = 0; //cancel realtime mode immediately else realtimeTimeout = 0; //cancel realtime mode immediately
} }
byte prevMain = strip.getMainSegmentId(); strip.setMainSegmentId(root[F("mainseg")] | strip.getMainSegmentId());
strip.mainSegment = root[F("mainseg")] | prevMain;
//if (strip.getMainSegmentId() != prevMain) setValuesFromMainSeg();
int it = 0; int it = 0;
JsonVariant segVar = root["seg"]; JsonVariant segVar = root["seg"];
@ -320,19 +309,17 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
if (id < 0) { if (id < 0) {
//apply all selected segments //apply all selected segments
bool didSet = false; bool didSet = false;
byte lowestActive = 99;
for (byte s = 0; s < strip.getMaxSegments(); s++) { for (byte s = 0; s < strip.getMaxSegments(); s++) {
WS2812FX::Segment &sg = strip.getSegment(s); WS2812FX::Segment &sg = strip.getSegment(s);
if (sg.isActive()) { if (sg.isActive()) {
if (lowestActive == 99) lowestActive = s;
if (sg.isSelected()) { if (sg.isSelected()) {
deserializeSegment(segVar, s, presetId); deserializeSegment(segVar, s, presetId);
didSet = true; didSet = true;
} }
} }
} }
//TODO: not sure if it is good idea to change first active but unselected segment //if none selected, apply to the main segment
if (!didSet && lowestActive < strip.getMaxSegments()) deserializeSegment(segVar, lowestActive, presetId); if (!didSet) deserializeSegment(segVar, strip.getMainSegmentId(), presetId);
} else { } else {
deserializeSegment(segVar, id, presetId); //apply only the segment with the specified ID deserializeSegment(segVar, id, presetId); //apply only the segment with the specified ID
} }
@ -344,7 +331,9 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
it++; it++;
} }
} }
setValuesFromMainSeg(); //to make transition work on main segment
//refresh main segment (ensure it is selected, if there are any selected segments)
strip.setMainSegmentId(strip.getMainSegmentId());
#ifndef WLED_DISABLE_CRONIXIE #ifndef WLED_DISABLE_CRONIXIE
if (root["nx"].is<const char*>()) { if (root["nx"].is<const char*>()) {
@ -391,7 +380,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
interfaceUpdateCallMode = CALL_MODE_WS_SEND; interfaceUpdateCallMode = CALL_MODE_WS_SEND;
} }
colorUpdated(callMode); stateUpdated(callMode);
return stateResponse; return stateResponse;
} }
@ -422,15 +411,10 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
for (uint8_t i = 0; i < 3; i++) for (uint8_t i = 0; i < 3; i++)
{ {
byte segcol[4]; byte* c = segcol; byte segcol[4]; byte* c = segcol;
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment segcol[0] = R(seg.colors[i]);
{ segcol[1] = G(seg.colors[i]);
c = (i == 0)? col:colSec; segcol[2] = B(seg.colors[i]);
} else { segcol[3] = W(seg.colors[i]);
segcol[0] = R(seg.colors[i]);
segcol[1] = G(seg.colors[i]);
segcol[2] = B(seg.colors[i]);
segcol[3] = W(seg.colors[i]);
}
char tmpcol[22]; char tmpcol[22];
sprintf_P(tmpcol, format, (unsigned)c[0], (unsigned)c[1], (unsigned)c[2], (unsigned)c[3]); sprintf_P(tmpcol, format, (unsigned)c[0], (unsigned)c[1], (unsigned)c[2], (unsigned)c[3]);
strcat(colstr, i<2 ? strcat(tmpcol, ",") : tmpcol); strcat(colstr, i<2 ? strcat(tmpcol, ",") : tmpcol);

View File

@ -5,7 +5,7 @@
*/ */
void setValuesFromMainSeg() void setValuesFromMainSeg()
{ {
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId()); WS2812FX::Segment& seg = strip.getMainSegment();
colorFromUint32(seg.colors[0]); colorFromUint32(seg.colors[0]);
colorFromUint32(seg.colors[1], true); colorFromUint32(seg.colors[1], true);
effectCurrent = seg.mode; effectCurrent = seg.mode;
@ -15,6 +15,33 @@ void setValuesFromMainSeg()
} }
//applies global legacy values (col, colSec, effectCurrent...)
void applyValuesToSelectedSegs()
{
//copy of main segment to tell if value was updated
WS2812FX::Segment mainsegPrev = strip.getMainSegment();
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i);
if (i != strip.getMainSegmentId() && (!seg.isActive() || !seg.isSelected())) continue;
if (effectSpeed != mainsegPrev.speed) {
seg.speed = effectSpeed; effectChanged = true;}
if (effectIntensity != mainsegPrev.intensity) {
seg.intensity = effectIntensity; effectChanged = true;}
if (effectPalette != mainsegPrev.palette) {
seg.palette = effectPalette; effectChanged = true;}
if (effectCurrent != mainsegPrev.mode) {
strip.setMode(i, effectCurrent); effectChanged = true;}
uint32_t col0 = RGBW32(col[0],col[1],col[2],col[3]);
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
if (col0 != mainsegPrev.colors[0]) {
seg.setColor(0, col0, i); colorChanged = true;}
if (col1 != mainsegPrev.colors[1]) {
seg.setColor(1, col1, i); colorChanged = true;}
}
}
void resetTimebase() void resetTimebase()
{ {
strip.timebase = 0 - millis(); strip.timebase = 0 - millis();
@ -43,9 +70,8 @@ byte scaledBri(byte in)
} }
void setAllLeds() { //applies global brightness
strip.setColor(0, RGBW32(col[0], col[1], col[2], col[3])); void applyBri() {
strip.setColor(1, RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]));
if (!realtimeMode || !arlsForceMaxBri) if (!realtimeMode || !arlsForceMaxBri)
{ {
strip.setBrightness(scaledBri(briT)); strip.setBrightness(scaledBri(briT));
@ -53,18 +79,20 @@ void setAllLeds() {
} }
void setLedsStandard() //applies global brightness and sets it as the "current" brightness (no transition)
{ void applyFinalBri() {
briOld = bri; briOld = bri;
briT = bri; briT = bri;
setAllLeds(); applyBri();
} }
void colorUpdated(int callMode) //called after every state changes, schedules interface updates, handles brightness transition and nightlight activation
{ //unlike colorUpdated(), does NOT apply any colors or FX to segments
void stateUpdated(byte callMode) {
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification) //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 11: ws send only 12: button preset // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa 11: ws send only 12: button preset
setValuesFromMainSeg();
if (bri != briOld || effectChanged || colorChanged) { if (bri != briOld || effectChanged || colorChanged) {
if (realtimeTimeout == UINT32_MAX) realtimeTimeout = 0; if (realtimeTimeout == UINT32_MAX) realtimeTimeout = 0;
@ -103,9 +131,7 @@ void colorUpdated(int callMode)
jsonTransitionOnce = false; jsonTransitionOnce = false;
strip.setTransition(transitionDelayTemp); strip.setTransition(transitionDelayTemp);
if (transitionDelayTemp == 0) { if (transitionDelayTemp == 0) {
//setLedsStandard(); applyFinalBri();
briOld = briT = bri;
if (!realtimeMode || !arlsForceMaxBri) strip.setBrightness(scaledBri(briT));
strip.trigger(); strip.trigger();
return; return;
} }
@ -119,9 +145,7 @@ void colorUpdated(int callMode)
transitionStartTime = millis(); transitionStartTime = millis();
} else { } else {
strip.setTransition(0); strip.setTransition(0);
//setLedsStandard(); applyFinalBri();
briOld = briT = bri;
if (!realtimeMode || !arlsForceMaxBri) strip.setBrightness(scaledBri(briT));
strip.trigger(); strip.trigger();
} }
} }
@ -150,7 +174,7 @@ void updateInterfaces(uint8_t callMode)
void handleTransitions() void handleTransitions()
{ {
//handle still pending interface update //handle still pending interface update
if (interfaceUpdateCallMode && millis() - lastInterfaceUpdate > 2000) if (interfaceUpdateCallMode && millis() - lastInterfaceUpdate > INTERFACE_UPDATE_COOLDOWN)
{ {
updateInterfaces(interfaceUpdateCallMode); updateInterfaces(interfaceUpdateCallMode);
interfaceUpdateCallMode = 0; //disable interfaceUpdateCallMode = 0; //disable
@ -165,18 +189,25 @@ void handleTransitions()
strip.setTransitionMode(false); strip.setTransitionMode(false);
transitionActive = false; transitionActive = false;
tperLast = 0; tperLast = 0;
setLedsStandard(); applyFinalBri();
return; return;
} }
if (tper - tperLast < 0.004) return; if (tper - tperLast < 0.004) return;
tperLast = tper; tperLast = tper;
briT = briOld +((bri - briOld )*tper); briT = briOld +((bri - briOld )*tper);
setAllLeds(); applyBri();
} }
} }
//legacy method, applies values from col, effectCurrent, ... to selected segments
void colorUpdated(byte callMode){
applyValuesToSelectedSegs();
stateUpdated(callMode);
}
void handleNightlight() void handleNightlight()
{ {
/* /*
@ -239,7 +270,7 @@ void handleNightlight()
effectSpeed = colNlT[1]; effectSpeed = colNlT[1];
effectPalette = colNlT[2]; effectPalette = colNlT[2];
toggleOnOff(); toggleOnOff();
setLedsStandard(); applyFinalBri();
} }
} }
#ifndef WLED_DISABLE_BLYNK #ifndef WLED_DISABLE_BLYNK

View File

@ -9,13 +9,13 @@
void parseMQTTBriPayload(char* payload) void parseMQTTBriPayload(char* payload)
{ {
if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; colorUpdated(1);} if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(1);}
else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); colorUpdated(1);} else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); stateUpdated(1);}
else { else {
uint8_t in = strtoul(payload, NULL, 10); uint8_t in = strtoul(payload, NULL, 10);
if (in == 0 && bri > 0) briLast = bri; if (in == 0 && bri > 0) briLast = bri;
bri = in; bri = in;
colorUpdated(CALL_MODE_DIRECT_CHANGE); stateUpdated(CALL_MODE_DIRECT_CHANGE);
} }
} }

View File

@ -3,19 +3,6 @@
/* /*
* Receives client input * Receives client input
*/ */
void _setRandomColor(bool _sec,bool fromButton)
{
lastRandomIndex = strip.get_random_wheel_index(lastRandomIndex);
if (_sec){
colorHStoRGB(lastRandomIndex*256,255,colSec);
} else {
colorHStoRGB(lastRandomIndex*256,255,col);
}
if (fromButton) colorUpdated(2);
}
bool isAsterisksOnly(const char* str, byte maxLen) bool isAsterisksOnly(const char* str, byte maxLen)
{ {
for (byte i = 0; i < maxLen; i++) { for (byte i = 0; i < maxLen; i++) {
@ -233,6 +220,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
receiveNotificationColor = request->hasArg(F("RC")); receiveNotificationColor = request->hasArg(F("RC"));
receiveNotificationEffects = request->hasArg(F("RX")); receiveNotificationEffects = request->hasArg(F("RX"));
receiveSegmentOptions = request->hasArg(F("SO")); receiveSegmentOptions = request->hasArg(F("SO"));
receiveSegmentBounds = request->hasArg(F("SG"));
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions); receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions);
notifyDirectDefault = request->hasArg(F("SD")); notifyDirectDefault = request->hasArg(F("SD"));
notifyDirect = notifyDirectDefault; notifyDirect = notifyDirectDefault;
@ -469,7 +457,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
JsonObject um = doc.createNestedObject("um"); JsonObject um = doc.createNestedObject("um");
size_t args = request->args(); size_t args = request->args();
uint j=0; uint16_t j=0;
for (size_t i=0; i<args; i++) { for (size_t i=0; i<args; i++) {
String name = request->argName(i); String name = request->argName(i);
String value = request->arg(i); String value = request->arg(i);
@ -615,31 +603,31 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
DEBUG_PRINT(F("API req: ")); DEBUG_PRINT(F("API req: "));
DEBUG_PRINTLN(req); DEBUG_PRINTLN(req);
strip.applyToAllSelected = true;
//segment select (sets main segment) //segment select (sets main segment)
byte prevMain = strip.getMainSegmentId(); byte prevMain = strip.getMainSegmentId();
pos = req.indexOf(F("SM=")); pos = req.indexOf(F("SM="));
if (pos > 0) { if (pos > 0) {
strip.mainSegment = getNumVal(&req, pos); strip.setMainSegmentId(getNumVal(&req, pos));
} }
byte selectedSeg = strip.getMainSegmentId(); byte selectedSeg = strip.getMainSegmentId();
if (selectedSeg != prevMain) setValuesFromMainSeg(); if (selectedSeg != prevMain) setValuesFromMainSeg();
//snapshot to check if request changed values later, temporary. //temporary values, do not write direcly to global values of only setting a single segment
byte prevCol[4] = {col[0], col[1], col[2], col[3]}; byte colIn[4] = {col[0], col[1], col[2], col[3]};
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]}; byte colInSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
byte prevEffect = effectCurrent; byte effectIn = effectCurrent;
byte prevSpeed = effectSpeed; byte speedIn = effectSpeed;
byte prevIntensity = effectIntensity; byte intensityIn = effectIntensity;
byte prevPalette = effectPalette; byte paletteIn = effectPalette;
bool singleSegment = false;
pos = req.indexOf(F("SS=")); pos = req.indexOf(F("SS="));
if (pos > 0) { if (pos > 0) {
byte t = getNumVal(&req, pos); byte t = getNumVal(&req, pos);
if (t < strip.getMaxSegments()) { if (t < strip.getMaxSegments()) {
selectedSeg = t; selectedSeg = t;
strip.applyToAllSelected = false; singleSegment = true;
} }
} }
@ -716,27 +704,24 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
//set brightness //set brightness
updateVal(&req, "&A=", &bri); updateVal(&req, "&A=", &bri);
bool col0Changed = false, col1Changed = false, col2Changed = false; bool col0Changed = false, col1Changed = false;
//set colors //set colors
updateVal(&req, "&R=", &col[0]); updateVal(&req, "&R=", &colIn[0]);
updateVal(&req, "&G=", &col[1]); updateVal(&req, "&G=", &colIn[1]);
updateVal(&req, "&B=", &col[2]); updateVal(&req, "&B=", &colIn[2]);
updateVal(&req, "&W=", &col[3]); updateVal(&req, "&W=", &colIn[3]);
for (byte i=0; i<4; i++) if (prevCol[i]!=col[i]) col0Changed = colorChanged = true;
if (col0Changed) selseg.setColor(0, RGBW32(col[0], col[1], col[2], col[3]), selectedSeg); updateVal(&req, "R2=", &colInSec[0]);
updateVal(&req, "R2=", &colSec[0]); updateVal(&req, "G2=", &colInSec[1]);
updateVal(&req, "G2=", &colSec[1]); updateVal(&req, "B2=", &colInSec[2]);
updateVal(&req, "B2=", &colSec[2]); updateVal(&req, "W2=", &colInSec[3]);
updateVal(&req, "W2=", &colSec[3]);
for (byte i=0; i<4; i++) if (prevColSec[i]!=colSec[i]) col1Changed = colorChanged = true;
if (col1Changed) selseg.setColor(1, RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]), selectedSeg);
#ifdef WLED_ENABLE_LOXONE #ifdef WLED_ENABLE_LOXONE
//lox parser //lox parser
pos = req.indexOf(F("LX=")); // Lox primary color pos = req.indexOf(F("LX=")); // Lox primary color
if (pos > 0) { if (pos > 0) {
int lxValue = getNumVal(&req, pos); int lxValue = getNumVal(&req, pos);
if (parseLx(lxValue, col)) { if (parseLx(lxValue, colIn)) {
bri = 255; bri = 255;
nightlightActive = false; //always disable nightlight when toggling nightlightActive = false; //always disable nightlight when toggling
} }
@ -744,7 +729,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("LY=")); // Lox secondary color pos = req.indexOf(F("LY=")); // Lox secondary color
if (pos > 0) { if (pos > 0) {
int lxValue = getNumVal(&req, pos); int lxValue = getNumVal(&req, pos);
if(parseLx(lxValue, colSec)) { if(parseLx(lxValue, colInSec)) {
bri = 255; bri = 255;
nightlightActive = false; //always disable nightlight when toggling nightlightActive = false; //always disable nightlight when toggling
} }
@ -761,51 +746,40 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
tempsat = getNumVal(&req, pos); tempsat = getNumVal(&req, pos);
} }
byte sec = req.indexOf(F("H2")); byte sec = req.indexOf(F("H2"));
colorHStoRGB(temphue, tempsat, (sec>0) ? colSec : col); colorHStoRGB(temphue, tempsat, (sec>0) ? colInSec : colIn);
if (sec>0) col1Changed = true;
else col0Changed = true;
colorChanged = true;
} }
//set white spectrum (kelvin) //set white spectrum (kelvin)
pos = req.indexOf(F("&K=")); pos = req.indexOf(F("&K="));
if (pos > 0) { if (pos > 0) {
byte sec = req.indexOf(F("K2")); byte sec = req.indexOf(F("K2"));
colorKtoRGB(getNumVal(&req, pos), (sec>0) ? colSec : col); colorKtoRGB(getNumVal(&req, pos), (sec>0) ? colInSec : colIn);
if (sec>0) col1Changed = true;
else col0Changed = true;
colorChanged = true;
} }
//set color from HEX or 32bit DEC //set color from HEX or 32bit DEC
byte tmpCol[4]; byte tmpCol[4];
pos = req.indexOf(F("CL=")); pos = req.indexOf(F("CL="));
if (pos > 0) { if (pos > 0) {
colorFromDecOrHexString(col, (char*)req.substring(pos + 3).c_str()); colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str());
selseg.setColor(0, RGBW32(col[0], col[1], col[2], col[3]), selectedSeg); // defined above (SS= or main)
col0Changed = colorChanged = true;
} }
pos = req.indexOf(F("C2=")); pos = req.indexOf(F("C2="));
if (pos > 0) { if (pos > 0) {
colorFromDecOrHexString(colSec, (char*)req.substring(pos + 3).c_str()); colorFromDecOrHexString(colInSec, (char*)req.substring(pos + 3).c_str());
selseg.setColor(1, RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]), selectedSeg); // defined above (SS= or main)
col1Changed = colorChanged = true;
} }
pos = req.indexOf(F("C3=")); pos = req.indexOf(F("C3="));
if (pos > 0) { if (pos > 0) {
colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str()); colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
selseg.setColor(2, RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]), selectedSeg); // defined above (SS= or main) uint32_t col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
col2Changed = colorChanged = true; selseg.setColor(2, col2, selectedSeg); // defined above (SS= or main)
colorChanged = true;
if (!singleSegment) strip.setColor(2, col2);
} }
//set to random hue SR=0->1st SR=1->2nd //set to random hue SR=0->1st SR=1->2nd
pos = req.indexOf(F("SR")); pos = req.indexOf(F("SR"));
if (pos > 0) { if (pos > 0) {
byte sec = getNumVal(&req, pos); byte sec = getNumVal(&req, pos);
_setRandomColor(sec); setRandomColor(sec? colInSec : colIn);
if (sec>0) col1Changed = true;
else col0Changed = true;
colorChanged = true;
} }
//swap 2nd & 1st //swap 2nd & 1st
@ -813,23 +787,41 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
if (pos > 0) { if (pos > 0) {
byte temp; byte temp;
for (uint8_t i=0; i<4; i++) { for (uint8_t i=0; i<4; i++) {
temp = col[i]; temp = colIn[i];
col[i] = colSec[i]; colIn[i] = colInSec[i];
colSec[i] = temp; colInSec[i] = temp;
} }
col0Changed = col1Changed = colorChanged = true; }
//apply colors to selected segment, and main color array if applicable
for (byte i=0; i<4; i++) if (colIn[i]!=col[i]) col0Changed = colorChanged = true;
if (col0Changed) selseg.setColor(0, RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]), selectedSeg);
if (!singleSegment) {
for (byte i=0; i<4; i++) col[i] = colIn[i];
}
for (byte i=0; i<4; i++) if (colInSec[i]!=colSec[i]) col1Changed = colorChanged = true;
if (col1Changed) selseg.setColor(1, RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]), selectedSeg);
if (!singleSegment) {
for (byte i=0; i<4; i++) colSec[i] = colInSec[i];
} }
//set effect parameters //set effect parameters
if (updateVal(&req, "FX=", &effectCurrent, 0, strip.getModeCount()-1) && request != nullptr) unloadPlaylist(); //unload playlist if changing FX using web request if (updateVal(&req, "FX=", &effectIn, 0, strip.getModeCount()-1) && request != nullptr) unloadPlaylist(); //unload playlist if changing FX using web request
updateVal(&req, "SX=", &effectSpeed); updateVal(&req, "SX=", &speedIn);
updateVal(&req, "IX=", &effectIntensity); updateVal(&req, "IX=", &intensityIn);
updateVal(&req, "FP=", &effectPalette, 0, strip.getPaletteCount()-1); updateVal(&req, "FP=", &paletteIn, 0, strip.getPaletteCount()-1);
strip.setMode(selectedSeg, effectCurrent); strip.setMode(selectedSeg, effectIn);
selseg.speed = effectSpeed; selseg.speed = speedIn;
selseg.intensity = effectIntensity; selseg.intensity = intensityIn;
selseg.palette = effectPalette; selseg.palette = paletteIn;
if (effectCurrent != prevEffect || effectSpeed != prevSpeed || effectIntensity != prevIntensity || effectPalette != prevPalette) effectChanged = true; if (effectIn != effectCurrent || speedIn != effectSpeed || intensityIn != effectIntensity || paletteIn != effectPalette) effectChanged = true;
if (!singleSegment) {
effectCurrent = effectIn;
effectSpeed = speedIn;
effectIntensity = intensityIn;
effectPalette = paletteIn;
}
//set advanced overlay //set advanced overlay
pos = req.indexOf(F("OL=")); pos = req.indexOf(F("OL="));
@ -959,24 +951,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
} }
//you can add more if you need //you can add more if you need
//apply to all selected manually to prevent #1618. Temporary
if (strip.applyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected() || i == selectedSeg) continue;
if (effectCurrent != prevEffect) strip.setMode(i, effectCurrent);
if (effectSpeed != prevSpeed) seg.speed = effectSpeed;
if (effectIntensity != prevIntensity) seg.intensity = effectIntensity;
if (effectPalette != prevPalette) seg.palette = effectPalette;
if (col0Changed) seg.setColor(0, RGBW32(col[0], col[1], col[2], col[3]), i); // use transitions
if (col1Changed) seg.setColor(1, RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]), i); // use transitions
if (col2Changed) seg.colors[2] = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
}
}
strip.applyToAllSelected = false;
setValuesFromMainSeg();
//end of temporary fix code
if (!apply) return true; //when called by JSON API, do not call colorUpdated() here if (!apply) return true; //when called by JSON API, do not call colorUpdated() here
//internal call, does not send XML response //internal call, does not send XML response

View File

@ -28,37 +28,39 @@ void notify(byte callMode, bool followUp)
default: return; default: return;
} }
byte udpOut[WLEDPACKETSIZE]; byte udpOut[WLEDPACKETSIZE];
WS2812FX::Segment& mainseg = strip.getSegment(strip.getMainSegmentId()); WS2812FX::Segment& mainseg = strip.getMainSegment();
udpOut[0] = 0; //0: wled notifier protocol 1: WARLS protocol udpOut[0] = 0; //0: wled notifier protocol 1: WARLS protocol
udpOut[1] = callMode; udpOut[1] = callMode;
udpOut[2] = bri; udpOut[2] = bri;
udpOut[3] = col[0]; uint32_t col = mainseg.colors[0];
udpOut[4] = col[1]; udpOut[3] = R(col);
udpOut[5] = col[2]; udpOut[4] = G(col);
udpOut[5] = B(col);
udpOut[6] = nightlightActive; udpOut[6] = nightlightActive;
udpOut[7] = nightlightDelayMins; udpOut[7] = nightlightDelayMins;
udpOut[8] = effectCurrent; udpOut[8] = mainseg.mode;
udpOut[9] = effectSpeed; udpOut[9] = mainseg.speed;
udpOut[10] = col[3]; udpOut[10] = W(col);
//compatibilityVersionByte: //compatibilityVersionByte:
//0: old 1: supports white 2: supports secondary color //0: old 1: supports white 2: supports secondary color
//3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette //3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette
//6: supports timebase syncing, 29 byte packet 7: supports tertiary color 8: supports sys time sync, 36 byte packet //6: supports timebase syncing, 29 byte packet 7: supports tertiary color 8: supports sys time sync, 36 byte packet
//9: supports sync groups, 37 byte packet 10: supports CCT, 39 byte packet 11: per segment options, variable packet length (40+MAX_NUM_SEGMENTS*3) //9: supports sync groups, 37 byte packet 10: supports CCT, 39 byte packet 11: per segment options, variable packet length (40+MAX_NUM_SEGMENTS*3)
udpOut[11] = 11; udpOut[11] = 11;
udpOut[12] = colSec[0]; col = mainseg.colors[1];
udpOut[13] = colSec[1]; udpOut[12] = R(col);
udpOut[14] = colSec[2]; udpOut[13] = G(col);
udpOut[15] = colSec[3]; udpOut[14] = B(col);
udpOut[16] = effectIntensity; udpOut[15] = W(col);
udpOut[16] = mainseg.intensity;
udpOut[17] = (transitionDelay >> 0) & 0xFF; udpOut[17] = (transitionDelay >> 0) & 0xFF;
udpOut[18] = (transitionDelay >> 8) & 0xFF; udpOut[18] = (transitionDelay >> 8) & 0xFF;
udpOut[19] = effectPalette; udpOut[19] = mainseg.palette;
uint32_t colTer = mainseg.colors[2]; col = mainseg.colors[2];
udpOut[20] = (colTer >> 16) & 0xFF; udpOut[20] = R(col);
udpOut[21] = (colTer >> 8) & 0xFF; udpOut[21] = G(col);
udpOut[22] = (colTer >> 0) & 0xFF; udpOut[22] = B(col);
udpOut[23] = (colTer >> 24) & 0xFF; udpOut[23] = W(col);
udpOut[24] = followUp; udpOut[24] = followUp;
uint32_t t = millis() + strip.timebase; uint32_t t = millis() + strip.timebase;
@ -322,16 +324,20 @@ void handleNotifications()
if (version < 200) if (version < 200)
{ {
if (applyEffects && currentPlaylist >= 0) unloadPlaylist(); if (applyEffects && currentPlaylist >= 0) unloadPlaylist();
if (version > 10 && receiveSegmentOptions) { if (version > 10 && (receiveSegmentOptions || receiveSegmentBounds)) {
//does not sync start & stop uint8_t numSrcSegs = udpIn[39];
uint8_t srcSegs = udpIn[39]; for (uint8_t i = 0; i < numSrcSegs; i++) {
//if (srcSegs > strip.getMaxSegments()) srcSegs = strip.getMaxSegments();
for (uint8_t i = 0; i < srcSegs; i++) {
uint16_t ofs = 41 + i*udpIn[40]; //start of segment offset byte uint16_t ofs = 41 + i*udpIn[40]; //start of segment offset byte
uint8_t id = udpIn[0 +ofs]; uint8_t id = udpIn[0 +ofs];
if (id > strip.getMaxSegments()) continue; if (id > strip.getMaxSegments()) continue;
WS2812FX::Segment& selseg = strip.getSegment(id); WS2812FX::Segment& selseg = strip.getSegment(id);
//bytes 1+2 contain start, 3+4 stop, unused at this time uint16_t start = (udpIn[1+ofs] << 8 | udpIn[2+ofs]);
uint16_t stop = (udpIn[3+ofs] << 8 | udpIn[4+ofs]);
uint16_t offset = (udpIn[7+ofs] << 8 | udpIn[8+ofs]);
if (!receiveSegmentOptions) {
strip.setSegment(id, start, stop, selseg.grouping, selseg.spacing, offset);
continue;
}
for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01); //only take into account mirrored, selected, on, reversed for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01); //only take into account mirrored, selected, on, reversed
selseg.setOpacity(udpIn[10+ofs], id); selseg.setOpacity(udpIn[10+ofs], id);
if (applyEffects) { if (applyEffects) {
@ -346,12 +352,18 @@ void handleNotifications()
selseg.setColor(2, RGBW32(udpIn[23+ofs],udpIn[24+ofs],udpIn[25+ofs],udpIn[26+ofs]), id); selseg.setColor(2, RGBW32(udpIn[23+ofs],udpIn[24+ofs],udpIn[25+ofs],udpIn[26+ofs]), id);
selseg.setCCT(udpIn[27+ofs], id); selseg.setCCT(udpIn[27+ofs], id);
} }
strip.setSegment(id, selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], (udpIn[7+ofs]<<8 | udpIn[8+ofs])); //also properly resets segments //setSegment() also properly resets segments
if (receiveSegmentBounds) {
strip.setSegment(id, start, stop, udpIn[5+ofs], udpIn[6+ofs], offset);
} else {
strip.setSegment(id, selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset);
}
} }
setValuesFromMainSeg();
effectChanged = true; effectChanged = true;
colorChanged = true; colorChanged = true;
} else if (applyEffects) { //simple effect sync, applies to all selected }
if (applyEffects && (version < 11 || !receiveSegmentOptions)) { //simple effect sync, applies to all selected
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8]; if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
effectSpeed = udpIn[9]; effectSpeed = udpIn[9];
if (version > 2) effectIntensity = udpIn[16]; if (version > 2) effectIntensity = udpIn[16];

View File

@ -27,7 +27,7 @@ void WLED::reset()
while (millis() - dly < 450) { while (millis() - dly < 450) {
yield(); // enough time to send response to client yield(); // enough time to send response to client
} }
setAllLeds(); applyBri();
DEBUG_PRINTLN(F("MODULE RESET")); DEBUG_PRINTLN(F("MODULE RESET"));
ESP.restart(); ESP.restart();
} }

View File

@ -315,6 +315,7 @@ WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brigh
WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color
WLED_GLOBAL bool receiveNotificationEffects _INIT(true); // apply effects setup WLED_GLOBAL bool receiveNotificationEffects _INIT(true); // apply effects setup
WLED_GLOBAL bool receiveSegmentOptions _INIT(false); // apply segment options WLED_GLOBAL bool receiveSegmentOptions _INIT(false); // apply segment options
WLED_GLOBAL bool receiveSegmentBounds _INIT(false); // apply segment bounds (start, stop, offset)
WLED_GLOBAL bool notifyDirect _INIT(false); // send notification if change via UI or HTTP API WLED_GLOBAL bool notifyDirect _INIT(false); // send notification if change via UI or HTTP API
WLED_GLOBAL bool notifyButton _INIT(false); // send if updated by button or infrared remote WLED_GLOBAL bool notifyButton _INIT(false); // send if updated by button or infrared remote
WLED_GLOBAL bool notifyAlexa _INIT(false); // send notification if updated via Alexa WLED_GLOBAL bool notifyAlexa _INIT(false); // send notification if updated via Alexa

View File

@ -160,6 +160,7 @@ void initServer()
request->send_P(200, "text/html", PAGE_usermod); request->send_P(200, "text/html", PAGE_usermod);
}); });
//Deprecated, use of /json/state and presets recommended instead
server.on("/url", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/url", HTTP_GET, [](AsyncWebServerRequest *request){
URL_response(request); URL_response(request);
}); });

View File

@ -56,13 +56,13 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
verboseResponse = deserializeState(root); verboseResponse = deserializeState(root);
if (!interfaceUpdateCallMode) { if (!interfaceUpdateCallMode) {
//special case, only on playlist load, avoid sending twice in rapid succession //special case, only on playlist load, avoid sending twice in rapid succession
if (millis() - lastInterfaceUpdate > 1700) verboseResponse = false; if (millis() - lastInterfaceUpdate > (INTERFACE_UPDATE_COOLDOWN -300)) verboseResponse = false;
} }
} }
releaseJSONBufferLock(); // will clean fileDoc releaseJSONBufferLock(); // will clean fileDoc
} }
//update if it takes longer than 300ms until next "broadcast" //update if it takes longer than 300ms until next "broadcast"
if (verboseResponse && (millis() - lastInterfaceUpdate < 1700 || !interfaceUpdateCallMode)) sendDataWs(client); if (verboseResponse && (millis() - lastInterfaceUpdate < (INTERFACE_UPDATE_COOLDOWN -300) || !interfaceUpdateCallMode)) sendDataWs(client);
} }
} else { } else {
//message is comprised of multiple frames or the frame is split into multiple packets //message is comprised of multiple frames or the frame is split into multiple packets
@ -108,9 +108,13 @@ void sendDataWs(AsyncWebSocketClient * client)
JsonObject info = doc.createNestedObject("info"); JsonObject info = doc.createNestedObject("info");
serializeInfo(info); serializeInfo(info);
size_t len = measureJson(doc); size_t len = measureJson(doc);
buffer = ws.makeBuffer(len); size_t heap1 = ESP.getFreeHeap();
if (!buffer) { buffer = ws.makeBuffer(len); // will not allocate correct memory sometimes
size_t heap2 = ESP.getFreeHeap();
if (!buffer || heap1-heap2<len) {
releaseJSONBufferLock(); releaseJSONBufferLock();
ws.closeAll(1013); //code 1013 = temporary overload, try again later
ws.cleanupClients(0); //disconnect all clients to release memory
return; //out of memory return; //out of memory
} }
serializeJson(doc, (char *)buffer->get(), len +1); serializeJson(doc, (char *)buffer->get(), len +1);
@ -155,7 +159,11 @@ void handleWs()
{ {
if (millis() - wsLastLiveTime > WS_LIVE_INTERVAL) if (millis() - wsLastLiveTime > WS_LIVE_INTERVAL)
{ {
#ifdef ESP8266
ws.cleanupClients(3);
#else
ws.cleanupClients(); ws.cleanupClients();
#endif
bool success = true; bool success = true;
if (wsLiveClientId) if (wsLiveClientId)
success = sendLiveLedsWs(wsLiveClientId); success = sendLiveLedsWs(wsLiveClientId);

View File

@ -75,6 +75,7 @@ void XML_response(AsyncWebServerRequest *request, char* dest)
if (request != nullptr) request->send(200, "text/xml", obuf); if (request != nullptr) request->send(200, "text/xml", obuf);
} }
//Deprecated, use of /json/state and presets recommended instead
void URL_response(AsyncWebServerRequest *request) void URL_response(AsyncWebServerRequest *request)
{ {
char sbuf[256]; char sbuf[256];
@ -480,6 +481,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',SET_F("RC"),receiveNotificationColor); sappend('c',SET_F("RC"),receiveNotificationColor);
sappend('c',SET_F("RX"),receiveNotificationEffects); sappend('c',SET_F("RX"),receiveNotificationEffects);
sappend('c',SET_F("SO"),receiveSegmentOptions); sappend('c',SET_F("SO"),receiveSegmentOptions);
sappend('c',SET_F("SG"),receiveSegmentBounds);
sappend('c',SET_F("SD"),notifyDirectDefault); sappend('c',SET_F("SD"),notifyDirectDefault);
sappend('c',SET_F("SB"),notifyButton); sappend('c',SET_F("SB"),notifyButton);
sappend('c',SET_F("SH"),notifyHue); sappend('c',SET_F("SH"),notifyHue);