Complete segment syncing.
Reduced complexity of colorUpdated regarding effect/color change. Minor optimizations.
This commit is contained in:
parent
7fb46cf982
commit
7eb029dcb6
@ -607,7 +607,7 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping,
|
||||
}
|
||||
|
||||
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;
|
||||
memset(_segments, 0, sizeof(_segments));
|
||||
//memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
|
||||
|
@ -22,11 +22,6 @@ void colorFromUint24(uint32_t in, bool secondary)
|
||||
_col[2] = B(in);
|
||||
}
|
||||
|
||||
//store color components in uint32_t
|
||||
uint32_t colorFromRgbw(byte* rgbw) {
|
||||
return RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
|
||||
}
|
||||
|
||||
//relatively change white brightness, minumum A=5
|
||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary)
|
||||
{
|
||||
@ -259,7 +254,7 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb)
|
||||
rgbw[1] = ((uint16_t) correctionRGB[1] * G(rgb)) /255; // correct G
|
||||
rgbw[2] = ((uint16_t) correctionRGB[2] * B(rgb)) /255; // correct B
|
||||
rgbw[3] = W(rgb);
|
||||
return colorFromRgbw(rgbw);
|
||||
return RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]);
|
||||
}
|
||||
|
||||
//approximates a Kelvin color temperature from an RGB color.
|
||||
@ -299,4 +294,4 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) {
|
||||
uint16_t k = 8080 + (225-r) *86;
|
||||
return (k > 10091) ? 10091 : k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,11 @@ void handleAlexa();
|
||||
void onAlexaChange(EspalexaDevice* dev);
|
||||
|
||||
//blynk.cpp
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
void initBlynk(const char* auth, const char* host, uint16_t port);
|
||||
void handleBlynk();
|
||||
void updateBlynk();
|
||||
#endif
|
||||
|
||||
//button.cpp
|
||||
void shortPressAction(uint8_t b=0);
|
||||
@ -56,7 +58,7 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
|
||||
//colors.cpp
|
||||
void colorFromUint32(uint32_t in, bool secondary = false);
|
||||
void colorFromUint24(uint32_t in, bool secondary = false);
|
||||
uint32_t colorFromRgbw(byte* rgbw);
|
||||
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
||||
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
||||
@ -141,7 +143,6 @@ void resetTimebase();
|
||||
void toggleOnOff();
|
||||
void setAllLeds();
|
||||
void setLedsStandard();
|
||||
bool colorChanged();
|
||||
void colorUpdated(int callMode);
|
||||
void updateInterfaces(uint8_t callMode);
|
||||
void handleTransitions();
|
||||
|
130
wled00/json.cpp
130
wled00/json.cpp
@ -146,14 +146,11 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
}
|
||||
|
||||
if (!colValid) continue;
|
||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||
{
|
||||
if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
|
||||
if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
|
||||
} else { //normal case, apply directly to segment
|
||||
seg.setColor(i, ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))), id);
|
||||
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
||||
}
|
||||
|
||||
uint32_t color = RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]);
|
||||
colorChanged |= (seg.colors[i] != color);
|
||||
seg.setColor(i, color, id);
|
||||
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,26 +173,18 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
|
||||
if (!(elem[F("sel")].isNull() && elem["rev"].isNull() && elem["on"].isNull() && elem[F("mi")].isNull())) effectChanged = true; //send UDP
|
||||
|
||||
//temporary, strip object gets updated via colorUpdated()
|
||||
if (id == strip.getMainSegmentId()) {
|
||||
byte effectPrev = effectCurrent;
|
||||
if (getVal(elem["fx"], &effectCurrent, 1, strip.getModeCount())) { //load effect ('r' random (1-255), '~' inc/dec (1-255), 0-255 exact value)
|
||||
if (!presetId && effectCurrent != effectPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
|
||||
}
|
||||
effectSpeed = elem[F("sx")] | effectSpeed;
|
||||
effectIntensity = elem[F("ix")] | effectIntensity;
|
||||
getVal(elem["pal"], &effectPalette, 1, strip.getPaletteCount());
|
||||
} else { //permanent
|
||||
byte fx = seg.mode;
|
||||
byte fxPrev = fx;
|
||||
if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random (1-255), '~' inc/dec (1-255), 0-255 exact value)
|
||||
strip.setMode(id, fx);
|
||||
if (!presetId && seg.mode != fxPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
|
||||
}
|
||||
seg.speed = elem[F("sx")] | seg.speed;
|
||||
seg.intensity = elem[F("ix")] | seg.intensity;
|
||||
getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount());
|
||||
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)
|
||||
strip.setMode(id, fx);
|
||||
if (!presetId && seg.mode != fxPrev) effectChanged = true; //send UDP
|
||||
}
|
||||
byte prevSpd = seg.speed;
|
||||
byte prevInt = seg.intensity;
|
||||
byte prevPal = seg.palette;
|
||||
if (getVal(elem[F("sx")], &seg.speed, 0, 255) && !presetId && prevSpd != seg.speed) effectChanged = true; //also supports inc/decrementing and random
|
||||
if (getVal(elem[F("ix")], &seg.intensity, 0, 255) && !presetId && prevInt != seg.intensity) effectChanged = true; //also supports inc/decrementing and random
|
||||
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
|
||||
if (!iarr.isNull()) {
|
||||
@ -289,16 +278,16 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
tr = root[F("tb")] | -1;
|
||||
if (tr >= 0) strip.timebase = ((uint32_t)tr) - millis();
|
||||
|
||||
JsonObject nl = root["nl"];
|
||||
JsonObject nl = root["nl"];
|
||||
nightlightActive = nl["on"] | nightlightActive;
|
||||
nightlightDelayMins = nl[F("dur")] | nightlightDelayMins;
|
||||
nightlightMode = nl[F("mode")] | nightlightMode;
|
||||
nightlightTargetBri = nl[F("tbri")] | nightlightTargetBri;
|
||||
|
||||
JsonObject udpn = root["udpn"];
|
||||
JsonObject udpn = root["udpn"];
|
||||
notifyDirect = udpn["send"] | notifyDirect;
|
||||
receiveNotifications = udpn["recv"] | receiveNotifications;
|
||||
bool noNotification = udpn[F("nn")]; //send no notification just for this request
|
||||
if ((bool)udpn[F("nn")]) callMode = CALL_MODE_NO_NOTIFY; //send no notification just for this request
|
||||
|
||||
unsigned long timein = root[F("time")] | UINT32_MAX; //backup time source if NTP not synced
|
||||
if (timein != UINT32_MAX) {
|
||||
@ -319,22 +308,21 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
|
||||
byte prevMain = strip.getMainSegmentId();
|
||||
strip.mainSegment = root[F("mainseg")] | prevMain;
|
||||
if (strip.getMainSegmentId() != prevMain) setValuesFromMainSeg();
|
||||
//if (strip.getMainSegmentId() != prevMain) setValuesFromMainSeg();
|
||||
|
||||
int it = 0;
|
||||
JsonVariant segVar = root["seg"];
|
||||
if (segVar.is<JsonObject>())
|
||||
{
|
||||
int id = segVar["id"] | -1;
|
||||
|
||||
if (id < 0) { //set all selected segments
|
||||
//if "seg" is not an array and ID not specified, apply to all selected/checked segments
|
||||
if (id < 0) {
|
||||
//apply all selected segments
|
||||
bool didSet = false;
|
||||
byte lowestActive = 99;
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
||||
{
|
||||
WS2812FX::Segment sg = strip.getSegment(s);
|
||||
if (sg.isActive())
|
||||
{
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++) {
|
||||
WS2812FX::Segment &sg = strip.getSegment(s);
|
||||
if (sg.isActive()) {
|
||||
if (lowestActive == 99) lowestActive = s;
|
||||
if (sg.isSelected()) {
|
||||
deserializeSegment(segVar, s, presetId);
|
||||
@ -342,9 +330,10 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO: not sure if it is good idea to change first active but unselected segment
|
||||
if (!didSet && lowestActive < strip.getMaxSegments()) deserializeSegment(segVar, lowestActive, presetId);
|
||||
} else { //set only the segment with the specified ID
|
||||
deserializeSegment(segVar, it, presetId);
|
||||
} else {
|
||||
deserializeSegment(segVar, id, presetId); //apply only the segment with the specified ID
|
||||
}
|
||||
} else {
|
||||
JsonArray segs = segVar.as<JsonArray>();
|
||||
@ -354,6 +343,8 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
it++;
|
||||
}
|
||||
}
|
||||
setValuesFromMainSeg(); //to make transition work on main segment
|
||||
if (effectChanged) unloadPlaylist(); //if any of the effect parameter changed unload playlist
|
||||
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
if (root["nx"].is<const char*>()) {
|
||||
@ -394,12 +385,13 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
JsonObject playlist = root[F("playlist")];
|
||||
if (!playlist.isNull() && loadPlaylist(playlist, presetId)) {
|
||||
//do not notify here, because the first playlist entry will do
|
||||
noNotification = true;
|
||||
if (root["on"].isNull()) callMode = CALL_MODE_NO_NOTIFY;
|
||||
else callMode = CALL_MODE_DIRECT_CHANGE; // possible bugfix for playlist only containing HTTP API preset FX=~
|
||||
} else {
|
||||
interfaceUpdateCallMode = CALL_MODE_WS_SEND;
|
||||
}
|
||||
|
||||
colorUpdated(noNotification ? CALL_MODE_NO_NOTIFY : callMode);
|
||||
colorUpdated(callMode);
|
||||
|
||||
return stateResponse;
|
||||
}
|
||||
@ -423,35 +415,35 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
|
||||
|
||||
if (segmentBounds && seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name); //not good practice, but decreases required JSON buffer
|
||||
|
||||
char colstr[70]; colstr[0] = '['; colstr[1] = '\0'; //max len 68 (5 chan, all 255)
|
||||
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
{
|
||||
// to conserve RAM we will serialize the col array manually
|
||||
// this will reduce RAM footprint from ~300 bytes to 84 bytes per segment
|
||||
char colstr[70]; colstr[0] = '['; colstr[1] = '\0'; //max len 68 (5 chan, all 255)
|
||||
const char *format = strip.isRgbw ? PSTR("[%u,%u,%u,%u]") : PSTR("[%u,%u,%u]");
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
{
|
||||
byte segcol[4]; byte* c = segcol;
|
||||
|
||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||
{
|
||||
c = (i == 0)? col:colSec;
|
||||
} else {
|
||||
segcol[0] = (byte)(seg.colors[i] >> 16); segcol[1] = (byte)(seg.colors[i] >> 8);
|
||||
segcol[2] = (byte)(seg.colors[i]); segcol[3] = (byte)(seg.colors[i] >> 24);
|
||||
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];
|
||||
if (strip.isRgbw) sprintf_P(tmpcol, PSTR("[%u,%u,%u,%u]"), c[0], c[1], c[2], c[3]);
|
||||
else sprintf_P(tmpcol, PSTR("[%u,%u,%u]"), c[0], c[1], c[2]);
|
||||
|
||||
strcat(colstr, i<2 ? strcat(tmpcol,",") : tmpcol);
|
||||
}
|
||||
strcat(colstr,"]");
|
||||
sprintf_P(tmpcol, format, (unsigned)c[0], (unsigned)c[1], (unsigned)c[2], (unsigned)c[3]);
|
||||
strcat(colstr, i<2 ? strcat_P(tmpcol, PSTR(",")) : tmpcol);
|
||||
}
|
||||
strcat_P(colstr, PSTR("]"));
|
||||
root["col"] = serialized(colstr);
|
||||
|
||||
root["fx"] = seg.mode;
|
||||
root["fx"] = seg.mode;
|
||||
root[F("sx")] = seg.speed;
|
||||
root[F("ix")] = seg.intensity;
|
||||
root["pal"] = seg.palette;
|
||||
root["pal"] = seg.palette;
|
||||
root[F("sel")] = seg.isSelected();
|
||||
root["rev"] = seg.getOption(SEG_OPTION_REVERSED);
|
||||
root["rev"] = seg.getOption(SEG_OPTION_REVERSED);
|
||||
root[F("mi")] = seg.getOption(SEG_OPTION_MIRROR);
|
||||
}
|
||||
|
||||
@ -464,7 +456,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
}
|
||||
|
||||
if (!forPreset) {
|
||||
if (errorFlag) root[F("error")] = errorFlag;
|
||||
if (errorFlag) {root[F("error")] = errorFlag; errorFlag = ERR_NONE;} //prevent error message to persist on screen
|
||||
|
||||
root["ps"] = (currentPreset > 0) ? currentPreset : -1;
|
||||
root[F("pl")] = currentPlaylist;
|
||||
@ -492,11 +484,9 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
root[F("mainseg")] = strip.getMainSegmentId();
|
||||
|
||||
JsonArray seg = root.createNestedArray("seg");
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
||||
{
|
||||
WS2812FX::Segment sg = strip.getSegment(s);
|
||||
if (sg.isActive())
|
||||
{
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++) {
|
||||
WS2812FX::Segment &sg = strip.getSegment(s);
|
||||
if (sg.isActive()) {
|
||||
JsonObject seg0 = seg.createNestedObject();
|
||||
serializeSegment(seg0, sg, s, forPreset, segmentBounds);
|
||||
} else if (forPreset && segmentBounds) { //disable segments not part of preset
|
||||
@ -622,9 +612,11 @@ void serializeInfo(JsonObject root)
|
||||
#endif
|
||||
|
||||
root[F("freeheap")] = ESP.getFreeHeap();
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||
if (psramFound()) root[F("psram")] = ESP.getFreePsram();
|
||||
#endif
|
||||
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
||||
|
||||
|
||||
usermods.addToJsonInfo(root);
|
||||
|
||||
byte os = 0;
|
||||
@ -671,7 +663,7 @@ void setPaletteColors(JsonArray json, CRGBPalette16 palette)
|
||||
for (int i = 0; i < 16; i++) {
|
||||
JsonArray colors = json.createNestedArray();
|
||||
CRGB color = palette[i];
|
||||
colors.add((((float)i / (float)16) * 255));
|
||||
colors.add(i<<4);
|
||||
colors.add(color.red);
|
||||
colors.add(color.green);
|
||||
colors.add(color.blue);
|
||||
@ -903,13 +895,13 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
|
||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
{
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
AsyncWebSocketClient * wsc = nullptr;
|
||||
if (!request) { //not HTTP, use Websockets
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
wsc = ws.client(wsClient);
|
||||
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t used = strip.getLengthTotal();
|
||||
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
|
||||
|
101
wled00/led.cpp
101
wled00/led.cpp
@ -44,8 +44,8 @@ byte scaledBri(byte in)
|
||||
|
||||
|
||||
void setAllLeds() {
|
||||
strip.setColor(0, col[0], col[1], col[2], col[3]);
|
||||
strip.setColor(1, colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||
strip.setColor(0, RGBW32(col[0], col[1], col[2], col[3]));
|
||||
strip.setColor(1, RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]));
|
||||
if (!realtimeMode || !arlsForceMaxBri)
|
||||
{
|
||||
strip.setBrightness(scaledBri(briT));
|
||||
@ -61,106 +61,67 @@ void setLedsStandard()
|
||||
}
|
||||
|
||||
|
||||
bool colorChanged()
|
||||
{
|
||||
for (byte i=0; i<4; i++)
|
||||
{
|
||||
if (col[i] != colIT[i]) return true;
|
||||
if (colSec[i] != colSecIT[i]) return true;
|
||||
}
|
||||
if (bri != briIT) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void colorUpdated(int callMode)
|
||||
{
|
||||
//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
|
||||
if (callMode != CALL_MODE_INIT &&
|
||||
callMode != CALL_MODE_DIRECT_CHANGE &&
|
||||
callMode != CALL_MODE_NO_NOTIFY &&
|
||||
callMode != CALL_MODE_BUTTON_PRESET) strip.applyToAllSelected = true; //if not from JSON api, which directly sets segments
|
||||
|
||||
bool someSel = false;
|
||||
|
||||
if (callMode == CALL_MODE_NOTIFICATION) {
|
||||
someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions);
|
||||
}
|
||||
|
||||
//Notifier: apply received FX to selected segments only if actually receiving FX
|
||||
if (someSel) strip.applyToAllSelected = receiveNotificationEffects;
|
||||
|
||||
bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette) || effectChanged;
|
||||
bool colChanged = colorChanged();
|
||||
|
||||
//Notifier: apply received color to selected segments only if actually receiving color
|
||||
if (someSel) strip.applyToAllSelected = receiveNotificationColor;
|
||||
|
||||
if (fxChanged || colChanged)
|
||||
{
|
||||
effectChanged = false;
|
||||
if (bri != briOld || effectChanged || colorChanged) {
|
||||
if (realtimeTimeout == UINT32_MAX) realtimeTimeout = 0;
|
||||
currentPreset = 0; //something changed, so we are no longer in the preset
|
||||
if (effectChanged) currentPreset = 0; //something changed, so we are no longer in the preset
|
||||
|
||||
notify(callMode);
|
||||
if (callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) notify(callMode);
|
||||
|
||||
//set flag to update blynk, ws and mqtt
|
||||
interfaceUpdateCallMode = callMode;
|
||||
effectChanged = false;
|
||||
colorChanged = false;
|
||||
} else {
|
||||
if (nightlightActive && !nightlightActiveOld &&
|
||||
callMode != CALL_MODE_NOTIFICATION &&
|
||||
callMode != CALL_MODE_NO_NOTIFY)
|
||||
{
|
||||
if (nightlightActive && !nightlightActiveOld && callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) {
|
||||
notify(CALL_MODE_NIGHTLIGHT);
|
||||
interfaceUpdateCallMode = CALL_MODE_NIGHTLIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
if (!colChanged) return; //following code is for e.g. initiating transitions
|
||||
|
||||
if (callMode != CALL_MODE_NO_NOTIFY && nightlightActive && (nightlightMode == NL_MODE_FADE || nightlightMode == NL_MODE_COLORFADE))
|
||||
{
|
||||
if (callMode != CALL_MODE_NO_NOTIFY && nightlightActive && (nightlightMode == NL_MODE_FADE || nightlightMode == NL_MODE_COLORFADE)) {
|
||||
briNlT = bri;
|
||||
nightlightDelayMs -= (millis() - nightlightStartTime);
|
||||
nightlightStartTime = millis();
|
||||
}
|
||||
for (byte i=0; i<4; i++)
|
||||
{
|
||||
colIT[i] = col[i];
|
||||
colSecIT[i] = colSec[i];
|
||||
}
|
||||
if (briT == 0)
|
||||
{
|
||||
if (briT == 0) {
|
||||
if (callMode != CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning
|
||||
}
|
||||
|
||||
briIT = bri;
|
||||
if (bri > 0) briLast = bri;
|
||||
|
||||
//deactivate nightlight if target brightness is reached
|
||||
if (bri == nightlightTargetBri && callMode != CALL_MODE_NO_NOTIFY && nightlightMode != NL_MODE_SUN) nightlightActive = false;
|
||||
|
||||
if (fadeTransition)
|
||||
{
|
||||
if (fadeTransition) {
|
||||
//set correct delay if not using notification delay
|
||||
if (callMode != CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay;
|
||||
jsonTransitionOnce = false;
|
||||
strip.setTransition(transitionDelayTemp);
|
||||
if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;}
|
||||
|
||||
if (transitionActive)
|
||||
{
|
||||
if (transitionDelayTemp == 0) {
|
||||
//setLedsStandard();
|
||||
briOld = briT = bri;
|
||||
if (!realtimeMode || !arlsForceMaxBri) strip.setBrightness(scaledBri(briT));
|
||||
strip.trigger();
|
||||
return;
|
||||
}
|
||||
|
||||
if (transitionActive) {
|
||||
briOld = briT;
|
||||
tperLast = 0;
|
||||
}
|
||||
strip.setTransitionMode(true);
|
||||
transitionActive = true;
|
||||
transitionStartTime = millis();
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
strip.setTransition(0);
|
||||
setLedsStandard();
|
||||
//setLedsStandard();
|
||||
briOld = briT = bri;
|
||||
if (!realtimeMode || !arlsForceMaxBri) strip.setBrightness(scaledBri(briT));
|
||||
strip.trigger();
|
||||
}
|
||||
}
|
||||
@ -168,11 +129,9 @@ void colorUpdated(int callMode)
|
||||
|
||||
void updateInterfaces(uint8_t callMode)
|
||||
{
|
||||
lastInterfaceUpdate = millis();
|
||||
sendDataWs();
|
||||
if (callMode == CALL_MODE_WS_SEND) {
|
||||
lastInterfaceUpdate = millis();
|
||||
return;
|
||||
}
|
||||
if (callMode == CALL_MODE_WS_SEND) return;
|
||||
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
if (espalexaDevice != nullptr && callMode != CALL_MODE_ALEXA) {
|
||||
@ -185,7 +144,6 @@ void updateInterfaces(uint8_t callMode)
|
||||
callMode != CALL_MODE_NO_NOTIFY) updateBlynk();
|
||||
#endif
|
||||
doPublishMqtt = true;
|
||||
lastInterfaceUpdate = millis();
|
||||
}
|
||||
|
||||
|
||||
@ -221,6 +179,13 @@ void handleTransitions()
|
||||
|
||||
void handleNightlight()
|
||||
{
|
||||
/*
|
||||
static unsigned long lastNlUpdate;
|
||||
unsigned long now = millis();
|
||||
if (now < 100 && lastNlUpdate > 0) lastNlUpdate = 0; //take care of millis() rollover
|
||||
if (now - lastNlUpdate < 100) return; //allow only 10 NL updates per second
|
||||
lastNlUpdate = now;
|
||||
*/
|
||||
if (nightlightActive)
|
||||
{
|
||||
if (!nightlightActiveOld) //init
|
||||
|
133
wled00/set.cpp
133
wled00/set.cpp
@ -307,6 +307,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
|
||||
//start ntp if not already connected
|
||||
if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
|
||||
ntpLastSyncTime = 0; // force new NTP query
|
||||
|
||||
longitude = request->arg(F("LN")).toFloat();
|
||||
latitude = request->arg(F("LT")).toFloat();
|
||||
@ -586,7 +587,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
DEBUG_PRINT(F("API req: "));
|
||||
DEBUG_PRINTLN(req);
|
||||
|
||||
strip.applyToAllSelected = false;
|
||||
strip.applyToAllSelected = true;
|
||||
|
||||
//segment select (sets main segment)
|
||||
byte prevMain = strip.getMainSegmentId();
|
||||
@ -597,22 +598,28 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
byte selectedSeg = strip.getMainSegmentId();
|
||||
if (selectedSeg != prevMain) setValuesFromMainSeg();
|
||||
|
||||
//snapshot to check if request changed values later, temporary.
|
||||
byte prevCol[4] = {col[0], col[1], col[2], col[3]};
|
||||
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
|
||||
byte prevEffect = effectCurrent;
|
||||
byte prevSpeed = effectSpeed;
|
||||
byte prevIntensity = effectIntensity;
|
||||
byte prevPalette = effectPalette;
|
||||
|
||||
pos = req.indexOf(F("SS="));
|
||||
if (pos > 0) {
|
||||
byte t = getNumVal(&req, pos);
|
||||
if (t < strip.getMaxSegments()) selectedSeg = t;
|
||||
if (t < strip.getMaxSegments()) {
|
||||
selectedSeg = t;
|
||||
strip.applyToAllSelected = false;
|
||||
}
|
||||
}
|
||||
|
||||
WS2812FX::Segment& selseg = strip.getSegment(selectedSeg);
|
||||
pos = req.indexOf(F("SV=")); //segment selected
|
||||
if (pos > 0) {
|
||||
byte t = getNumVal(&req, pos);
|
||||
if (t == 2) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++)
|
||||
{
|
||||
strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0);
|
||||
}
|
||||
}
|
||||
if (t == 2) for (uint8_t i = 0; i < strip.getMaxSegments(); i++) strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0); // unselect other segments
|
||||
selseg.setOption(SEG_OPTION_SELECTED, t);
|
||||
}
|
||||
|
||||
@ -678,26 +685,21 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
applyPreset(presetCycCurr);
|
||||
}
|
||||
|
||||
//snapshot to check if request changed values later, temporary.
|
||||
byte prevCol[4] = {col[0], col[1], col[2], col[3]};
|
||||
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
|
||||
byte prevEffect = effectCurrent;
|
||||
byte prevSpeed = effectSpeed;
|
||||
byte prevIntensity = effectIntensity;
|
||||
byte prevPalette = effectPalette;
|
||||
|
||||
//set brightness
|
||||
updateVal(&req, "&A=", &bri);
|
||||
|
||||
bool col0Changed = false, col1Changed = false, col2Changed = false;
|
||||
//set colors
|
||||
updateVal(&req, "&R=", &col[0]);
|
||||
updateVal(&req, "&G=", &col[1]);
|
||||
updateVal(&req, "&B=", &col[2]);
|
||||
updateVal(&req, "&W=", &col[3]);
|
||||
for (byte i=0; i<4; i++) if (prevCol[i]!=col[i]) col0Changed = colorChanged = true;
|
||||
updateVal(&req, "R2=", &colSec[0]);
|
||||
updateVal(&req, "G2=", &colSec[1]);
|
||||
updateVal(&req, "B2=", &colSec[2]);
|
||||
updateVal(&req, "W2=", &colSec[3]);
|
||||
for (byte i=0; i<4; i++) if (prevColSec[i]!=colSec[i]) col1Changed = colorChanged = true;
|
||||
|
||||
#ifdef WLED_ENABLE_LOXONE
|
||||
//lox parser
|
||||
@ -728,52 +730,64 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
if (pos > 0) {
|
||||
tempsat = getNumVal(&req, pos);
|
||||
}
|
||||
colorHStoRGB(temphue,tempsat,(req.indexOf(F("H2"))>0)? colSec:col);
|
||||
byte sec = req.indexOf(F("H2"));
|
||||
colorHStoRGB(temphue, tempsat, (sec>0) ? colSec : col);
|
||||
if (sec>0) col1Changed = true;
|
||||
else col0Changed = true;
|
||||
colorChanged = true;
|
||||
}
|
||||
|
||||
//set white spectrum (kelvin)
|
||||
pos = req.indexOf(F("&K="));
|
||||
if (pos > 0) {
|
||||
colorKtoRGB(getNumVal(&req, pos),(req.indexOf(F("K2"))>0)? colSec:col);
|
||||
byte sec = req.indexOf(F("K2"));
|
||||
colorKtoRGB(getNumVal(&req, pos), (sec>0) ? colSec : col);
|
||||
if (sec>0) col1Changed = true;
|
||||
else col0Changed = true;
|
||||
colorChanged = true;
|
||||
}
|
||||
|
||||
//set color from HEX or 32bit DEC
|
||||
byte tmpCol[4];
|
||||
pos = req.indexOf(F("CL="));
|
||||
if (pos > 0) {
|
||||
colorFromDecOrHexString(col, (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="));
|
||||
if (pos > 0) {
|
||||
colorFromDecOrHexString(colSec, (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="));
|
||||
if (pos > 0) {
|
||||
byte t[4];
|
||||
colorFromDecOrHexString(t, (char*)req.substring(pos + 3).c_str());
|
||||
if (selectedSeg != strip.getMainSegmentId()) {
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(2, t[0], t[1], t[2], t[3]);
|
||||
} else {
|
||||
selseg.setColor(2, RGBW32(t[0], t[1], t[2], t[3]), selectedSeg); // defined above (SS=)
|
||||
}
|
||||
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)
|
||||
col2Changed = colorChanged = true;
|
||||
}
|
||||
|
||||
//set to random hue SR=0->1st SR=1->2nd
|
||||
pos = req.indexOf(F("SR"));
|
||||
if (pos > 0) {
|
||||
_setRandomColor(getNumVal(&req, pos));
|
||||
byte sec = getNumVal(&req, pos);
|
||||
_setRandomColor(sec);
|
||||
if (sec>0) col1Changed = true;
|
||||
else col0Changed = true;
|
||||
colorChanged = true;
|
||||
}
|
||||
|
||||
//swap 2nd & 1st
|
||||
pos = req.indexOf(F("SC"));
|
||||
if (pos > 0) {
|
||||
byte temp;
|
||||
for (uint8_t i=0; i<4; i++)
|
||||
{
|
||||
temp = col[i];
|
||||
col[i] = colSec[i];
|
||||
for (uint8_t i=0; i<4; i++) {
|
||||
temp = col[i];
|
||||
col[i] = colSec[i];
|
||||
colSec[i] = temp;
|
||||
}
|
||||
col0Changed = col1Changed = colorChanged = true;
|
||||
}
|
||||
|
||||
//set effect parameters
|
||||
@ -781,6 +795,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
updateVal(&req, "SX=", &effectSpeed);
|
||||
updateVal(&req, "IX=", &effectIntensity);
|
||||
updateVal(&req, "FP=", &effectPalette, 0, strip.getPaletteCount()-1);
|
||||
strip.setMode(selectedSeg, effectCurrent);
|
||||
selseg.speed = effectSpeed;
|
||||
selseg.intensity = effectIntensity;
|
||||
selseg.palette = effectPalette;
|
||||
if (effectCurrent != prevEffect || effectSpeed != prevSpeed || effectIntensity != prevIntensity || effectPalette != prevPalette) effectChanged = true;
|
||||
|
||||
//set advanced overlay
|
||||
pos = req.indexOf(F("OL="));
|
||||
@ -911,45 +930,21 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
//you can add more if you need
|
||||
|
||||
//apply to all selected manually to prevent #1618. Temporary
|
||||
bool col0Changed = false, col1Changed = false;
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
if (col[i] != prevCol[i]) col0Changed = true;
|
||||
if (colSec[i] != prevColSec[i]) col1Changed = true;
|
||||
}
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++)
|
||||
{
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isSelected()) continue;
|
||||
if (effectCurrent != prevEffect) {
|
||||
strip.setMode(i, effectCurrent);
|
||||
effectChanged = true;
|
||||
}
|
||||
if (effectSpeed != prevSpeed) {
|
||||
seg.speed = effectSpeed;
|
||||
effectChanged = true;
|
||||
}
|
||||
if (effectIntensity != prevIntensity) {
|
||||
seg.intensity = effectIntensity;
|
||||
effectChanged = true;
|
||||
}
|
||||
if (effectPalette != prevPalette) {
|
||||
seg.palette = effectPalette;
|
||||
effectChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (col0Changed) {
|
||||
if (selectedSeg == strip.getMainSegmentId()) {
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(0, colorFromRgbw(col));
|
||||
}
|
||||
}
|
||||
if (col1Changed) {
|
||||
if (selectedSeg == strip.getMainSegmentId()) {
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(1, colorFromRgbw(colSec));
|
||||
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.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
if (col1Changed) seg.colors[1] = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||
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
|
||||
@ -958,8 +953,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
pos = req.indexOf(F("IN"));
|
||||
if (pos < 1) XML_response(request);
|
||||
|
||||
strip.applyToAllSelected = false;
|
||||
|
||||
pos = req.indexOf(F("&NN")); //do not send UDP notifications this time
|
||||
colorUpdated((pos > 0) ? CALL_MODE_NO_NOTIFY : CALL_MODE_DIRECT_CHANGE);
|
||||
|
||||
|
@ -282,24 +282,26 @@ void handleNotifications()
|
||||
|
||||
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
||||
//apply colors from notification
|
||||
if (receiveNotificationColor || !someSel)
|
||||
{
|
||||
col[0] = udpIn[3];
|
||||
col[1] = udpIn[4];
|
||||
col[2] = udpIn[5];
|
||||
if (receiveNotificationColor || !someSel) {
|
||||
if (version < 11 || !receiveSegmentOptions) {
|
||||
// only change col[] if not syncing full segments
|
||||
col[0] = udpIn[3];
|
||||
col[1] = udpIn[4];
|
||||
col[2] = udpIn[5];
|
||||
}
|
||||
if (version > 0) //sending module's white val is intended
|
||||
{
|
||||
col[3] = udpIn[10];
|
||||
if (version > 1)
|
||||
{
|
||||
// only change col[3] if not syncing full segments
|
||||
if (version < 11 || !receiveSegmentOptions) col[3] = udpIn[10];
|
||||
if (version > 1 && (version < 11 || !receiveSegmentOptions)) {
|
||||
// only change colSec[] if not syncing full segments
|
||||
colSec[0] = udpIn[12];
|
||||
colSec[1] = udpIn[13];
|
||||
colSec[2] = udpIn[14];
|
||||
colSec[3] = udpIn[15];
|
||||
}
|
||||
if (version > 6)
|
||||
{
|
||||
strip.setColor(2, udpIn[20], udpIn[21], udpIn[22], udpIn[23]); //tertiary color
|
||||
if (version > 6 && (version < 11 || !receiveSegmentOptions)) {
|
||||
strip.setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); //tertiary color
|
||||
}
|
||||
if (version > 9 && version < 200 && udpIn[37] < 255) { //valid CCT/Kelvin value
|
||||
uint8_t cct = udpIn[38];
|
||||
@ -324,22 +326,20 @@ void handleNotifications()
|
||||
for (uint8_t i = 0; i < srcSegs; i++) {
|
||||
WS2812FX::Segment& selseg = strip.getSegment(i);
|
||||
uint16_t ofs = 41 + i*UDP_SEG_SIZE; //start of segment offset byte
|
||||
for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[44+i*22] >> j) & 0x01); //only take into account mirrored, selected, on, reversed
|
||||
uint16_t offset = udpIn[2+ofs]<<8 | udpIn[3+ofs];
|
||||
selseg.setOpacity(udpIn[4+ofs], i);
|
||||
if (i == strip.getMainSegmentId()) { //temporary, to make transition work on main segment
|
||||
//TODO
|
||||
} else { //permanent
|
||||
strip.setMode(i, udpIn[5+ofs]);
|
||||
selseg.speed = udpIn[6+ofs];
|
||||
selseg.intensity = udpIn[7+ofs];
|
||||
selseg.palette = udpIn[8+ofs];
|
||||
}
|
||||
for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[4 +ofs] >> j) & 0x01); //only take into account mirrored, selected, on, reversed
|
||||
selseg.setOpacity( udpIn[5+ofs], i);
|
||||
strip.setMode(i, udpIn[6+ofs]);
|
||||
selseg.speed = udpIn[7+ofs];
|
||||
selseg.intensity = udpIn[8+ofs];
|
||||
selseg.palette = udpIn[9+ofs];
|
||||
selseg.setColor(0, RGBW32(udpIn[10+ofs],udpIn[11+ofs],udpIn[12+ofs],udpIn[13+ofs]), i);
|
||||
selseg.setColor(1, RGBW32(udpIn[14+ofs],udpIn[15+ofs],udpIn[16+ofs],udpIn[17+ofs]), i);
|
||||
selseg.setColor(2, RGBW32(udpIn[18+ofs],udpIn[19+ofs],udpIn[20+ofs],udpIn[21+ofs]), i);
|
||||
strip.setSegment(i, selseg.start, selseg.stop, udpIn[0+ofs], udpIn[1+ofs], offset); //also properly resets segments
|
||||
strip.setSegment(i, selseg.start, selseg.stop, udpIn[0+ofs], udpIn[1+ofs], (udpIn[2+ofs]<<8 | udpIn[3+ofs])); //also properly resets segments
|
||||
}
|
||||
setValuesFromMainSeg();
|
||||
effectChanged = true;
|
||||
colorChanged = true;
|
||||
} else { //simple effect sync, applies to all selected
|
||||
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
|
||||
effectSpeed = udpIn[9];
|
||||
|
@ -16,6 +16,7 @@
|
||||
// ESP8266-01 (blue) got too little storage space to work with WLED. 0.10.2 is the last release supporting this unit.
|
||||
|
||||
// ESP8266-01 (black) has 1MB flash and can thus fit the whole program, although OTA update is not possible. Use 1M(128K SPIFFS).
|
||||
// 2-step OTA may still be possible: https://github.com/Aircoookie/WLED/issues/2040#issuecomment-981111096
|
||||
// Uncomment some of the following lines to disable features:
|
||||
// Alternatively, with platformio pass your chosen flags to your custom build target in platformio_override.ini
|
||||
|
||||
@ -417,9 +418,6 @@ WLED_GLOBAL bool interfacesInited _INIT(false);
|
||||
WLED_GLOBAL bool wasConnected _INIT(false);
|
||||
|
||||
// color
|
||||
WLED_GLOBAL byte colIT[] _INIT_N(({ 0, 0, 0, 0 })); // color that was last sent to LEDs
|
||||
WLED_GLOBAL byte colSecIT[] _INIT_N(({ 0, 0, 0, 0 }));
|
||||
|
||||
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same
|
||||
|
||||
// transitions
|
||||
@ -470,6 +468,7 @@ WLED_GLOBAL byte effectSpeed _INIT(128);
|
||||
WLED_GLOBAL byte effectIntensity _INIT(128);
|
||||
WLED_GLOBAL byte effectPalette _INIT(0);
|
||||
WLED_GLOBAL bool effectChanged _INIT(false);
|
||||
WLED_GLOBAL bool colorChanged _INIT(false);
|
||||
|
||||
// network
|
||||
WLED_GLOBAL bool udpConnected _INIT(false), udp2Connected _INIT(false), udpRgbConnected _INIT(false);
|
||||
|
Loading…
Reference in New Issue
Block a user