Merge branch 'master' into merge-master

This commit is contained in:
Blaz Kristan 2022-02-20 22:24:11 +01:00
parent c895b76864
commit 41b6f3ffa7
45 changed files with 2184 additions and 2213 deletions

View File

@ -2,6 +2,17 @@
### Builds after release 0.12.0 ### Builds after release 0.12.0
#### Build 2202200
- Added `info.leds.seglc` per-segment light capability info (PR #2552)
- Fixed `info.leds.rgbw` behavior
- Segment bounds sync (PR #2547)
- WebSockets auto reconnection and error handling
- Disable relay pin by default (PR #2531)
- Various fixes (ESP32 touch pin 33, floats, PR #2530, #2534, #2538)
- Deprecated `info.leds.cct`, `info.leds.wv` and `info.leds.rgbw`
- Deprecated `/url` endpoint
#### Build 2202030 #### Build 2202030
- Switched to binary format for WebSockets peek (PR #2516) - Switched to binary format for WebSockets peek (PR #2516)
@ -19,26 +30,26 @@
#### Build 2112080 #### Build 2112080
- Version bump to 0.13.0-b6 "Toki" - Version bump to 0.13.0-b6 "Toki"
- Added "ESP02" (ESP8266 with 2M of flash) to PIO/release binaries - Added "ESP02" (ESP8266 with 2M of flash) to PIO/release binaries
#### Build 2112070 #### Build 2112070
- Added new effect "Fairy", replacing "Police All" - Added new effect "Fairy", replacing "Police All"
- Added new effect "Fairytwinkle", replacing "Two Areas" - Added new effect "Fairytwinkle", replacing "Two Areas"
- Static single JSON buffer (performance and stability improvement) (PR #2336) - Static single JSON buffer (performance and stability improvement) (PR #2336)
#### Build 2112030 #### Build 2112030
- Fixed ESP32 crash on Colortwinkles brightness change - Fixed ESP32 crash on Colortwinkles brightness change
- Fixed setting picker to black resetting hue and saturation - Fixed setting picker to black resetting hue and saturation
- Fixed auto white mode not saved to config - Fixed auto white mode not saved to config
#### Build 2111300 #### Build 2111300
- Added CCT and white balance correction support (PR #2285) - Added CCT and white balance correction support (PR #2285)
- Unified UI slider style - Unified UI slider style
- Added LED settings config template upload - Added LED settings config template upload
#### Build 2111220 #### Build 2111220

6
package-lock.json generated
View File

@ -28,9 +28,9 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
}, },
"ajv": { "ajv": {
"version": "6.12.2", "version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"requires": { "requires": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",

View File

@ -104,7 +104,6 @@ build_flags =
-DBEARSSL_SSL_BASIC -DBEARSSL_SSL_BASIC
-D CORE_DEBUG_LEVEL=0 -D CORE_DEBUG_LEVEL=0
-D NDEBUG -D NDEBUG
;-Dregister=
#build_flags for the IRremoteESP8266 library (enabled decoders have to appear here) #build_flags for the IRremoteESP8266 library (enabled decoders have to appear here)
-D _IR_ENABLE_DEFAULT_=false -D _IR_ENABLE_DEFAULT_=false
-D DECODE_HASH=true -D DECODE_HASH=true

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

@ -60,7 +60,7 @@ private:
byte prevPlaylist = 0; byte prevPlaylist = 0;
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;
@ -139,7 +139,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

@ -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

@ -86,7 +86,7 @@ private:
static const char _str_minBrightness[]; static const char _str_minBrightness[];
static const char _str_maxBrightness[]; static const char _str_maxBrightness[];
#ifdef USERMOD_ID_SN_PHOTORESISTOR #ifdef USERMOD_SN_PHOTORESISTOR
Usermod_SN_Photoresistor *ptr; Usermod_SN_Photoresistor *ptr;
#else #else
void* ptr = nullptr; void* ptr = nullptr;
@ -371,7 +371,7 @@ public:
} }
_setAllFalse(); _setAllFalse();
#ifdef USERMOD_ID_SN_PHOTORESISTOR #ifdef USERMOD_SN_PHOTORESISTOR
ptr = (Usermod_SN_Photoresistor*) usermods.lookup(USERMOD_ID_SN_PHOTORESISTOR); ptr = (Usermod_SN_Photoresistor*) usermods.lookup(USERMOD_ID_SN_PHOTORESISTOR);
#endif #endif
DEBUG_PRINTLN(F("Setup done")); DEBUG_PRINTLN(F("Setup done"));
@ -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

@ -92,8 +92,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
@ -107,8 +107,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

@ -291,12 +291,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

@ -459,12 +459,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

@ -630,6 +630,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(bool forceReset = false), makeAutoSegments(bool forceReset = false),
@ -643,29 +644,25 @@ 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), hasRGBWBus(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), getLastActiveSegmentId(void),
getTargetFps(void),
setPixelSegment(uint8_t n), setPixelSegment(uint8_t n),
gamma8(uint8_t), gamma8(uint8_t),
gamma8_cal(uint8_t, float), gamma8_cal(uint8_t, float),
@ -695,11 +692,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);
@ -893,6 +888,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

@ -392,64 +392,21 @@ 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,24 +431,37 @@ 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
{ uint8_t WS2812FX::getLastActiveSegmentId(void) {
for (uint8_t i = MAX_NUM_SEGMENTS -1; i > 0; i--) {
if (_segments[i].isActive()) return i; if (_segments[i].isActive()) return i;
} }
return 0; return 0;
@ -539,8 +501,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) {
@ -578,7 +540,9 @@ uint8_t WS2812FX::Segment::differs(Segment& b) {
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;
@ -618,6 +582,23 @@ uint8_t WS2812FX::Segment::getLightCapabilities() {
return capabilities; return capabilities;
} }
//used for JSON API info.leds.rgbw. Little practical use, deprecate with info.leds.rgbw.
//returns if there is an RGBW bus (supports RGB and White, not only white)
//not influenced by auto-white mode, also true if white slider does not affect output white channel
bool WS2812FX::hasRGBWBus(void) {
for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
Bus *bus = busses.getBus(b);
if (bus == nullptr || bus->getLength()==0) break;
switch (bus->getType()) {
case TYPE_SK6812_RGBW:
case TYPE_TM1814:
case TYPE_ANALOG_4CH:
return true;
}
}
return false;
}
bool WS2812FX::hasCCTBus(void) { bool WS2812FX::hasCCTBus(void) {
if (cctFromRgb && !correctWB) return false; if (cctFromRgb && !correctWB) return false;
for (uint8_t b = 0; b < busses.getNumBusses(); b++) { for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
@ -649,17 +630,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;
@ -681,7 +653,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;
@ -739,6 +711,12 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
} else { } else {
//expand the main seg to the entire length, but only if there are no other segments, or reset is forced //expand the main seg to the entire length, but only if there are no other segments, or reset is forced
uint8_t mainSeg = getMainSegmentId(); uint8_t mainSeg = getMainSegmentId();
if (forceReset) {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) {
setSegment(i, 0, 0);
}
}
if (forceReset) { if (forceReset) {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) {

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

@ -46,27 +46,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,7 +16,7 @@ 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(); effectChanged = true; colorUpdated(CALL_MODE_BUTTON); break;
} }
} else { } else {
@ -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
@ -263,8 +244,8 @@ void handleButton()
} else if (b == 0 && dur > WLED_LONG_AP) { //long press on button 0 (when released) } else 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
//NOTE: this interferes with double click handling in usermods so it is commented out //NOTE: this interferes with double click handling in usermods so usermod needs to implement full button handling
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

@ -265,6 +265,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);
@ -671,9 +672,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);
}
//relatively change white brightness, minumum A=5 //relatively change white brightness, minumum A=5
void relativeChangeWhite(int8_t amount, byte lowerBoundary) void relativeChangeWhite(int8_t amount, byte lowerBoundary)
{ {

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
@ -340,4 +341,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

@ -425,6 +425,10 @@ button {
overflow: auto; overflow: auto;
} }
.modal button:hover {
background-color: var(--c-4);
}
#info, #nodes { #info, #nodes {
z-index: 3; z-index: 3;
} }

View File

@ -188,8 +188,6 @@ function onLoad()
var sett = localStorage.getItem('wledUiCfg'); var sett = localStorage.getItem('wledUiCfg');
if (sett) cfg = mergeDeep(cfg, JSON.parse(sett)); if (sett) cfg = mergeDeep(cfg, JSON.parse(sett));
makeWS();
resetPUtil(); resetPUtil();
applyCfg(); applyCfg();
@ -206,7 +204,7 @@ function onLoad()
//TODO: do some parsing first //TODO: do some parsing first
}) })
.catch((e)=>{ .catch((e)=>{
console.log("holidays.json does not contain array of holidays. Defaults loaded."); console.log("No array of holidays in holidays.json. Defaults loaded.");
}) })
.finally(()=>{ .finally(()=>{
loadBg(cfg.theme.bg.url); loadBg(cfg.theme.bg.url);
@ -228,7 +226,7 @@ function onLoad()
loadFXData(); loadFXData();
setTimeout(()=>{ //ESP8266 can't handle quick requests setTimeout(()=>{ //ESP8266 can't handle quick requests
loadPresets(()=>{ loadPresets(()=>{
requestJson(); requestJson(); // will create WS
}); });
},100); },100);
}); });
@ -276,14 +274,9 @@ function showToast(text, error = false)
if (error) console.log(text); if (error) console.log(text);
} }
function showErrorToast() function showErrorToast() {
{ // if we received a timeout force WS reconnect
if (ws && ws.readyState === WebSocket.OPEN) { setTimeout(makeWS,500);
// if we received a timeout force WS reconnect
ws.close();
ws = null;
if (lastinfo.ws > -1) setTimeout(makeWS,500);
}
showToast('Connection to light failed!', true); showToast('Connection to light failed!', true);
} }
@ -1081,13 +1074,14 @@ function cmpP(a, b)
} }
function makeWS() { function makeWS() {
if (ws) return; if (ws) { ws.close(); ws=null; }
if (lastinfo.ws < 0) 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 = (e)=>{ ws.onmessage = (e)=>{
if (e.data instanceof ArrayBuffer) return; //liveview packet if (e.data instanceof ArrayBuffer) return; //liveview packet
var json = JSON.parse(e.data); var json = JSON.parse(e.data);
if (json.leds) return; //liveview packet if (json.leds) return; //JSON liveview packet
clearTimeout(jsonTimeout); clearTimeout(jsonTimeout);
jsonTimeout = null; jsonTimeout = null;
lastUpdate = new Date(); lastUpdate = new Date();
@ -1108,8 +1102,7 @@ function makeWS() {
}; };
ws.onclose = (e)=>{ ws.onclose = (e)=>{
gId('connind').style.backgroundColor = "var(--c-r)"; gId('connind').style.backgroundColor = "var(--c-r)";
ws = null; setTimeout(makeWS,500); //retry WS connection
if (lastinfo.ws > -1) setTimeout(makeWS,500); //retry WS connection
} }
ws.onopen = (e)=>{ ws.onopen = (e)=>{
//ws.send("{'v':true}"); //unnecessary (https://github.com/Aircoookie/WLED/blob/master/wled00/ws.cpp#L18) //ws.send("{'v':true}"); //unnecessary (https://github.com/Aircoookie/WLED/blob/master/wled00/ws.cpp#L18)
@ -1398,6 +1391,7 @@ function requestJson(command=null)
} }
var s = json.state ? json.state : json; var s = json.state ? json.state : json;
readState(s); readState(s);
makeWS();
reqsLegal = true; reqsLegal = true;
}) })
.catch((e)=>{ .catch((e)=>{

View File

@ -92,7 +92,7 @@ UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required
</tr> </tr>
</table><br> </table><br>
Receive: <nowrap><input type="checkbox" name="RB">Brightness,</nowrap> <nowrap><input type="checkbox" name="RC">Color,</nowrap> <nowrap>and <input type="checkbox" name="RX">Effects</nowrap><br> Receive: <nowrap><input type="checkbox" name="RB">Brightness,</nowrap> <nowrap><input type="checkbox" name="RC">Color,</nowrap> <nowrap>and <input type="checkbox" name="RX">Effects</nowrap><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

@ -73,6 +73,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();
@ -143,9 +145,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();
@ -276,7 +279,6 @@ bool oappendi(int i); // append new number to temp buffer efficiently
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=false);
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

@ -902,183 +902,184 @@ const uint8_t PAGE_settings_ui[] PROGMEM = {
// Autogenerated from wled00/data/settings_sync.htm, do not edit!! // Autogenerated from wled00/data/settings_sync.htm, do not edit!!
const uint16_t PAGE_settings_sync_length = 2794; const uint16_t PAGE_settings_sync_length = 2814;
const uint8_t PAGE_settings_sync[] PROGMEM = { const uint8_t PAGE_settings_sync[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x95, 0x1a, 0x5b, 0x77, 0xda, 0x38, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x95, 0x1a, 0x5b, 0x77, 0xda, 0x38,
0xf3, 0xdd, 0xbf, 0x42, 0xeb, 0x87, 0xdd, 0xb0, 0x25, 0x60, 0x20, 0xd0, 0x34, 0xc1, 0xee, 0x17, 0xf3, 0xdd, 0xbf, 0x42, 0xeb, 0x87, 0x6e, 0xd8, 0x12, 0x30, 0x10, 0x68, 0x4a, 0xb0, 0xfb, 0x85,
0x42, 0x9a, 0xe4, 0x6c, 0xd3, 0x52, 0x48, 0xf7, 0xf2, 0xb4, 0x47, 0xd8, 0x02, 0x3b, 0xd8, 0x96, 0x90, 0x26, 0x39, 0xdb, 0x34, 0x14, 0xd2, 0xed, 0xee, 0xd3, 0x1e, 0x61, 0x0b, 0x70, 0xb0, 0x2d,
0xd7, 0x92, 0x73, 0x39, 0x7b, 0xf6, 0xbf, 0x7f, 0x33, 0x92, 0x6d, 0xc0, 0x5c, 0xfb, 0x10, 0x23, 0xaf, 0x25, 0xe7, 0x72, 0xf6, 0xec, 0x7f, 0xff, 0x66, 0x24, 0xdb, 0x80, 0xb9, 0xf6, 0x21, 0x46,
0x4b, 0x33, 0xa3, 0xd1, 0xdc, 0x47, 0x4e, 0xff, 0xa7, 0xe1, 0xd7, 0xeb, 0xc7, 0xbf, 0x46, 0x37, 0x96, 0x66, 0x46, 0xa3, 0xb9, 0x8f, 0x9c, 0xde, 0x2f, 0x83, 0x87, 0xab, 0xc7, 0xbf, 0x86, 0xd7,
0xc4, 0x97, 0x51, 0xe8, 0xf4, 0xf1, 0x49, 0x42, 0x1a, 0xcf, 0x6d, 0x93, 0xc5, 0x26, 0xbc, 0x33, 0x64, 0x2e, 0xc3, 0xc0, 0xe9, 0xe1, 0x93, 0x04, 0x34, 0x9a, 0xd9, 0x26, 0x8b, 0x4c, 0x78, 0x67,
0xea, 0x39, 0xfd, 0x88, 0x49, 0x4a, 0x62, 0x1a, 0x31, 0xdb, 0x7c, 0x0e, 0xd8, 0x4b, 0xc2, 0x53, 0xd4, 0x73, 0x7a, 0x21, 0x93, 0x94, 0x44, 0x34, 0x64, 0xb6, 0xf9, 0xec, 0xb3, 0x97, 0x98, 0x27,
0x69, 0x12, 0x97, 0xc7, 0x92, 0xc5, 0xd2, 0x36, 0x5f, 0x02, 0x4f, 0xfa, 0x76, 0xd7, 0xb2, 0x4c, 0xd2, 0x24, 0x2e, 0x8f, 0x24, 0x8b, 0xa4, 0x6d, 0xbe, 0xf8, 0x9e, 0x9c, 0xdb, 0x6d, 0xcb, 0x32,
0xc7, 0xd0, 0xa0, 0x46, 0x65, 0xcd, 0x63, 0xcf, 0x81, 0xcb, 0x4e, 0xd5, 0x4b, 0x3d, 0x88, 0x03, 0x1d, 0x43, 0x83, 0x1a, 0xa5, 0x35, 0x8f, 0x3d, 0xfb, 0x2e, 0x3b, 0x55, 0x2f, 0x55, 0x3f, 0xf2,
0x19, 0xd0, 0xf0, 0x54, 0xb8, 0x34, 0x64, 0x76, 0xab, 0x1e, 0xd1, 0xd7, 0x20, 0xca, 0xa2, 0xf2, 0xa5, 0x4f, 0x83, 0x53, 0xe1, 0xd2, 0x80, 0xd9, 0x8d, 0x6a, 0x48, 0x5f, 0xfd, 0x30, 0x0d, 0x8b,
0x3d, 0x13, 0x2c, 0x55, 0x2f, 0x74, 0x0a, 0xef, 0x31, 0x37, 0x89, 0x51, 0xd9, 0x3a, 0x67, 0xc8, 0xf7, 0x54, 0xb0, 0x44, 0xbd, 0xd0, 0x09, 0xbc, 0x47, 0xdc, 0x24, 0x46, 0x69, 0xeb, 0x8c, 0x21,
0xf5, 0x69, 0x2a, 0x18, 0x6c, 0x92, 0xc9, 0xd9, 0xe9, 0x39, 0xcc, 0xca, 0x40, 0x86, 0xcc, 0x99, 0x77, 0x4e, 0x13, 0xc1, 0x60, 0x93, 0x54, 0x4e, 0x4f, 0xcf, 0x61, 0x56, 0xfa, 0x32, 0x60, 0xce,
0xbc, 0xc5, 0x2e, 0x99, 0x30, 0x29, 0x83, 0x78, 0x2e, 0xfa, 0x4d, 0x3d, 0xd9, 0x17, 0x6e, 0x1a, 0xf8, 0x2d, 0x72, 0xc9, 0x98, 0x49, 0xe9, 0x47, 0x33, 0xd1, 0xab, 0xeb, 0xc9, 0x9e, 0x70, 0x13,
0x24, 0xd2, 0x31, 0x9e, 0x69, 0x4a, 0x3c, 0xdb, 0xe3, 0x6e, 0x16, 0x01, 0x83, 0x97, 0xb3, 0x2c, 0x3f, 0x96, 0x8e, 0xf1, 0x4c, 0x13, 0xe2, 0xd9, 0x1e, 0x77, 0xd3, 0x10, 0x18, 0xbc, 0x98, 0xa6,
0x76, 0x65, 0xc0, 0x63, 0x32, 0xbf, 0xf7, 0x4e, 0x58, 0xed, 0xdf, 0x94, 0xc9, 0x2c, 0x8d, 0x89, 0x91, 0x2b, 0x7d, 0x1e, 0x91, 0xd9, 0x9d, 0x77, 0xc2, 0x2a, 0xff, 0x26, 0x4c, 0xa6, 0x49, 0x44,
0xd7, 0x98, 0x33, 0x79, 0x13, 0x32, 0x84, 0x19, 0xbc, 0xa9, 0xa5, 0xff, 0x4a, 0xd0, 0xbb, 0x93, 0xbc, 0xda, 0x8c, 0xc9, 0xeb, 0x80, 0x21, 0x4c, 0xff, 0x4d, 0x2d, 0xfd, 0x57, 0x80, 0xde, 0x9e,
0xda, 0xbf, 0x2f, 0x41, 0xec, 0xf1, 0x97, 0x06, 0x4f, 0x58, 0x7c, 0x62, 0xfa, 0x52, 0x26, 0xe2, 0x54, 0xfe, 0x7d, 0xf1, 0x23, 0x8f, 0xbf, 0xd4, 0x78, 0xcc, 0xa2, 0x13, 0x73, 0x2e, 0x65, 0x2c,
0xa2, 0xd9, 0x5c, 0xc4, 0xbc, 0xf1, 0x12, 0x32, 0x44, 0x6e, 0x06, 0x20, 0x80, 0x74, 0x46, 0x5d, 0xba, 0xf5, 0xfa, 0x22, 0xe2, 0xb5, 0x97, 0x80, 0x21, 0x72, 0xdd, 0x07, 0x01, 0x24, 0x53, 0xea,
0x26, 0x9a, 0x99, 0x97, 0x9c, 0xc6, 0x5c, 0x06, 0xb3, 0x80, 0xa5, 0x4d, 0x73, 0x85, 0xd0, 0xa0, 0x32, 0x51, 0x4f, 0xbd, 0xf8, 0x34, 0xe2, 0xd2, 0x9f, 0xfa, 0x2c, 0xa9, 0x9b, 0x2b, 0x84, 0xfa,
0x4a, 0xa8, 0x29, 0x72, 0xb6, 0xcd, 0xba, 0xf9, 0xb7, 0x60, 0xe1, 0x6c, 0x15, 0x9a, 0x7a, 0x4f, 0x65, 0x42, 0x75, 0x91, 0xb1, 0x6d, 0x56, 0xcd, 0xbf, 0x05, 0x0b, 0xa6, 0xab, 0xd0, 0xd4, 0x7b,
0x00, 0xdf, 0x3b, 0xeb, 0x9e, 0xd9, 0xb6, 0xd7, 0x98, 0xcc, 0x1a, 0xc3, 0xfb, 0xc6, 0x33, 0x0d, 0x02, 0xf8, 0xce, 0x59, 0xfb, 0xcc, 0xb6, 0xbd, 0xda, 0x78, 0x5a, 0x1b, 0xdc, 0xd5, 0x9e, 0x69,
0x33, 0xf6, 0xf1, 0xa4, 0x55, 0xcc, 0x5c, 0xe9, 0x99, 0x9f, 0x7f, 0x3e, 0x59, 0x7b, 0xb7, 0xad, 0x90, 0xb2, 0x4f, 0x27, 0x8d, 0x7c, 0xe6, 0x52, 0xcf, 0xbc, 0x7b, 0x77, 0xb2, 0xf6, 0x6e, 0x5b,
0x5a, 0xbd, 0x80, 0xb9, 0xf9, 0xbe, 0x0e, 0x53, 0xbc, 0x03, 0x4c, 0xed, 0xa2, 0xdb, 0xed, 0x9d, 0x95, 0x6a, 0x0e, 0x73, 0xfd, 0x7d, 0x1d, 0x26, 0x7f, 0x07, 0x98, 0x4a, 0xb7, 0xdd, 0xee, 0x9c,
0x57, 0xa8, 0x03, 0x9c, 0x75, 0x88, 0x7c, 0xab, 0x56, 0xb7, 0x0e, 0x91, 0x6f, 0xd5, 0x56, 0xce, 0x97, 0xa8, 0x03, 0x9c, 0x75, 0x88, 0x7c, 0xa3, 0x52, 0xb5, 0x0e, 0x91, 0x6f, 0x54, 0x56, 0xce,
0xf2, 0xe9, 0x1a, 0x8e, 0x32, 0xe3, 0xe9, 0xc9, 0x93, 0x6d, 0x5d, 0x3e, 0xf5, 0xcf, 0x2f, 0x9f, 0xf2, 0xf9, 0x0a, 0x8e, 0x32, 0xe5, 0xc9, 0xc9, 0x93, 0x6d, 0x5d, 0x3c, 0xf5, 0xce, 0x2f, 0x9e,
0xde, 0xbd, 0xab, 0xa1, 0x0a, 0xcc, 0x5b, 0xf3, 0xdd, 0xc9, 0xd3, 0x3b, 0x00, 0x6e, 0xb8, 0x3e, 0xde, 0xbf, 0xaf, 0xa0, 0x0a, 0xcc, 0x1b, 0xf3, 0xfd, 0xc9, 0xd3, 0x7b, 0x00, 0xae, 0xb9, 0x73,
0x73, 0x17, 0xcc, 0xb3, 0xf5, 0xf4, 0xc4, 0xac, 0x69, 0x42, 0x8e, 0xf3, 0xf4, 0x73, 0xab, 0xae, 0xe6, 0x2e, 0x98, 0x67, 0xeb, 0xe9, 0xb1, 0x59, 0xd1, 0x84, 0x1c, 0xe7, 0xe9, 0x5d, 0xa3, 0xaa,
0x26, 0xc7, 0x3b, 0x60, 0xc7, 0x6b, 0xb0, 0xcb, 0x5d, 0x6f, 0x71, 0x57, 0x34, 0x00, 0x38, 0x6c, 0x26, 0x47, 0x3b, 0x60, 0x47, 0x6b, 0xb0, 0xcb, 0x5d, 0x6f, 0x70, 0x57, 0x34, 0x00, 0x38, 0x6c,
0xdd, 0x83, 0x3f, 0x6a, 0xb7, 0x2e, 0xab, 0x5c, 0xb0, 0x77, 0xf6, 0x76, 0x46, 0x7e, 0xa5, 0x75, 0xd5, 0x83, 0x3f, 0x6a, 0x37, 0x2e, 0xca, 0x5c, 0xb0, 0xf7, 0xf6, 0x76, 0x46, 0x7e, 0xa3, 0x55,
0x2f, 0x5f, 0x1b, 0x6f, 0x59, 0xa3, 0xbf, 0xda, 0xed, 0xcb, 0x0a, 0xaf, 0x36, 0xab, 0x57, 0x38, 0x2f, 0x5b, 0x1b, 0x6d, 0x59, 0xa3, 0xbf, 0xd9, 0xcd, 0x8b, 0x12, 0xaf, 0x36, 0xab, 0x96, 0x38,
0xb2, 0xbd, 0x25, 0x3b, 0x93, 0x51, 0xc9, 0xce, 0x9a, 0xc4, 0x35, 0x95, 0xd7, 0x04, 0x70, 0x84, 0xb2, 0xbd, 0x25, 0x3b, 0xe3, 0x61, 0xc1, 0xce, 0x9a, 0xc4, 0x35, 0x95, 0xd7, 0x18, 0x70, 0x84,
0x7c, 0x0b, 0x59, 0xc3, 0x0b, 0x44, 0x12, 0xd2, 0x37, 0x9b, 0x39, 0xd6, 0x47, 0x33, 0xe6, 0x31, 0x7c, 0x0b, 0x58, 0xcd, 0xf3, 0x45, 0x1c, 0xd0, 0x37, 0x9b, 0x39, 0xd6, 0x27, 0x33, 0xe2, 0x11,
0x33, 0x2f, 0xcc, 0x69, 0xc8, 0xdd, 0x85, 0x59, 0x87, 0xa9, 0x52, 0xd2, 0xa3, 0x62, 0xd3, 0x15, 0x33, 0xbb, 0xe6, 0x24, 0xe0, 0xee, 0xc2, 0xac, 0xc2, 0x54, 0x21, 0xe9, 0x61, 0xbe, 0xe9, 0x8a,
0x41, 0x83, 0x1f, 0xfc, 0x4e, 0x43, 0xd8, 0x47, 0xbc, 0x04, 0xd2, 0xf5, 0x4f, 0x12, 0x74, 0x99, 0xa0, 0xc1, 0x0f, 0xfe, 0xa0, 0x01, 0xec, 0x23, 0x5e, 0x7c, 0xe9, 0xce, 0x4f, 0x62, 0x74, 0x99,
0xfb, 0x58, 0xae, 0xa3, 0xd4, 0x6a, 0xff, 0xba, 0x54, 0x30, 0x82, 0xea, 0xbf, 0x58, 0xe3, 0xc5, 0xbb, 0x48, 0xae, 0xa3, 0x54, 0x2a, 0xff, 0xba, 0x54, 0x30, 0x82, 0xea, 0xef, 0xae, 0xf1, 0x62,
0xc6, 0xa9, 0xcb, 0x69, 0xca, 0xe8, 0xe2, 0x52, 0x81, 0xa0, 0xfd, 0x55, 0x40, 0x70, 0x6a, 0x15, 0xe3, 0xd4, 0xc5, 0x24, 0x61, 0x74, 0x71, 0xa1, 0x40, 0xd0, 0xfe, 0x4a, 0x20, 0x38, 0xb5, 0x0a,
0xe4, 0xcc, 0x3a, 0xab, 0x52, 0xc1, 0xa9, 0xff, 0xf0, 0xbc, 0x75, 0xd4, 0xfc, 0x0a, 0x7b, 0xc0, 0x72, 0x66, 0x9d, 0x95, 0xa9, 0xe0, 0xd4, 0x7f, 0x78, 0xde, 0x2a, 0x6a, 0x7e, 0x85, 0x3d, 0xe0,
0xd9, 0x2d, 0xb0, 0x08, 0x0b, 0x05, 0xa7, 0xff, 0x19, 0xfd, 0x66, 0xee, 0xac, 0xb9, 0xd3, 0x12, 0xec, 0x06, 0x58, 0x84, 0x85, 0x9c, 0xd3, 0xff, 0x8c, 0x5e, 0x3d, 0x73, 0xd6, 0xcc, 0x69, 0x89,
0x91, 0xba, 0xb6, 0x59, 0xb8, 0x46, 0xe3, 0x49, 0x7c, 0x4c, 0xec, 0x33, 0x70, 0xf7, 0x25, 0x18, 0x48, 0x5c, 0xdb, 0xcc, 0x5d, 0xa3, 0xf6, 0x24, 0x3e, 0xc5, 0xf6, 0x19, 0xb8, 0xfb, 0x12, 0x0c,
0x4a, 0xc9, 0xf9, 0x5f, 0x10, 0x61, 0x74, 0x20, 0x59, 0x1a, 0x9e, 0x98, 0x5a, 0x70, 0xae, 0x10, 0xa5, 0xe4, 0xfc, 0xcf, 0x0f, 0x31, 0x3a, 0x90, 0x34, 0x09, 0x4e, 0x4c, 0x2d, 0x38, 0x57, 0x08,
0x66, 0xed, 0x12, 0x09, 0x2a, 0x88, 0x7e, 0x53, 0x87, 0xb3, 0x29, 0xf7, 0xde, 0x08, 0x8f, 0x43, 0xb3, 0x72, 0x81, 0x04, 0x15, 0x44, 0xaf, 0xae, 0xc3, 0xd9, 0x84, 0x7b, 0x6f, 0x84, 0x47, 0x01,
0x4e, 0x3d, 0xdb, 0x04, 0x16, 0x80, 0x16, 0x58, 0x41, 0x44, 0x02, 0x78, 0xc5, 0xc1, 0xdf, 0xc2, 0xa7, 0x9e, 0x6d, 0x02, 0x0b, 0x40, 0x0b, 0xac, 0x20, 0x24, 0x3e, 0xbc, 0xe2, 0xe0, 0x6f, 0x61,
0xcc, 0xa3, 0xdd, 0x64, 0x66, 0x12, 0x88, 0x35, 0x3e, 0x87, 0x95, 0x84, 0x0b, 0x88, 0x7a, 0x06, 0x66, 0xd1, 0x6e, 0x3c, 0x35, 0x09, 0xc4, 0x9a, 0x39, 0x87, 0x95, 0x98, 0x0b, 0x88, 0x7a, 0x06,
0x8f, 0x45, 0x36, 0x8d, 0x02, 0x08, 0x3b, 0x68, 0x4e, 0x80, 0xea, 0x05, 0xcf, 0xc4, 0x0d, 0xa9, 0x8f, 0x44, 0x3a, 0x09, 0x7d, 0x08, 0x3b, 0x68, 0x4e, 0x80, 0xea, 0xf9, 0xcf, 0xc4, 0x0d, 0xa8,
0x10, 0xb6, 0x29, 0x79, 0x92, 0xf2, 0x97, 0xf5, 0x39, 0x9f, 0x85, 0xc9, 0x00, 0xa6, 0xa6, 0x99, 0x10, 0xb6, 0x29, 0x79, 0x9c, 0xf0, 0x97, 0xf5, 0xb9, 0x39, 0x0b, 0xe2, 0x3e, 0x4c, 0x4d, 0x52,
0x94, 0x70, 0x62, 0xf9, 0x96, 0x00, 0x5d, 0xfd, 0xa2, 0xa8, 0xb9, 0x61, 0xe0, 0x2e, 0x6c, 0xf3, 0x29, 0xe1, 0xc4, 0xf2, 0x2d, 0x06, 0xba, 0xfa, 0x45, 0x51, 0x73, 0x03, 0xdf, 0x5d, 0xd8, 0xe6,
0x0e, 0x69, 0x7d, 0xec, 0x37, 0xf5, 0x0a, 0xb0, 0x0a, 0x24, 0x76, 0x20, 0x95, 0x38, 0x03, 0xc4, 0x2d, 0xd2, 0xfa, 0xd4, 0xab, 0xeb, 0x15, 0x60, 0x15, 0x48, 0xec, 0x40, 0x2a, 0x70, 0xfa, 0x88,
0x19, 0x50, 0x77, 0x51, 0xa2, 0x19, 0xeb, 0x18, 0x9a, 0x53, 0xd3, 0x99, 0xd0, 0x67, 0xb6, 0x24, 0xd3, 0xa7, 0xee, 0xa2, 0x40, 0x33, 0xd6, 0x31, 0x34, 0xa7, 0xa6, 0x33, 0xa6, 0xcf, 0x6c, 0x49,
0xed, 0xa7, 0x05, 0x79, 0xbf, 0xad, 0xa3, 0x25, 0xc8, 0x36, 0x4b, 0x40, 0x3a, 0x6d, 0x98, 0xea, 0x7a, 0x9e, 0xe4, 0xe4, 0xe7, 0x4d, 0x1d, 0x2d, 0x41, 0xb6, 0x69, 0x0c, 0xd2, 0x69, 0xc2, 0x54,
0x38, 0xc6, 0x1f, 0x9f, 0x6f, 0x86, 0x64, 0x90, 0x82, 0x78, 0x40, 0x9f, 0x12, 0xe6, 0x3b, 0xce, 0xcb, 0x31, 0x7e, 0x7c, 0xb9, 0x1e, 0x90, 0x7e, 0x02, 0xe2, 0x01, 0x7d, 0x4a, 0x98, 0x6f, 0x39,
0xf7, 0xe1, 0x88, 0x8c, 0x40, 0xba, 0x17, 0xa4, 0x1f, 0xc4, 0x49, 0x26, 0x73, 0xf9, 0x7c, 0x1f, 0xdf, 0x07, 0x43, 0x32, 0x04, 0xe9, 0x76, 0x49, 0xcf, 0x8f, 0xe2, 0x54, 0x66, 0xf2, 0xf9, 0x3e,
0x99, 0xf9, 0x56, 0x71, 0x16, 0x4d, 0x59, 0x0a, 0xd2, 0x0a, 0x62, 0xdb, 0x6c, 0xc1, 0x2f, 0x7d, 0x34, 0xb3, 0xad, 0xa2, 0x34, 0x9c, 0xb0, 0x04, 0xa4, 0xe5, 0x47, 0xb6, 0xd9, 0x80, 0x5f, 0xfa,
0xb5, 0xcd, 0x5e, 0xb7, 0xdb, 0xe9, 0xc2, 0x29, 0x73, 0x51, 0x78, 0x30, 0x4e, 0xd9, 0x3f, 0x59, 0x6a, 0x9b, 0x9d, 0x76, 0xbb, 0xd5, 0x86, 0x53, 0x66, 0xa2, 0xf0, 0x60, 0x9c, 0xb0, 0x7f, 0x52,
0x90, 0x32, 0xd4, 0x42, 0xea, 0xb4, 0x63, 0x6f, 0x2b, 0xd5, 0xf6, 0x2e, 0xaa, 0xc6, 0x2a, 0xd9, 0x3f, 0x61, 0xa8, 0x85, 0xc4, 0x69, 0x46, 0xde, 0x56, 0xaa, 0xcd, 0x5d, 0x54, 0x8d, 0x55, 0xb2,
0x5d, 0x54, 0xd5, 0xdf, 0x2a, 0x3d, 0x70, 0x48, 0xa5, 0x5b, 0xfc, 0x5d, 0xa7, 0x6b, 0x28, 0xc3, 0xbb, 0xa8, 0xaa, 0xbf, 0x55, 0x7a, 0xe0, 0x90, 0x4a, 0xb7, 0xf8, 0xbb, 0x4e, 0xd7, 0x50, 0x86,
0x00, 0x1a, 0xda, 0xc3, 0x2e, 0x94, 0x73, 0x39, 0xeb, 0xdc, 0x80, 0xf3, 0x6a, 0xec, 0xf1, 0x71, 0x01, 0x34, 0xb4, 0x87, 0x75, 0x95, 0x73, 0x39, 0xeb, 0xdc, 0x80, 0xf3, 0x6a, 0xec, 0xd1, 0x71,
0xd8, 0x7d, 0x89, 0x89, 0x8b, 0xe4, 0x6b, 0x11, 0x4d, 0xe7, 0x41, 0x7c, 0x61, 0x11, 0x9a, 0x49, 0xd8, 0x3d, 0x89, 0x89, 0x8b, 0x64, 0x6b, 0x21, 0x4d, 0x66, 0x7e, 0xd4, 0xb5, 0x08, 0x4d, 0x25,
0x8e, 0x8b, 0xc0, 0x9b, 0xf4, 0x20, 0x79, 0x86, 0x22, 0xa1, 0x70, 0xa8, 0x0f, 0x4b, 0x32, 0x92, 0xc7, 0x45, 0xe0, 0x4d, 0x7a, 0x90, 0x3c, 0x03, 0x11, 0x53, 0x38, 0xd4, 0xc7, 0x25, 0x19, 0xc9,
0xbd, 0xca, 0x53, 0x1a, 0x06, 0xf3, 0xf8, 0xc2, 0x65, 0x98, 0x3e, 0x4c, 0xad, 0x9d, 0x79, 0xca, 0x5e, 0xe5, 0x29, 0x0d, 0xfc, 0x59, 0xd4, 0x75, 0x19, 0xa6, 0x0f, 0x53, 0x6b, 0x67, 0x96, 0xf0,
0xb3, 0x04, 0x33, 0x19, 0x1c, 0xaf, 0xa9, 0xf0, 0x15, 0x0d, 0x47, 0xcf, 0xc0, 0x5f, 0xab, 0x1c, 0x34, 0xc6, 0x4c, 0x06, 0xc7, 0xab, 0x2b, 0x7c, 0x45, 0xc3, 0xd1, 0x33, 0xf0, 0xd7, 0x28, 0x46,
0xb5, 0xd5, 0xc8, 0xc0, 0x61, 0xa7, 0x9c, 0x3c, 0x2b, 0x47, 0xdd, 0x72, 0xd4, 0x2b, 0x47, 0xef, 0x4d, 0x35, 0x32, 0x70, 0xd8, 0x2a, 0x26, 0xcf, 0x8a, 0x51, 0xbb, 0x18, 0x75, 0x8a, 0xd1, 0x87,
0xcb, 0xd1, 0xf9, 0xe6, 0x16, 0x13, 0x16, 0x7b, 0x17, 0x46, 0x09, 0x91, 0xcb, 0x45, 0x4b, 0x41, 0x62, 0x74, 0xbe, 0xb9, 0xc5, 0x98, 0x45, 0x5e, 0xd7, 0x28, 0x20, 0x32, 0xb9, 0x68, 0x29, 0xa8,
0x85, 0xbe, 0x29, 0x7f, 0xcd, 0xa5, 0xd3, 0x2a, 0x7c, 0x06, 0x46, 0x4e, 0x15, 0xc3, 0xd8, 0x8a, 0xd0, 0x37, 0xe1, 0xaf, 0x99, 0x74, 0x1a, 0xb9, 0xcf, 0xc0, 0xc8, 0x29, 0x63, 0x18, 0x5b, 0x51,
0xd2, 0x2e, 0x51, 0xda, 0x9b, 0x28, 0x5b, 0x31, 0x3a, 0x65, 0x31, 0x00, 0xc3, 0xe3, 0x50, 0xce, 0x9a, 0x05, 0x4a, 0x73, 0x13, 0x65, 0x2b, 0x46, 0xab, 0x28, 0x06, 0x60, 0x78, 0x1c, 0xca, 0x59,
0xca, 0x4d, 0xce, 0x8e, 0xe5, 0xab, 0x5b, 0xa2, 0x74, 0x8f, 0xdc, 0xa4, 0xb7, 0xe4, 0xab, 0x77, 0xb1, 0xc9, 0xd9, 0xb1, 0x7c, 0xb5, 0x0b, 0x94, 0xf6, 0x91, 0x9b, 0x74, 0x96, 0x7c, 0x75, 0x8e,
0x24, 0xca, 0xfb, 0x72, 0x93, 0xf7, 0xc7, 0xf2, 0x75, 0x5e, 0xa2, 0x9c, 0x17, 0x28, 0xab, 0xca, 0x44, 0xf9, 0x50, 0x6c, 0xf2, 0xe1, 0x58, 0xbe, 0xce, 0x0b, 0x94, 0xf3, 0x1c, 0x65, 0x55, 0x59,
0x1a, 0x33, 0x97, 0x05, 0xcf, 0xec, 0xe2, 0x28, 0x62, 0xe3, 0x52, 0x5f, 0xe3, 0xd6, 0x71, 0x1c, 0x23, 0xe6, 0x32, 0xff, 0x99, 0x75, 0x8f, 0x22, 0x36, 0x2a, 0xf4, 0x35, 0x6a, 0x1c, 0xc7, 0xf1,
0x8f, 0xdb, 0xe5, 0x21, 0xc7, 0x47, 0xea, 0x6b, 0xdc, 0x29, 0x37, 0xe9, 0x1c, 0x79, 0xc8, 0x71, 0xa8, 0x59, 0x1c, 0x72, 0x74, 0xa4, 0xbe, 0x46, 0xad, 0x62, 0x93, 0xd6, 0x91, 0x87, 0x1c, 0x15,
0xa9, 0xaf, 0xf1, 0xd9, 0x91, 0x9b, 0x74, 0x97, 0x7c, 0x1d, 0xa9, 0xaf, 0x71, 0xaf, 0xdc, 0xa4, 0xfa, 0x1a, 0x9d, 0x1d, 0xb9, 0x49, 0x7b, 0xc9, 0xd7, 0x91, 0xfa, 0x1a, 0x75, 0x8a, 0x4d, 0x3a,
0x77, 0x2c, 0x5f, 0xa5, 0xbe, 0xc6, 0xef, 0x8f, 0xdc, 0xe4, 0x7c, 0xc9, 0xd7, 0xba, 0xbe, 0x9a, 0xc7, 0xf2, 0x55, 0xe8, 0x6b, 0xf4, 0xe1, 0xc8, 0x4d, 0xce, 0x97, 0x7c, 0xad, 0xeb, 0xab, 0xae,
0x2a, 0x42, 0xa8, 0x38, 0x55, 0xea, 0x2c, 0xe6, 0x2f, 0x29, 0x4d, 0x76, 0xd1, 0x2b, 0xe8, 0x40, 0x22, 0x84, 0x8a, 0x53, 0x85, 0xce, 0x22, 0xfe, 0x92, 0xd0, 0x78, 0x17, 0xbd, 0x9c, 0x0e, 0x24,
0x22, 0x19, 0xa4, 0xc1, 0xdc, 0x97, 0x31, 0x13, 0xa2, 0xde, 0x6f, 0x16, 0x58, 0xfb, 0xb1, 0x73, 0x92, 0x7e, 0xe2, 0xcf, 0xe6, 0x32, 0x62, 0x42, 0x54, 0x7b, 0xf5, 0x1c, 0x6b, 0x3f, 0x76, 0x86,
0xe4, 0x6b, 0xd3, 0xb9, 0xe6, 0x21, 0x4f, 0xeb, 0xc6, 0x06, 0x22, 0x85, 0x40, 0xbc, 0x1f, 0xf9, 0x7c, 0x65, 0x3a, 0x57, 0x3c, 0xe0, 0x49, 0xd5, 0xd8, 0x40, 0xa4, 0x10, 0x88, 0xf7, 0x23, 0xff,
0x4f, 0xd3, 0xb9, 0x99, 0xcd, 0x98, 0x2b, 0xc5, 0x12, 0xb9, 0x8c, 0xb3, 0xc6, 0x0e, 0xac, 0xc9, 0x69, 0x3a, 0xd7, 0xd3, 0x29, 0x73, 0xa5, 0x58, 0x22, 0x17, 0x71, 0xd6, 0xd8, 0x81, 0x35, 0x7e,
0x57, 0x08, 0x61, 0x6c, 0x8e, 0x55, 0x34, 0xe1, 0x09, 0x66, 0x7c, 0x81, 0x48, 0x06, 0x86, 0x15, 0x80, 0x60, 0x3a, 0x66, 0x33, 0x2c, 0xa3, 0x09, 0x8f, 0x31, 0xe5, 0x8b, 0xea, 0xfe, 0x8d, 0xc6,
0xa2, 0x4b, 0x62, 0x97, 0xaa, 0x69, 0x48, 0x6a, 0xc4, 0x83, 0x08, 0xee, 0x4a, 0x2c, 0xeb, 0xe3, 0x37, 0xd0, 0x45, 0x90, 0x09, 0x4f, 0x23, 0x4f, 0xe0, 0x06, 0x18, 0x81, 0x88, 0xae, 0x9e, 0x5d,
0x39, 0xbb, 0xd8, 0xcf, 0xcf, 0x64, 0x68, 0x3a, 0x7b, 0x48, 0xe5, 0x59, 0x30, 0x49, 0x41, 0x4c, 0xaa, 0x08, 0x40, 0xfe, 0x23, 0x1e, 0x04, 0x7b, 0x57, 0x62, 0x07, 0x10, 0xcd, 0x58, 0x97, 0xec,
0x84, 0xa7, 0xe4, 0x7e, 0x7c, 0x88, 0xde, 0x60, 0x95, 0xde, 0x55, 0xc8, 0x5e, 0xe9, 0x3a, 0xd5, 0x97, 0xda, 0x78, 0x60, 0x3a, 0xbb, 0x49, 0x65, 0x09, 0x33, 0x4e, 0x40, 0xa2, 0x84, 0x27, 0xe4,
0x43, 0xf8, 0x57, 0xab, 0xf8, 0x23, 0x3f, 0x08, 0x83, 0x44, 0x90, 0xbb, 0x8c, 0xe5, 0xc7, 0xf9, 0x6e, 0x74, 0x90, 0x5e, 0x7f, 0x85, 0xde, 0x65, 0xc0, 0x5e, 0xe9, 0x3a, 0xd5, 0xee, 0x81, 0x13,
0x31, 0x62, 0x77, 0xab, 0xc4, 0x1e, 0xa8, 0x9b, 0xf2, 0x1f, 0xc3, 0x7f, 0xd8, 0x2d, 0x1c, 0xf9, 0x5e, 0x6a, 0x74, 0x43, 0xe1, 0x0f, 0xe7, 0x7e, 0xe0, 0xc7, 0x82, 0xdc, 0xa6, 0x2c, 0x3b, 0xce,
0x02, 0x9d, 0xd8, 0x21, 0xfc, 0xb6, 0x99, 0x2b, 0xd7, 0x31, 0xc6, 0x6c, 0xca, 0xb9, 0x2c, 0x13, 0xcf, 0x11, 0xbb, 0x5d, 0x25, 0x76, 0x4f, 0xdd, 0x84, 0xff, 0x1c, 0xfe, 0xfd, 0x2a, 0xfe, 0xba,
0x2c, 0x91, 0x9c, 0xd0, 0x24, 0x09, 0xdf, 0xf2, 0x73, 0x89, 0x46, 0xbf, 0x19, 0xa8, 0xaa, 0xe1, 0x70, 0xe4, 0x0b, 0x34, 0x6d, 0x87, 0xf0, 0x9b, 0x66, 0x66, 0x07, 0x8e, 0x31, 0x62, 0x13, 0xce,
0x3e, 0x16, 0x92, 0xc6, 0x2e, 0x23, 0x9f, 0x83, 0xbc, 0x66, 0x30, 0x6e, 0x62, 0x95, 0x09, 0x83, 0x65, 0x91, 0x8b, 0x89, 0xe4, 0x84, 0xc6, 0x71, 0xf0, 0x96, 0x9d, 0x4b, 0xd4, 0x7a, 0x75, 0x5f,
0x62, 0x25, 0x84, 0x95, 0x03, 0x5b, 0x7f, 0xf9, 0x9c, 0xb3, 0xfe, 0x40, 0x17, 0x8c, 0x48, 0x3f, 0x15, 0x18, 0x77, 0x91, 0x90, 0x34, 0x72, 0x19, 0xf9, 0xe2, 0x67, 0xe5, 0x85, 0x71, 0x1d, 0xa9,
0x10, 0x4b, 0x74, 0x48, 0xb3, 0x2e, 0x7f, 0x66, 0x29, 0x12, 0x3d, 0x44, 0x06, 0xd5, 0x09, 0x2c, 0xa4, 0xe9, 0xe7, 0x2b, 0x01, 0xac, 0x1c, 0xd8, 0xfa, 0xeb, 0x97, 0x8c, 0xf5, 0x7b, 0xba, 0x60,
0x8c, 0x19, 0x0d, 0x65, 0x10, 0x31, 0x43, 0x31, 0x94, 0x3b, 0x1b, 0xc1, 0x62, 0x26, 0xcd, 0x57, 0x44, 0xce, 0x7d, 0xb1, 0x44, 0x87, 0x8c, 0xec, 0xf2, 0x67, 0x96, 0x20, 0xd1, 0x43, 0x64, 0x50,
0x0e, 0x10, 0x1a, 0xe7, 0x76, 0x56, 0x88, 0xe3, 0x0b, 0x93, 0x2f, 0x3c, 0x5d, 0x90, 0xe1, 0xc3, 0x9b, 0xc0, 0xc2, 0x88, 0xd1, 0x40, 0xfa, 0x21, 0x33, 0x14, 0x43, 0x99, 0x5f, 0x12, 0xac, 0x7b,
0x9f, 0x44, 0xe1, 0xa9, 0xe3, 0xc3, 0xe2, 0x23, 0xa0, 0x03, 0x2d, 0x68, 0xda, 0xd0, 0x86, 0x35, 0x92, 0x6c, 0xe5, 0x00, 0xa1, 0x51, 0x66, 0x66, 0xb9, 0x38, 0xbe, 0x32, 0xf9, 0xc2, 0x93, 0x05,
0xf2, 0xf0, 0x5e, 0x15, 0x6b, 0x4a, 0x50, 0x20, 0x55, 0x2c, 0x7f, 0x55, 0x13, 0x07, 0x24, 0xb5, 0x19, 0xdc, 0xff, 0x49, 0x14, 0x9e, 0x3a, 0x3e, 0x2c, 0x3e, 0x02, 0x3a, 0xd0, 0x82, 0xfe, 0x0e,
0x37, 0x10, 0x43, 0x97, 0xc7, 0x26, 0x56, 0xd9, 0xe0, 0x60, 0xad, 0x46, 0xa7, 0x45, 0x4e, 0xc4, 0x6d, 0x58, 0x23, 0x0f, 0xee, 0x54, 0x5d, 0xa7, 0x04, 0x05, 0x52, 0xc5, 0x4a, 0x59, 0xf5, 0x7b,
0xd5, 0xf5, 0x97, 0x5a, 0xbf, 0xa9, 0x41, 0x4a, 0xd0, 0x1c, 0x12, 0x8b, 0x6d, 0xd3, 0xb9, 0x4a, 0x40, 0x52, 0xfb, 0x0d, 0x31, 0x74, 0x25, 0x6d, 0x62, 0x41, 0x0e, 0xbe, 0xd8, 0xa8, 0xb5, 0x1a,
0xe5, 0x29, 0xb0, 0xb2, 0x01, 0x54, 0xd0, 0xb3, 0x4c, 0xa2, 0x39, 0x81, 0x9e, 0xc8, 0x2c, 0x46, 0xe4, 0x44, 0x5c, 0x5e, 0x7d, 0xad, 0xf4, 0xea, 0x1a, 0xa4, 0x00, 0xcd, 0x20, 0xb1, 0x2e, 0x37,
0xe0, 0xfe, 0x99, 0x90, 0x3c, 0x22, 0x58, 0x26, 0x2f, 0x51, 0x9b, 0x7a, 0x5d, 0x1f, 0x11, 0x0b, 0x9d, 0xcb, 0x44, 0x9e, 0x02, 0x2b, 0x1b, 0x40, 0x39, 0x3d, 0xcb, 0x24, 0x9a, 0x13, 0x68, 0x9f,
0x57, 0x0c, 0x5e, 0xd0, 0x7d, 0x38, 0xc6, 0x96, 0xd2, 0xec, 0xe6, 0xa8, 0x82, 0x6f, 0xf5, 0x54, 0xcc, 0x7c, 0x04, 0x91, 0x22, 0x15, 0x92, 0x87, 0x04, 0x2b, 0xea, 0x25, 0x6a, 0x5d, 0xaf, 0xeb,
0xbb, 0xab, 0x3f, 0x5d, 0x84, 0x3e, 0x64, 0xa0, 0x07, 0xac, 0x33, 0x0f, 0x68, 0xe2, 0xa6, 0x34, 0x23, 0x62, 0x8d, 0x8b, 0x71, 0x0e, 0x1a, 0x15, 0xc7, 0xd8, 0x52, 0xc5, 0x5d, 0x1f, 0x55, 0x1b,
0x6a, 0x49, 0xb1, 0xca, 0x8f, 0x41, 0x93, 0xd0, 0xcb, 0x54, 0xf9, 0xfb, 0xbe, 0x95, 0x3f, 0xab, 0xae, 0x9e, 0x6a, 0x77, 0xa1, 0xa8, 0xeb, 0xd5, 0xfb, 0x14, 0xf4, 0x80, 0x25, 0xe9, 0x01, 0x4d,
0xe0, 0xaf, 0xf3, 0xe1, 0xc3, 0x87, 0x0a, 0x1b, 0x06, 0xe8, 0xb5, 0x62, 0xe5, 0xca, 0xa8, 0xc9, 0x5c, 0x17, 0x46, 0x2d, 0x29, 0x36, 0x04, 0x11, 0x68, 0x12, 0xda, 0x9e, 0x32, 0x7f, 0xdf, 0xb7,
0x35, 0x72, 0x40, 0x38, 0xd0, 0xee, 0x53, 0xe2, 0xa7, 0x6c, 0x66, 0x97, 0x9d, 0xfe, 0x3c, 0x90, 0xf2, 0x67, 0xe5, 0xfc, 0xb5, 0x3e, 0x7e, 0xfc, 0x58, 0x62, 0xc3, 0x00, 0xbd, 0x96, 0xac, 0x5c,
0x7e, 0x36, 0x6d, 0xb8, 0x3c, 0x6a, 0x7e, 0x66, 0xde, 0xa7, 0x57, 0xfd, 0x84, 0xb3, 0x02, 0x6f, 0x19, 0x35, 0xb9, 0x42, 0x0e, 0x08, 0x07, 0xda, 0x3d, 0x4a, 0xe6, 0x09, 0x9b, 0xda, 0xc5, 0xa5,
0x73, 0xbc, 0x92, 0xf8, 0x7b, 0x1a, 0xd2, 0x78, 0x61, 0x3a, 0x6a, 0xbe, 0xdf, 0xa4, 0xce, 0x4f, 0xc0, 0xcc, 0x97, 0xf3, 0x74, 0x52, 0x73, 0x79, 0x58, 0xff, 0xc2, 0xbc, 0xcf, 0xaf, 0xfa, 0x09,
0xb8, 0xd5, 0x64, 0x11, 0x24, 0x48, 0xf0, 0x94, 0xcf, 0x4e, 0x05, 0xec, 0xc5, 0xd0, 0xac, 0x13, 0x67, 0x05, 0xde, 0x66, 0x78, 0x7b, 0xf1, 0xf7, 0x24, 0xa0, 0xd1, 0xc2, 0x74, 0xd4, 0x7c, 0xaf,
0x28, 0xe0, 0x99, 0x5c, 0xfa, 0xb4, 0xb1, 0xe3, 0xfc, 0x13, 0x7d, 0x7e, 0xb4, 0x3c, 0xa1, 0x44, 0x4e, 0x9d, 0x5f, 0x54, 0x70, 0x59, 0xf8, 0x31, 0x12, 0x3c, 0xe5, 0xd3, 0x53, 0x01, 0x7b, 0x31,
0x40, 0x3d, 0x0f, 0xe3, 0x5b, 0x45, 0x02, 0xc3, 0xab, 0x8d, 0x32, 0x75, 0x4d, 0x04, 0xdd, 0x96, 0x34, 0xeb, 0x18, 0x6a, 0x7d, 0x26, 0x97, 0x3e, 0x6d, 0xec, 0x38, 0xff, 0x58, 0x9f, 0x1f, 0x2d,
0x55, 0x11, 0x00, 0x52, 0x8c, 0xb8, 0xb7, 0x69, 0xbe, 0x0f, 0x66, 0xd5, 0xfa, 0xf0, 0x8a, 0x67, 0x4f, 0x28, 0x11, 0x50, 0xcf, 0xc3, 0xf8, 0x56, 0x92, 0xc0, 0xe0, 0x72, 0xa3, 0xa2, 0x5d, 0x13,
0x18, 0x08, 0xf4, 0x40, 0x6f, 0x97, 0x85, 0x42, 0x39, 0x31, 0x81, 0x46, 0x0d, 0x1c, 0x7f, 0x7c, 0x41, 0xbb, 0x61, 0x95, 0x04, 0x80, 0x14, 0x43, 0xee, 0x6d, 0x9a, 0xef, 0xbd, 0x59, 0xb6, 0x3e,
0x3b, 0xd8, 0x05, 0x04, 0x11, 0xc6, 0xc8, 0xa1, 0x86, 0x7b, 0xc0, 0x3a, 0x45, 0xd6, 0xd9, 0x05, 0xbc, 0x0d, 0x1a, 0xf8, 0x02, 0x3d, 0xd0, 0xdb, 0x65, 0xa1, 0x50, 0x79, 0x8c, 0xa1, 0xa7, 0x03,
0x00, 0xbe, 0xa0, 0x0c, 0x08, 0xf7, 0x32, 0x76, 0x01, 0x41, 0x55, 0x30, 0x0c, 0xa2, 0x88, 0xa5, 0xc7, 0x1f, 0xdd, 0xf4, 0x77, 0x01, 0x41, 0x84, 0x31, 0x32, 0xa8, 0xc1, 0x1e, 0xb0, 0x56, 0x9e,
0xe4, 0x1d, 0x29, 0xa1, 0x77, 0x3a, 0x18, 0x70, 0x56, 0x02, 0xfd, 0xb1, 0xc3, 0x4d, 0x28, 0x31, 0xa0, 0x76, 0x01, 0x80, 0x2f, 0x28, 0x03, 0xc2, 0xbd, 0x8c, 0x5d, 0x40, 0x50, 0x40, 0x0c, 0xfc,
0xd6, 0x0d, 0x62, 0xc7, 0xd5, 0x0f, 0x43, 0x8f, 0x3e, 0xf5, 0xa2, 0xd7, 0x26, 0x28, 0xa5, 0x62, 0x30, 0x64, 0x09, 0x79, 0x4f, 0x0a, 0xe8, 0x9d, 0x0e, 0x06, 0x9c, 0x15, 0x40, 0x3f, 0x76, 0xb8,
0x1a, 0xda, 0xdb, 0x83, 0x78, 0xc6, 0xd1, 0x3e, 0x0c, 0x15, 0x44, 0x20, 0x20, 0x81, 0x79, 0x54, 0x09, 0x25, 0xc6, 0xba, 0x41, 0xec, 0xb8, 0x25, 0x62, 0xe8, 0xd1, 0xa7, 0x5e, 0xf8, 0x5a, 0x07,
0x6d, 0xfa, 0xf1, 0x80, 0xcf, 0x59, 0xd6, 0xaa, 0x4a, 0x49, 0xa4, 0x93, 0xec, 0x27, 0x9e, 0x82, 0xa5, 0x94, 0x4c, 0x43, 0x7b, 0xbb, 0x1f, 0x4d, 0x39, 0xda, 0x87, 0xa1, 0x82, 0x08, 0x04, 0x24,
0x75, 0x01, 0x08, 0x99, 0x96, 0x25, 0xc3, 0x01, 0x1f, 0xfb, 0x54, 0x64, 0xc1, 0x5c, 0xc7, 0x65, 0x30, 0x8f, 0xb2, 0x4d, 0x3f, 0x1e, 0xf0, 0x39, 0xcb, 0x5a, 0x55, 0x29, 0x09, 0x55, 0x8e, 0x35,
0x94, 0x24, 0x73, 0x1a, 0x45, 0x14, 0xba, 0x96, 0x14, 0x53, 0x34, 0xc8, 0xe3, 0x50, 0xd8, 0xbc, 0x3e, 0xf3, 0x04, 0xac, 0x0b, 0x40, 0xc8, 0xa4, 0xa8, 0x2e, 0x0e, 0xf8, 0xd8, 0xe7, 0x2c, 0x09,
0xcd, 0x09, 0x15, 0x01, 0x98, 0x60, 0x4b, 0xc9, 0x67, 0x33, 0xe8, 0x34, 0x2b, 0xa7, 0xfb, 0xe3, 0xe6, 0x3a, 0x2e, 0xa2, 0x24, 0x99, 0xd1, 0x30, 0xa4, 0xd0, 0xe0, 0x24, 0x98, 0xa2, 0x41, 0x1e,
0xeb, 0xd6, 0xd3, 0x9d, 0xb6, 0xbb, 0xdd, 0xfc, 0x80, 0x6a, 0x64, 0x2c, 0x4d, 0x16, 0x22, 0xb9, 0x87, 0xc2, 0xe6, 0x4d, 0x46, 0x28, 0x0f, 0xc0, 0x04, 0xbb, 0x4f, 0x3e, 0x9d, 0x42, 0x53, 0x5a,
0x4e, 0xd0, 0xbf, 0x73, 0xc8, 0x65, 0xe4, 0x4a, 0x88, 0x00, 0x33, 0x84, 0x4e, 0x3a, 0x37, 0x51, 0x3a, 0xdd, 0x8f, 0x87, 0xad, 0xa7, 0x3b, 0x6d, 0xb6, 0xdb, 0xd9, 0x01, 0xd5, 0xc8, 0x58, 0x9a,
0x16, 0x52, 0xc9, 0xf2, 0x14, 0xae, 0x2f, 0x1e, 0x0f, 0xb9, 0xd6, 0x55, 0x9e, 0x74, 0x34, 0x4e, 0x2c, 0x44, 0x72, 0x9d, 0xa0, 0xff, 0xe0, 0x90, 0xcb, 0xc8, 0xa5, 0x10, 0x3e, 0x66, 0x08, 0x9d,
0x10, 0x3f, 0x73, 0x9d, 0x2d, 0xd5, 0x72, 0xe5, 0xa4, 0xd8, 0xa4, 0x95, 0xf5, 0xd8, 0xd5, 0xbd, 0x74, 0xae, 0xc3, 0x34, 0xa0, 0x92, 0x65, 0x29, 0x5c, 0xdf, 0x51, 0x1e, 0x72, 0xad, 0xcb, 0x2c,
0x62, 0x31, 0x64, 0xf1, 0x5c, 0xfa, 0x60, 0xad, 0x6d, 0x9d, 0x75, 0x06, 0xe1, 0x5b, 0xbc, 0x50, 0xe9, 0x68, 0x1c, 0x3f, 0x7a, 0xe6, 0x3a, 0x5b, 0xaa, 0xe5, 0xd2, 0x49, 0xb1, 0x9f, 0x2b, 0x8a,
0xdc, 0xf4, 0xa7, 0x8e, 0xa1, 0xde, 0xea, 0xe4, 0xe1, 0xdb, 0xe3, 0x23, 0xc1, 0x3a, 0x0b, 0x8b, 0x86, 0xcb, 0x3b, 0xc5, 0x62, 0xc0, 0xa2, 0x99, 0x9c, 0x83, 0xb5, 0x36, 0x75, 0xd6, 0xe9, 0x07,
0x02, 0x81, 0x7d, 0x1d, 0x0d, 0x43, 0xbc, 0x44, 0x8d, 0xd1, 0xe3, 0x20, 0xad, 0x02, 0x61, 0x96, 0x6f, 0xd1, 0x42, 0x71, 0xd3, 0x9b, 0x38, 0x86, 0x7a, 0xab, 0x92, 0xfb, 0x6f, 0x8f, 0x8f, 0x04,
0xc6, 0x34, 0x24, 0x3e, 0x17, 0x52, 0xa8, 0x78, 0x61, 0x3c, 0x62, 0x02, 0x8c, 0xe8, 0x1b, 0x09, 0x4b, 0x32, 0x2c, 0x0a, 0x04, 0xb6, 0x80, 0x34, 0x08, 0xf0, 0xbe, 0x35, 0x42, 0x8f, 0x83, 0xb4,
0x22, 0x08, 0x13, 0x00, 0xe6, 0xa3, 0x4e, 0x44, 0x02, 0x99, 0x1c, 0xc2, 0x5f, 0xac, 0xaa, 0x9b, 0x0a, 0x84, 0x59, 0x12, 0xd1, 0x80, 0xcc, 0xb9, 0x90, 0x42, 0xc5, 0x0b, 0xe3, 0x11, 0x13, 0x60,
0x99, 0x9a, 0xbd, 0x99, 0x8c, 0xce, 0xdb, 0xbd, 0x1e, 0x44, 0xae, 0xa9, 0x53, 0xa8, 0x9f, 0x4c, 0x48, 0xdf, 0x88, 0x1f, 0x42, 0x98, 0x00, 0xb0, 0x39, 0xea, 0x44, 0xc4, 0x90, 0xc9, 0x21, 0xfc,
0x99, 0xc0, 0xa0, 0x26, 0xc0, 0x9c, 0x45, 0x1d, 0x6f, 0x3c, 0xde, 0x48, 0x26, 0x18, 0x0c, 0x58, 0x45, 0xaa, 0xba, 0x99, 0xaa, 0xd9, 0xeb, 0xf1, 0xf0, 0xbc, 0xd9, 0xe9, 0x40, 0xe4, 0x9a, 0x38,
0x8e, 0x06, 0x2f, 0x82, 0xa5, 0x28, 0x23, 0x41, 0x28, 0x44, 0x14, 0x82, 0xba, 0x6a, 0x28, 0xfc, 0xb9, 0xfa, 0xc9, 0x84, 0x09, 0x0c, 0x6a, 0x02, 0xcc, 0x19, 0x4a, 0x34, 0x1e, 0x41, 0xda, 0x4e,
0x13, 0x50, 0x1c, 0xf2, 0x23, 0x61, 0xa3, 0xf0, 0xad, 0x5e, 0x72, 0x4a, 0x01, 0x03, 0xc6, 0x1e, 0x05, 0x83, 0x01, 0xcb, 0xd0, 0xe0, 0x45, 0xb0, 0x04, 0x65, 0x24, 0x08, 0x85, 0x88, 0x42, 0x50,
0xee, 0x88, 0x6c, 0x03, 0x95, 0x48, 0x9d, 0x0b, 0x29, 0x23, 0x27, 0x98, 0x5d, 0xf1, 0x7c, 0xb5, 0x57, 0x35, 0x85, 0x7f, 0x02, 0x8a, 0x43, 0x7e, 0x24, 0x6c, 0x14, 0xbc, 0x55, 0x0b, 0x4e, 0x29,
0x22, 0x6f, 0xde, 0x71, 0x0c, 0xee, 0xc6, 0x16, 0x31, 0x6a, 0x29, 0x0e, 0xee, 0x36, 0xa4, 0xb8, 0x60, 0xc0, 0xd8, 0xc3, 0x1d, 0x91, 0x6d, 0xa0, 0x12, 0xaa, 0x73, 0x21, 0x65, 0xe4, 0x04, 0xb3,
0xed, 0x56, 0x60, 0x30, 0x32, 0x0b, 0x05, 0x1e, 0x91, 0x7b, 0xce, 0xad, 0xd5, 0x0b, 0x02, 0x1d, 0x2b, 0x9e, 0xaf, 0x92, 0xe7, 0xcd, 0x5b, 0x8e, 0xc1, 0xdd, 0xd8, 0x22, 0x46, 0x2d, 0xc5, 0xfe,
0xe7, 0x94, 0x31, 0x90, 0xab, 0x4c, 0xfa, 0xc0, 0xf8, 0x82, 0xc5, 0x4b, 0xa6, 0xf2, 0x1d, 0x7e, 0xed, 0x86, 0x14, 0xb7, 0x5d, 0x20, 0xf4, 0x87, 0x66, 0xae, 0xc0, 0x23, 0x72, 0xcf, 0xb9, 0xb5,
0x5b, 0x67, 0xa4, 0x53, 0x96, 0x41, 0xd7, 0x21, 0xa3, 0xa9, 0x3a, 0x9d, 0x42, 0x24, 0xb3, 0x80, 0x7a, 0x97, 0xa0, 0xe3, 0x9c, 0x32, 0x06, 0x72, 0x99, 0xca, 0x39, 0x30, 0xbe, 0x60, 0xd1, 0x92,
0x85, 0xaa, 0x16, 0xf2, 0xb4, 0xa3, 0x34, 0x88, 0xaa, 0x03, 0x8e, 0x0d, 0x0b, 0x53, 0x34, 0x89, 0xa9, 0x6c, 0x87, 0xdf, 0xd7, 0x19, 0x69, 0x15, 0x65, 0xd0, 0x55, 0xc0, 0x68, 0xa2, 0x4e, 0xa7,
0x2d, 0x21, 0x61, 0x82, 0xf7, 0x30, 0x65, 0x48, 0x50, 0x77, 0x31, 0x68, 0x36, 0xda, 0xb0, 0x75, 0x10, 0xc9, 0xd4, 0x67, 0x81, 0xaa, 0x85, 0x3c, 0xed, 0x28, 0x35, 0xa2, 0xea, 0x80, 0x63, 0xc3,
0x31, 0x85, 0xef, 0x07, 0x9c, 0xef, 0xe1, 0x9b, 0xe6, 0x7b, 0x90, 0x02, 0xaf, 0x69, 0xd5, 0xf8, 0xc2, 0x04, 0x4d, 0x62, 0x4b, 0x48, 0x18, 0xe3, 0x95, 0x4d, 0x11, 0x12, 0xd4, 0xb5, 0x0d, 0x9a,
0x57, 0x25, 0xff, 0x30, 0x39, 0x4a, 0xf2, 0x0f, 0xdf, 0x46, 0x5f, 0xc7, 0x8f, 0xdb, 0xd3, 0x4a, 0x8d, 0x36, 0x6c, 0x5d, 0x4c, 0xe1, 0xfb, 0x01, 0xe7, 0xbb, 0xff, 0xa6, 0xf9, 0xee, 0x27, 0xc0,
0x45, 0xfa, 0x15, 0x91, 0xa3, 0xfd, 0x3f, 0xfa, 0x9a, 0x6b, 0xe2, 0x82, 0xf7, 0x42, 0x27, 0x10, 0x6b, 0x52, 0x36, 0xfe, 0x55, 0xc9, 0xdf, 0x8f, 0x8f, 0x92, 0xfc, 0xfd, 0xb7, 0xe1, 0xc3, 0xe8,
0xd0, 0x10, 0x8c, 0x2d, 0x45, 0xcb, 0xc3, 0xb6, 0x00, 0xb2, 0x38, 0x98, 0x0f, 0xe4, 0x73, 0x30, 0x71, 0x7b, 0x5a, 0x29, 0x49, 0xbf, 0x24, 0x72, 0xb4, 0xff, 0xc7, 0xb9, 0xe6, 0x9a, 0xb8, 0xe0,
0xab, 0x0c, 0x2b, 0xcc, 0xdc, 0xd0, 0xc0, 0xff, 0xb4, 0x21, 0x7e, 0x61, 0x08, 0x52, 0x58, 0x97, 0xbd, 0xd0, 0x33, 0xf8, 0x34, 0x00, 0x63, 0x4b, 0xd0, 0xf2, 0xb0, 0x81, 0x80, 0x2c, 0x0e, 0xe6,
0xa2, 0x94, 0xc0, 0x26, 0x50, 0x86, 0x79, 0x64, 0xc6, 0x11, 0x99, 0xc3, 0x42, 0x5a, 0x18, 0xf2, 0x03, 0xf9, 0x1c, 0xcc, 0x2a, 0xc5, 0x0a, 0x33, 0x33, 0x34, 0xf0, 0x3f, 0x6d, 0x88, 0x5f, 0x19,
0x4f, 0x85, 0x07, 0x7c, 0x17, 0x68, 0xbe, 0x11, 0xdb, 0x2b, 0x80, 0x6f, 0xdf, 0x27, 0x37, 0xe3, 0x82, 0xe4, 0xd6, 0xa5, 0x28, 0xc5, 0xb0, 0x09, 0x94, 0x61, 0x1e, 0x99, 0x72, 0x44, 0xe6, 0xb0,
0x35, 0x21, 0x9c, 0x59, 0x9a, 0xf5, 0x51, 0xbe, 0x47, 0x45, 0xd8, 0xc5, 0xd6, 0x65, 0x0c, 0x00, 0x90, 0xe4, 0x86, 0xfc, 0x4b, 0xee, 0x01, 0xdf, 0x05, 0x9a, 0x6f, 0xc8, 0xf6, 0x0a, 0xe0, 0xdb,
0xe1, 0x5c, 0x4d, 0xd6, 0xe5, 0xd8, 0x3b, 0xd3, 0x24, 0xae, 0xc3, 0x00, 0x8f, 0x78, 0x3f, 0xdc, 0xf7, 0xf1, 0xf5, 0x68, 0x4d, 0x08, 0x67, 0x96, 0x66, 0x7d, 0x98, 0xed, 0x51, 0x12, 0x76, 0xbe,
0x1a, 0x43, 0x0a, 0xf4, 0xeb, 0xfb, 0xa1, 0xbe, 0xd8, 0xaa, 0x72, 0x90, 0xdb, 0xeb, 0x23, 0x4f, 0x75, 0x11, 0x03, 0x40, 0x38, 0x97, 0xe3, 0x75, 0x39, 0x76, 0xce, 0x34, 0x89, 0xab, 0xc0, 0xc7,
0x02, 0x77, 0x1f, 0x85, 0xe1, 0x86, 0x12, 0x55, 0x32, 0xb9, 0xc5, 0x6b, 0xa3, 0xc3, 0xd8, 0xb7, 0x23, 0xde, 0x0d, 0xb6, 0xc6, 0x90, 0x1c, 0xfd, 0xea, 0x6e, 0xa0, 0xef, 0xc0, 0xca, 0x1c, 0x64,
0x9b, 0x21, 0x0c, 0xa5, 0x3e, 0xca, 0xa6, 0x50, 0xae, 0xfb, 0xd5, 0x66, 0xea, 0x80, 0xe9, 0x0d, 0xf6, 0xfa, 0xc8, 0x63, 0xdf, 0xdd, 0x47, 0x61, 0xb0, 0xa1, 0x44, 0x95, 0x4c, 0x6e, 0xf0, 0x86,
0x1e, 0x7e, 0xa0, 0x73, 0xf8, 0x31, 0x9f, 0x89, 0xfe, 0x91, 0x72, 0x8b, 0xcb, 0x28, 0x7b, 0x58, 0xe9, 0x30, 0xf6, 0xcd, 0x66, 0x08, 0x43, 0xa9, 0x0f, 0xd3, 0x09, 0x94, 0xeb, 0xf3, 0x72, 0x33,
0xf3, 0x98, 0x95, 0xe6, 0x4b, 0xc7, 0x60, 0xe0, 0xe5, 0x2f, 0x9e, 0x11, 0x97, 0xa2, 0xdf, 0x42, 0x75, 0xc0, 0xf4, 0xfa, 0xf7, 0x3f, 0xd1, 0x39, 0xfc, 0x9c, 0xcf, 0x84, 0xff, 0x48, 0xb9, 0xc5,
0xa0, 0x42, 0x33, 0x82, 0x94, 0xe8, 0x41, 0x57, 0x76, 0x3f, 0x52, 0xa1, 0x0b, 0x67, 0x42, 0xcc, 0x65, 0x94, 0x3d, 0xac, 0x79, 0xcc, 0x4a, 0xf3, 0xa5, 0x63, 0x30, 0xf0, 0xf2, 0x17, 0x4f, 0x89,
0x91, 0x44, 0x1b, 0x37, 0x10, 0x54, 0x73, 0xbf, 0x5c, 0x4d, 0x21, 0x1d, 0xff, 0x82, 0x11, 0x4f, 0x4b, 0xd1, 0x6f, 0x21, 0x50, 0xa1, 0x19, 0x41, 0x4a, 0xf4, 0xa0, 0x2b, 0xbb, 0x1b, 0xaa, 0xd0,
0xe5, 0x83, 0x3c, 0xd6, 0xfa, 0x10, 0xc1, 0xe1, 0x28, 0x0d, 0xa3, 0x28, 0xfe, 0x47, 0x1c, 0x42, 0x85, 0x33, 0x01, 0xe6, 0x48, 0xa2, 0x8d, 0x1b, 0x08, 0xaa, 0xb9, 0x5f, 0x2f, 0xa1, 0x67, 0x95,
0x39, 0xc6, 0x75, 0x4d, 0x64, 0xcd, 0x79, 0xee, 0x3e, 0xef, 0xcd, 0xde, 0x50, 0x8e, 0x3a, 0x04, 0xbf, 0x62, 0xc4, 0x53, 0xf9, 0x20, 0x8b, 0xb5, 0x73, 0x88, 0xe0, 0x70, 0x94, 0x9a, 0x91, 0x17,
0x2d, 0xfc, 0xad, 0x12, 0x8c, 0xee, 0xee, 0xb7, 0xe3, 0x59, 0xd6, 0x5a, 0xde, 0xc7, 0x74, 0x7f, 0xff, 0x43, 0x0e, 0xa1, 0x1c, 0xe3, 0xba, 0x26, 0xb2, 0xe6, 0x3c, 0xb7, 0x5f, 0xf6, 0x66, 0x6f,
0x28, 0xbf, 0xdd, 0x8d, 0xb4, 0x56, 0xc0, 0x13, 0xe3, 0x3a, 0x28, 0x44, 0x77, 0x41, 0x7b, 0x15, 0x28, 0x47, 0x1d, 0x82, 0x16, 0xfe, 0x56, 0x0a, 0x46, 0xb7, 0x77, 0xdb, 0xf1, 0x2c, 0x6b, 0x2d,
0x79, 0x07, 0x9d, 0xbb, 0x41, 0xbe, 0xc6, 0xcd, 0xaf, 0xb3, 0x59, 0xfd, 0x00, 0x28, 0x14, 0x0d, 0xef, 0x63, 0xba, 0x3f, 0x94, 0xdf, 0x6e, 0x87, 0x5a, 0x2b, 0xe0, 0x89, 0x51, 0x15, 0x14, 0xa2,
0x64, 0xe5, 0x56, 0x82, 0xac, 0x5c, 0x26, 0xec, 0x62, 0xe8, 0x1a, 0x50, 0xd4, 0x5d, 0x84, 0xca, 0xbb, 0xa0, 0xbd, 0x8a, 0xbc, 0x7d, 0xc0, 0x8e, 0xfd, 0x21, 0xaa, 0x3f, 0x4c, 0xa7, 0x07, 0x9a,
0x0f, 0x20, 0xb8, 0x41, 0xa1, 0x8f, 0x8b, 0x8d, 0xdb, 0xdb, 0x3b, 0x6b, 0x23, 0xee, 0xe7, 0x51, 0xfb, 0x5b, 0x28, 0x1a, 0xc8, 0xca, 0x05, 0x06, 0x59, 0xb9, 0x77, 0xd8, 0xc5, 0xd0, 0x15, 0xa0,
0x46, 0x54, 0xaa, 0x7b, 0x2c, 0x14, 0x1c, 0xd2, 0xa8, 0xc8, 0xbf, 0xb5, 0x11, 0xb8, 0x7e, 0x08, 0xa8, 0x6b, 0x0b, 0x95, 0x1f, 0x40, 0x70, 0xfd, 0x5c, 0x1f, 0xdd, 0x8d, 0x8b, 0xde, 0x5b, 0x6b,
0x7d, 0xe3, 0x2e, 0x7a, 0x13, 0xdb, 0xd8, 0x83, 0xde, 0x39, 0x8c, 0xbe, 0xc4, 0x2e, 0x42, 0xe6, 0x23, 0xee, 0x67, 0x51, 0x46, 0x94, 0xaa, 0x7b, 0x2c, 0x14, 0x1c, 0x52, 0x2b, 0xc9, 0xbf, 0xb1,
0x48, 0xdd, 0x5b, 0xa0, 0xa9, 0x25, 0x99, 0xf0, 0xc3, 0x20, 0x5e, 0x14, 0x4e, 0xc8, 0xe3, 0x15, 0x11, 0xb8, 0x7e, 0x0a, 0x7d, 0xe3, 0xda, 0x7a, 0x13, 0xdb, 0xd8, 0x83, 0xde, 0x3a, 0x8c, 0xbe,
0xf3, 0x05, 0x51, 0xcf, 0xc0, 0x3f, 0x60, 0x06, 0x72, 0xb7, 0xa0, 0xcf, 0x79, 0xc3, 0x9c, 0xd0, 0xc4, 0xce, 0x43, 0xe6, 0x50, 0xdd, 0x5b, 0xa0, 0xa9, 0xc5, 0xa9, 0x98, 0x07, 0x7e, 0xb4, 0xc8,
0xf9, 0x32, 0x0a, 0x1a, 0x27, 0x2f, 0xbe, 0x4a, 0x58, 0x29, 0x94, 0x02, 0x45, 0x68, 0x8d, 0xe7, 0x9d, 0x90, 0x47, 0x2b, 0xe6, 0x0b, 0xa2, 0x9e, 0x82, 0x7f, 0xc0, 0x0c, 0xe4, 0x6e, 0x41, 0x9f,
0xb5, 0x42, 0xf0, 0x50, 0x39, 0xc9, 0x0c, 0x2d, 0x08, 0xaf, 0xa3, 0x4b, 0xe6, 0x82, 0x04, 0x4b, 0xb3, 0x86, 0x39, 0xa6, 0xb3, 0x65, 0x14, 0x34, 0x4e, 0x5e, 0xe6, 0x2a, 0x61, 0x25, 0x50, 0x0a,
0x66, 0x5d, 0xe7, 0x6b, 0x67, 0x00, 0xba, 0xd3, 0x2c, 0x08, 0x3d, 0xfc, 0x98, 0x02, 0x90, 0xca, 0xe4, 0xa1, 0x35, 0x9a, 0x55, 0x72, 0xc1, 0x43, 0xe5, 0x24, 0x53, 0xb4, 0x20, 0xbc, 0xb9, 0x2e,
0xd5, 0x26, 0x2c, 0x85, 0x60, 0xae, 0x9c, 0x6c, 0x40, 0x33, 0x8f, 0xa4, 0x50, 0x78, 0x55, 0x9b, 0x98, 0xf3, 0x63, 0x2c, 0x99, 0x75, 0x9d, 0xaf, 0x9d, 0x01, 0xe8, 0x4e, 0x52, 0x3f, 0xf0, 0xf0,
0x88, 0xc1, 0x70, 0xa3, 0x89, 0x68, 0xb5, 0xba, 0x10, 0x65, 0xf0, 0x69, 0x59, 0x3b, 0x6b, 0xf6, 0xbb, 0x0b, 0x40, 0x2a, 0x57, 0x1b, 0xb3, 0x04, 0x82, 0xb9, 0x72, 0xb2, 0x3e, 0x4d, 0x3d, 0x92,
0x76, 0xc7, 0x82, 0x28, 0x8a, 0x4f, 0xcb, 0xda, 0x59, 0xfc, 0xf7, 0x2c, 0xe8, 0x9a, 0xf1, 0xb9, 0x40, 0xe1, 0x55, 0x6e, 0x22, 0xfa, 0x83, 0x8d, 0x26, 0xa2, 0xd1, 0x68, 0x43, 0x94, 0xc1, 0xa7,
0x87, 0x90, 0xf6, 0x12, 0x7c, 0xee, 0x26, 0xd4, 0x7d, 0xdf, 0x43, 0x18, 0x78, 0xee, 0x21, 0xf4, 0x65, 0xed, 0xac, 0xd9, 0x9b, 0x2d, 0x0b, 0xa2, 0x28, 0x3e, 0x2d, 0x6b, 0x67, 0xf1, 0xdf, 0xb1,
0xa1, 0xdd, 0x82, 0xde, 0x00, 0x9f, 0xbb, 0x09, 0xb5, 0x2c, 0xb5, 0x9b, 0xfa, 0xd9, 0x43, 0xaa, 0xa0, 0x6b, 0xc6, 0xe7, 0x1e, 0x42, 0xda, 0x4b, 0xf0, 0xb9, 0x9b, 0x50, 0xfb, 0x43, 0x07, 0x61,
0xa5, 0x99, 0x6a, 0x55, 0xb9, 0x5a, 0xeb, 0x31, 0x20, 0x6c, 0xfd, 0xc6, 0x58, 0x82, 0x75, 0x99, 0xe0, 0xb9, 0x87, 0xd0, 0xc7, 0x66, 0x03, 0x7a, 0x03, 0x7c, 0xee, 0x26, 0xd4, 0xb0, 0xd4, 0x6e,
0x96, 0x15, 0x46, 0x50, 0x4c, 0x83, 0xf7, 0x51, 0x92, 0xf2, 0xe7, 0x06, 0x99, 0x70, 0xa8, 0xab, 0xea, 0x67, 0x0f, 0xa9, 0x86, 0x66, 0xaa, 0x51, 0xe6, 0x6a, 0xad, 0xc7, 0x80, 0xb0, 0xf5, 0x3b,
0xa7, 0x9c, 0xa6, 0x9e, 0xae, 0x11, 0x21, 0x0f, 0x12, 0x91, 0x25, 0xea, 0x23, 0x98, 0x0f, 0xee, 0x63, 0x31, 0xd6, 0x65, 0x5a, 0x56, 0x18, 0x41, 0x31, 0x0d, 0xde, 0x85, 0x71, 0xc2, 0x9f, 0x6b,
0xa8, 0xf4, 0x51, 0x5c, 0xd0, 0xa4, 0xd5, 0x6f, 0x43, 0x47, 0x7c, 0x4d, 0xda, 0xfd, 0x31, 0xc9, 0x64, 0xcc, 0xa1, 0xae, 0x9e, 0x70, 0x9a, 0x78, 0xba, 0x46, 0x84, 0x3c, 0x48, 0x44, 0x1a, 0xab,
0x58, 0xf9, 0x50, 0x85, 0x5f, 0xcc, 0xe0, 0x07, 0x3f, 0xaa, 0xe1, 0x17, 0x36, 0xfc, 0x37, 0x82, 0xef, 0x65, 0x73, 0x70, 0x47, 0xa5, 0x8f, 0xfc, 0x82, 0x26, 0x29, 0x7f, 0x46, 0x3a, 0xe2, 0xc3,
0xff, 0x03, 0x5c, 0xb2, 0xe5, 0xf2, 0x56, 0x20, 0x00, 0x00 0xd3, 0xee, 0xef, 0x4e, 0xc6, 0xca, 0x37, 0x2d, 0xfc, 0xb8, 0x06, 0x3f, 0xf8, 0xfd, 0x0d, 0x3f,
0xc6, 0xe1, 0x7f, 0x1c, 0xfc, 0x1f, 0x60, 0xa7, 0x58, 0xea, 0x81, 0x20, 0x00, 0x00
}; };

File diff suppressed because it is too large Load Diff

View File

@ -88,7 +88,7 @@ byte relativeChange(byte property, int8_t amount, byte lowerBoundary, byte highe
void changeEffect(uint8_t fx) void changeEffect(uint8_t fx)
{ {
if (strip.applyToAllSelected) { if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i); WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
@ -103,7 +103,7 @@ void changeEffect(uint8_t fx)
void changePalette(uint8_t pal) void changePalette(uint8_t pal)
{ {
if (strip.applyToAllSelected) { if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i); WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
@ -121,7 +121,7 @@ void changeEffectSpeed(int8_t amount)
if (effectCurrent != 0) { if (effectCurrent != 0) {
int16_t new_val = (int16_t) effectSpeed + amount; int16_t new_val = (int16_t) effectSpeed + amount;
effectSpeed = (byte)constrain(new_val,0,255); effectSpeed = (byte)constrain(new_val,0,255);
if (strip.applyToAllSelected) { if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i); WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
@ -145,7 +145,7 @@ void changeEffectSpeed(int8_t amount)
col[0] = fastled_col.red; col[0] = fastled_col.red;
col[1] = fastled_col.green; col[1] = fastled_col.green;
col[2] = fastled_col.blue; col[2] = fastled_col.blue;
if (strip.applyToAllSelected) { if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i); WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
@ -167,7 +167,7 @@ void changeEffectIntensity(int8_t amount)
if (effectCurrent != 0) { if (effectCurrent != 0) {
int16_t new_val = (int16_t) effectIntensity + amount; int16_t new_val = (int16_t) effectIntensity + amount;
effectIntensity = (byte)constrain(new_val,0,255); effectIntensity = (byte)constrain(new_val,0,255);
if (strip.applyToAllSelected) { if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i); WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
@ -189,7 +189,7 @@ void changeEffectIntensity(int8_t amount)
col[0] = fastled_col.red; col[0] = fastled_col.red;
col[1] = fastled_col.green; col[1] = fastled_col.green;
col[2] = fastled_col.blue; col[2] = fastled_col.blue;
if (strip.applyToAllSelected) { if (irApplyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i); WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected()) continue; if (!seg.isActive() || !seg.isSelected()) continue;
@ -208,7 +208,7 @@ void changeEffectIntensity(int8_t amount)
void changeColor(uint32_t c, int16_t cct=-1) void changeColor(uint32_t c, int16_t cct=-1)
{ {
if (strip.applyToAllSelected) { if (irApplyToAllSelected) {
// main segment may not be selected! // main segment may not be selected!
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i); WS2812FX::Segment& seg = strip.getSegment(i);
@ -262,8 +262,6 @@ void decodeIR(uint32_t code)
} }
if (code > 0xFFFFFF) return; //invalid code if (code > 0xFFFFFF) return; //invalid code
strip.applyToAllSelected = irApplyToAllSelected;
switch (irEnabled) { switch (irEnabled) {
case 1: case 1:
if (code > 0xF80000) { if (code > 0xF80000) {
@ -283,8 +281,6 @@ void decodeIR(uint32_t code)
//case 8: return; // ir.json file, handled above switch statement //case 8: return; // ir.json file, handled above switch statement
} }
strip.applyToAllSelected = false;
if (nightlightActive && bri == 0) nightlightActive = false; if (nightlightActive && bri == 0) nightlightActive = false;
colorUpdated(CALL_MODE_BUTTON); //for notifier, IR is considered a button input colorUpdated(CALL_MODE_BUTTON); //for notifier, IR is considered a button input
} }
@ -643,9 +639,6 @@ void decodeIRJson(uint32_t code)
cmdStr = fdo["cmd"].as<String>(); cmdStr = fdo["cmd"].as<String>();
jsonCmdObj = fdo["cmd"]; //object jsonCmdObj = fdo["cmd"]; //object
// command is JSON object
//allow applyPreset() to reuse JSON buffer, or it would alloc. a second buffer and run out of mem.
//fileDoc = &doc; // used for applying presets (presets.cpp)
if (jsonCmdObj.isNull()) // we could also use: fdo["cmd"].is<String>() if (jsonCmdObj.isNull()) // we could also use: fdo["cmd"].is<String>()
{ {
if (cmdStr.startsWith("!")) { if (cmdStr.startsWith("!")) {

View File

@ -12,8 +12,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;
@ -68,7 +67,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;
@ -95,9 +93,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())
@ -151,26 +147,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 && fx != 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()) {
@ -225,8 +215,9 @@ 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);
} }
//send UDP if not in preset and something changed that is not just selection
return; // seg.differs(prev); 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)
@ -234,7 +225,6 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
{ {
DEBUG_PRINTLN(F("Deserializing state")); DEBUG_PRINTLN(F("Deserializing state"));
strip.applyToAllSelected = false;
bool stateResponse = root[F("v")] | false; bool stateResponse = root[F("v")] | false;
getVal(root["bri"], &bri); getVal(root["bri"], &bri);
@ -295,9 +285,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"];
@ -308,11 +296,9 @@ 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;
@ -320,7 +306,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
} }
} }
//TODO: not sure if it is good idea to change first active but unselected segment //TODO: not sure if it is good idea to change first active but unselected 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
} }
@ -332,7 +318,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*>()) {
@ -380,7 +368,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;
} }
@ -411,15 +399,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);
@ -496,10 +479,9 @@ void serializeInfo(JsonObject root)
JsonObject leds = root.createNestedObject("leds"); JsonObject leds = root.createNestedObject("leds");
leds[F("count")] = strip.getLengthTotal(); leds[F("count")] = strip.getLengthTotal();
leds[F("rgbw")] = strip.hasWhiteChannel(); leds[F("rgbw")] = strip.hasRGBWBus(); //deprecated, use info.leds.lc
leds[F("wv")] = false; leds[F("wv")] = false; //deprecated, use info.leds.lc
leds["cct"] = correctWB || strip.hasCCTBus(); //deprecated, use info.leds.lc
leds["cct"] = correctWB || strip.hasCCTBus();
switch (Bus::getAutoWhiteMode()) { switch (Bus::getAutoWhiteMode()) {
case RGBW_MODE_MANUAL_ONLY: case RGBW_MODE_MANUAL_ONLY:
case RGBW_MODE_DUAL: case RGBW_MODE_DUAL:
@ -520,6 +502,17 @@ void serializeInfo(JsonObject root)
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0; leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
leds[F("maxseg")] = strip.getMaxSegments(); leds[F("maxseg")] = strip.getMaxSegments();
//leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config //leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config
uint8_t totalLC = 0;
JsonArray lcarr = leds.createNestedArray(F("seglc"));
uint8_t nSegs = strip.getLastActiveSegmentId();
for (byte s = 0; s <= nSegs; s++) {
uint8_t lc = strip.getSegment(s).getLightCapabilities();
totalLC |= lc;
lcarr.add(lc);
}
leds["lc"] = totalLC;
root[F("str")] = syncToggleReceive; root[F("str")] = syncToggleReceive;

View File

@ -21,6 +21,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();
@ -49,9 +76,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));
@ -59,18 +85,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;
@ -109,9 +137,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;
} }
@ -125,9 +151,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();
} }
} }
@ -156,7 +180,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
@ -171,18 +195,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()
{ {
static unsigned long lastNlUpdate; static unsigned long lastNlUpdate;
@ -244,7 +275,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

@ -218,6 +218,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;
@ -450,7 +451,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);
@ -540,31 +541,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;
} }
} }
@ -641,27 +642,23 @@ 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=", &col[0]);
updateVal(&req, "&G=", &col[1]); updateVal(&req, "&G=", &col[1]);
updateVal(&req, "&B=", &col[2]); updateVal(&req, "&B=", &col[2]);
updateVal(&req, "&W=", &col[3]); updateVal(&req, "&W=", &col[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); // use transitions
updateVal(&req, "R2=", &colSec[0]); updateVal(&req, "R2=", &colSec[0]);
updateVal(&req, "G2=", &colSec[1]); updateVal(&req, "G2=", &colSec[1]);
updateVal(&req, "B2=", &colSec[2]); updateVal(&req, "B2=", &colSec[2]);
updateVal(&req, "W2=", &colSec[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); // use transitions
#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
} }
@ -669,7 +666,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
} }
@ -686,51 +683,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
@ -738,23 +724,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="));
@ -884,24 +888,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()) break; if (id > strip.getMaxSegments()) break;
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, id); //only take into account mirrored, selected, on, reversed for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[9 +ofs] >> j) & 0x01, id); //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

@ -179,18 +179,6 @@ void prepareHostname(char* hostname)
} }
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(CALL_MODE_BUTTON);
}
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++) {

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

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2202191 #define VERSION 2202201
//uncomment this if you have a "my_config.h" file you'd like to use //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG
@ -325,6 +325,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

@ -175,6 +175,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

@ -55,13 +55,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
@ -114,7 +114,8 @@ void sendDataWs(AsyncWebSocketClient * client)
size_t heap2 = ESP.getFreeHeap(); size_t heap2 = ESP.getFreeHeap();
if (!buffer || heap1-heap2<len) { if (!buffer || heap1-heap2<len) {
releaseJSONBufferLock(); releaseJSONBufferLock();
ws.cleanupClients(0); // disconnect all clients to release memory 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);
@ -163,7 +164,7 @@ void handleWs()
if (millis() - wsLastLiveTime > WS_LIVE_INTERVAL) if (millis() - wsLastLiveTime > WS_LIVE_INTERVAL)
{ {
#ifdef ESP8266 #ifdef ESP8266
ws.cleanupClients(2); ws.cleanupClients(3);
#else #else
ws.cleanupClients(); ws.cleanupClients();
#endif #endif

View File

@ -72,6 +72,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];
@ -439,6 +440,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);