Merge branch 'master' into master-merge

This commit is contained in:
Blaz Kristan 2022-03-08 22:46:50 +01:00
commit ddadaa828a
11 changed files with 1043 additions and 1041 deletions

2
.gitignore vendored
View File

@ -3,7 +3,6 @@
.pioenvs .pioenvs
.piolibdeps .piolibdeps
.vscode .vscode
!.vscode/extensions.json
/wled00/Release /wled00/Release
/wled00/extLibs /wled00/extLibs
/platformio_override.ini /platformio_override.ini
@ -17,3 +16,4 @@ node_modules
.direnv .direnv
wled-update.sh wled-update.sh
esp01-update.sh esp01-update.sh
/wled00/LittleFS

View File

@ -2,6 +2,12 @@
### Builds after release 0.12.0 ### Builds after release 0.12.0
#### Build 2203080
- Disabled auto white mode in segments with no RGB bus
- Fixed hostname string not 0-terminated
- Fixed Popcorn mode not lighting first LED on pop
#### Build 2203060 #### Build 2203060
- Dynamic hiding of unused color controls in UI (PR #2567) - Dynamic hiding of unused color controls in UI (PR #2567)

View File

@ -657,7 +657,8 @@ class WS2812FX {
paletteFade = 0, paletteFade = 0,
paletteBlend = 0, paletteBlend = 0,
milliampsPerLed = 55, milliampsPerLed = 55,
cctBlending = 0, autoWhiteMode = RGBW_MODE_DUAL,
cctBlending = 0,
getBrightness(void), getBrightness(void),
getModeCount(void), getModeCount(void),
getPaletteCount(void), getPaletteCount(void),

View File

@ -152,17 +152,18 @@ void WS2812FX::service() {
_colors_t[slot] = transitions[t].currentColor(SEGMENT.colors[slot]); _colors_t[slot] = transitions[t].currentColor(SEGMENT.colors[slot]);
} }
if (!cctFromRgb || correctWB) busses.setSegmentCCT(_cct_t, correctWB); if (!cctFromRgb || correctWB) busses.setSegmentCCT(_cct_t, correctWB);
_no_rgb = !(SEGMENT.getLightCapabilities() & 0x01);
for (uint8_t c = 0; c < NUM_COLORS; c++) { for (uint8_t c = 0; c < NUM_COLORS; c++) {
// if segment is not RGB capable, treat RGB channels of main segment colors as if 0
// this prevents Dual mode with white value 0 from setting White channel from inaccessible RGB values
// If not RGB capable, also treat palette as if default (0), as palettes set white channel to 0
if (_no_rgb) _colors_t[c] = _colors_t[c] & 0xFF000000;
_colors_t[c] = gamma32(_colors_t[c]); _colors_t[c] = gamma32(_colors_t[c]);
} }
handle_palette(); handle_palette();
// if segment is not RGB capable, force None auto white mode
// If not RGB capable, also treat palette as if default (0), as palettes set white channel to 0
_no_rgb = !(SEGMENT.getLightCapabilities() & 0x01);
if (_no_rgb) Bus::setAutoWhiteMode(RGBW_MODE_MANUAL_ONLY);
delay = (this->*_mode[SEGMENT.mode])(); //effect function delay = (this->*_mode[SEGMENT.mode])(); //effect function
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++; if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
Bus::setAutoWhiteMode(strip.autoWhiteMode);
} }
SEGENV.next_time = nowUp + delay; SEGENV.next_time = nowUp + delay;
@ -573,8 +574,9 @@ void WS2812FX::Segment::refreshLightCapabilities() {
_capabilities = 0; return; _capabilities = 0; return;
} }
uint8_t capabilities = 0; uint8_t capabilities = 0;
uint8_t awm = Bus::getAutoWhiteMode(); uint8_t awm = instance->autoWhiteMode;
bool whiteSlider = (awm == RGBW_MODE_DUAL || awm == RGBW_MODE_MANUAL_ONLY); bool whiteSlider = (awm == RGBW_MODE_DUAL || awm == RGBW_MODE_MANUAL_ONLY);
bool segHasValidBus = false;
for (uint8_t b = 0; b < busses.getNumBusses(); b++) { for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
Bus *bus = busses.getBus(b); Bus *bus = busses.getBus(b);
@ -582,13 +584,14 @@ void WS2812FX::Segment::refreshLightCapabilities() {
if (bus->getStart() >= stop) continue; if (bus->getStart() >= stop) continue;
if (bus->getStart() + bus->getLength() <= start) continue; if (bus->getStart() + bus->getLength() <= start) continue;
segHasValidBus = true;
uint8_t type = bus->getType(); uint8_t type = bus->getType();
if (!whiteSlider || (type != TYPE_ANALOG_1CH && (cctFromRgb || type != TYPE_ANALOG_2CH))) if (type != TYPE_ANALOG_1CH && (cctFromRgb || type != TYPE_ANALOG_2CH))
{ {
capabilities |= 0x01; //segment supports RGB (full color) capabilities |= 0x01; // segment supports RGB (full color)
} }
if (bus->isRgbw()) capabilities |= 0x02; //segment supports white channel if (bus->isRgbw()) capabilities |= 0x02; //segment supports white channel
if (whiteSlider) capabilities |= 0x08; //segment allows white channel adjustments if (whiteSlider || (bus->isRgbw() && !(capabilities & 0x01))) capabilities |= 0x08; //segment allows white channel adjustments
if (!cctFromRgb) { if (!cctFromRgb) {
switch (type) { switch (type) {
case TYPE_ANALOG_5CH: case TYPE_ANALOG_5CH:
@ -598,6 +601,9 @@ void WS2812FX::Segment::refreshLightCapabilities() {
} }
if (correctWB && type != TYPE_ANALOG_1CH) capabilities |= 0x04; //white balance correction (uses CCT slider) if (correctWB && type != TYPE_ANALOG_1CH) capabilities |= 0x04; //white balance correction (uses CCT slider)
} }
// if seg has any bus, but no bus has RGB, it by definition supports white (at least for now)
// In case of no RGB, disregard auto white mode and always show a white slider
if (segHasValidBus && !(capabilities & 0x01)) capabilities |= 0x02; // segment supports white channel
_capabilities = capabilities; _capabilities = capabilities;
} }

View File

@ -83,13 +83,14 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]); CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]); CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
Bus::setAutoWhiteMode(hw_led[F("rgbwm")] | Bus::getAutoWhiteMode()); CJSON(strip.autoWhiteMode, hw_led[F("rgbwm")]);
Bus::setAutoWhiteMode(strip.autoWhiteMode);
strip.fixInvalidSegments(); // refreshes segment light capabilities (in case auto white mode changed) strip.fixInvalidSegments(); // refreshes segment light capabilities (in case auto white mode changed)
CJSON(correctWB, hw_led["cct"]); CJSON(correctWB, hw_led["cct"]);
CJSON(cctFromRgb, hw_led[F("cr")]); CJSON(cctFromRgb, hw_led[F("cr")]);
CJSON(strip.cctBlending, hw_led[F("cb")]); CJSON(strip.cctBlending, hw_led[F("cb")]);
Bus::setCCTBlend(strip.cctBlending); Bus::setCCTBlend(strip.cctBlending);
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS
JsonArray ins = hw_led["ins"]; JsonArray ins = hw_led["ins"];
@ -573,9 +574,9 @@ void serializeConfig() {
hw_led[F("ledma")] = strip.milliampsPerLed; hw_led[F("ledma")] = strip.milliampsPerLed;
hw_led["cct"] = correctWB; hw_led["cct"] = correctWB;
hw_led[F("cr")] = cctFromRgb; hw_led[F("cr")] = cctFromRgb;
hw_led[F("cb")] = strip.cctBlending; hw_led[F("cb")] = strip.cctBlending;
hw_led["fps"] = strip.getTargetFps(); hw_led["fps"] = strip.getTargetFps();
hw_led[F("rgbwm")] = Bus::getAutoWhiteMode(); hw_led[F("rgbwm")] = strip.autoWhiteMode;
JsonArray hw_led_ins = hw_led.createNestedArray("ins"); JsonArray hw_led_ins = hw_led.createNestedArray("ins");

View File

@ -3,7 +3,6 @@ var loc = false, locip;
var noNewSegs = false; var noNewSegs = false;
var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true; var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true;
var hasWhite = false, hasRGB = false, hasCCT = false; var hasWhite = false, hasRGB = false, hasCCT = false;
var whites = [0,0,0];
var expanded = [false]; var expanded = [false];
var powered = [true]; var powered = [true];
var nlDur = 60, nlTar = 0; var nlDur = 60, nlTar = 0;
@ -56,17 +55,18 @@ function rgbBri(a) {return 0.2126*parseInt(a.r) + 0.7152*parseInt(a.g) + 0.0722*
// sets background of color slot selectors // sets background of color slot selectors
function setCSL(cs) function setCSL(cs)
{ {
let w = whites[parseInt(cs.id.substr(3))]; let w = cs.dataset.w ? parseInt(cs.dataset.w) : 0;
let hasShadow = getComputedStyle(cs).textShadow;
if (hasRGB && !isRgbBlack(cs.dataset)) { if (hasRGB && !isRgbBlack(cs.dataset)) {
cs.style.backgroundColor = rgbStr(cs.dataset); cs.style.backgroundColor = rgbStr(cs.dataset);
cs.style.color = rgbBri(cs.dataset) > 127 ? "#000":"#fff"; // if text has no CSS "shadow" if (!hasShadow) cs.style.color = rgbBri(cs.dataset) > 127 ? "#000":"#fff"; // if text has no CSS "shadow"
if (hasWhite && w > 0) { if (hasWhite && w > 0) {
cs.style.background = `linear-gradient(180deg, ${rgbStr(cs.dataset)} 30%, rgb(${w},${w},${w}))`; cs.style.background = `linear-gradient(180deg, ${rgbStr(cs.dataset)} 30%, rgb(${w},${w},${w}))`;
} }
} else { } else {
if (!hasWhite) w = 0; if (!hasWhite) w = 0;
cd.style.background = `rgb(${w},${w},${w})`; cs.style.background = `rgb(${w},${w},${w})`;
cd.style.color = w > 127 ? "#000":"#fff"; if (!hasShadow) cs.style.color = w > 127 ? "#000":"#fff";
} }
} }
@ -1189,8 +1189,9 @@ function readState(s,command=false)
cd[e].dataset.r = i.col[e][0]; cd[e].dataset.r = i.col[e][0];
cd[e].dataset.g = i.col[e][1]; cd[e].dataset.g = i.col[e][1];
cd[e].dataset.b = i.col[e][2]; cd[e].dataset.b = i.col[e][2];
cd[e].style.backgroundColor = rgbStr(cd[e].dataset); // or: setCSL(cd[e]); if (hasWhite) { let w = cd[e].dataset.w = i.col[e][3]; }
if (hasWhite) { let w = cd[e].dataset.w = i.col[e][3]; whites[e] = parseInt(w); } //cd[e].style.backgroundColor = rgbStr(cd[e].dataset); // or:
setCSL(cd[e]);
} }
selectSlot(csel); selectSlot(csel);
if (i.cct != null && i.cct>=0) gId("sliderA").value = i.cct; if (i.cct != null && i.cct>=0) gId("sliderA").value = i.cct;
@ -1436,7 +1437,6 @@ function requestJson(command=null)
}) })
.catch((e)=>{ .catch((e)=>{
showToast(e, true); showToast(e, true);
console.log(e);
}); });
} }
@ -2042,7 +2042,7 @@ function selectSlot(b)
setPicker(cd[b].style.backgroundColor); setPicker(cd[b].style.backgroundColor);
//force slider update on initial load (picker "color:change" not fired if black) //force slider update on initial load (picker "color:change" not fired if black)
if (cpick.color.value == 0) updatePSliders(); if (cpick.color.value == 0) updatePSliders();
gId('sliderW').value = whites[b]; gId('sliderW').value = parseInt(cd[b].dataset.w);
updateTrail(gId('sliderW')); updateTrail(gId('sliderW'));
redrawPalPrev(); redrawPalPrev();
//updatePSliders(); //updatePSliders();
@ -2073,7 +2073,7 @@ function updatePSliders() {
//update hex field //update hex field
var str = cpick.color.hexString.substring(1); var str = cpick.color.hexString.substring(1);
var w = whites[csel]; var w = parseInt(gId("csl").children[csel].dataset.w);
if (w > 0) str += w.toString(16); if (w > 0) str += w.toString(16);
gId('hexc').value = str; gId('hexc').value = str;
gId('hexcnf').style.backgroundColor = "var(--c-3)"; gId('hexcnf').style.backgroundColor = "var(--c-3)";
@ -2105,13 +2105,13 @@ function segEnter(s) {
function fromHex() function fromHex()
{ {
var str = gId('hexc').value; var str = gId('hexc').value;
whites[csel] = parseInt(str.substring(6), 16); let w = parseInt(str.substring(6), 16);
try { try {
setPicker("#" + str.substring(0,6)); setPicker("#" + str.substring(0,6));
} catch (e) { } catch (e) {
setPicker("#ffaa00"); setPicker("#ffaa00");
} }
if (isNaN(whites[csel])) whites[csel] = 0; gId("csl").children[csel].dataset.w = isNaN(w) ? 0 : w;
setColor(2); setColor(2);
} }
@ -2144,19 +2144,21 @@ function setColor(sr)
{ {
var cd = gId('csl').children; // color slots var cd = gId('csl').children; // color slots
let cdd = cd[csel].dataset; let cdd = cd[csel].dataset;
if (sr == 1 && cdd.r == "0" && cdd.g == "0" && cdd.b == "0") cpick.color.setChannel('hsv', 'v', 100); let w = 0, r,g,b;
if (sr != 2) whites[csel] = parseInt(gId('sliderW').value); if (sr == 1 && isRgbBlack(cdd)) cpick.color.setChannel('hsv', 'v', 100);
if (sr != 2 && hasWhite) w = parseInt(gId('sliderW').value);
var col = cpick.color.rgb; var col = cpick.color.rgb;
cdd.r = col.r; cdd.r = r = hasRGB ? col.r : w;
cdd.g = col.g; cdd.g = g = hasRGB ? col.g : w;
cdd.b = col.b; cdd.b = b = hasRGB ? col.b : w;
if (hasWhite) cdd.w = whites[csel]; cdd.w = w;
cd[csel].style.backgroundColor = rgbStr(cd[csel].dataset); // or: setCSL(cd[csel]); //cd[csel].style.backgroundColor = rgbStr(cd[csel].dataset); // or:
var obj = {"seg": {"col": [[col.r, col.g, col.b, whites[csel]],[],[]]}}; setCSL(cd[csel]);
var obj = {"seg": {"col": [[r, g, b, w],[],[]]}};
if (csel == 1) { if (csel == 1) {
obj = {"seg": {"col": [[],[col.r, col.g, col.b, whites[csel]],[]]}}; obj = {"seg": {"col": [[],[r, g, b, w],[]]}};
} else if (csel == 2) { } else if (csel == 2) {
obj = {"seg": {"col": [[],[],[col.r, col.g, col.b, whites[csel]]]}}; obj = {"seg": {"col": [[],[],[r, g, b, w]]}};
} }
requestJson(obj); requestJson(obj);
} }
@ -2256,7 +2258,6 @@ function getPalettesData(page, callback)
}) })
.catch((error)=>{ .catch((error)=>{
showToast(error, true); showToast(error, true);
console.log(error);
}); });
} }

File diff suppressed because it is too large Load Diff

View File

@ -224,7 +224,7 @@ void changeColor(uint32_t c, int16_t cct=-1)
bool isCCT = GET_BIT(capabilities, 2); bool isCCT = GET_BIT(capabilities, 2);
if (isRGB) mask |= 0x00FFFFFF; // RGB if (isRGB) mask |= 0x00FFFFFF; // RGB
if (hasW) mask |= 0xFF000000; // white if (hasW) mask |= 0xFF000000; // white
if (hasW && (Bus::getAutoWhiteMode() == RGBW_MODE_AUTO_ACCURATE) && (c & 0xFF000000)) { // white channel & white specified if (hasW && (strip.autoWhiteMode == RGBW_MODE_AUTO_ACCURATE) && (c & 0xFF000000)) { // white channel & white specified
seg.setColor(0, c | 0xFFFFFF, i); // for accurate mode we fake white seg.setColor(0, c | 0xFFFFFF, i); // for accurate mode we fake white
} else if (c & mask) seg.setColor(0, c & mask, i); // only apply if not black } else if (c & mask) seg.setColor(0, c & mask, i); // only apply if not black
if (isCCT && cct >= 0) seg.setCCT(cct, i); if (isCCT && cct >= 0) seg.setCCT(cct, i);
@ -240,7 +240,7 @@ void changeColor(uint32_t c, int16_t cct=-1)
bool isCCT = GET_BIT(capabilities, 2); bool isCCT = GET_BIT(capabilities, 2);
if (isRGB) mask |= 0x00FFFFFF; // RGB if (isRGB) mask |= 0x00FFFFFF; // RGB
if (hasW) mask |= 0xFF000000; // white if (hasW) mask |= 0xFF000000; // white
if (hasW && (Bus::getAutoWhiteMode() == RGBW_MODE_AUTO_ACCURATE) && (c & 0xFF000000)) { // white channel & white specified if (hasW && (strip.autoWhiteMode == RGBW_MODE_AUTO_ACCURATE) && (c & 0xFF000000)) { // white channel & white specified
seg.setColor(0, c | 0xFFFFFF, i); // for accurate mode we fake white seg.setColor(0, c | 0xFFFFFF, i); // for accurate mode we fake white
} else if (c & mask) seg.setColor(0, c & mask, i); // only apply if not black } else if (c & mask) seg.setColor(0, c & mask, i); // only apply if not black
if (isCCT && cct >= 0) seg.setCCT(cct, i); if (isCCT && cct >= 0) seg.setCCT(cct, i);

View File

@ -468,24 +468,6 @@ 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.hasRGBWBus(); //deprecated, use info.leds.lc
leds[F("wv")] = false; //deprecated, use info.leds.lc
leds["cct"] = correctWB || strip.hasCCTBus(); //deprecated, use info.leds.lc
switch (Bus::getAutoWhiteMode()) {
case RGBW_MODE_MANUAL_ONLY:
case RGBW_MODE_DUAL:
if (strip.hasWhiteChannel()) leds[F("wv")] = true;
break;
}
/*
JsonArray leds_pin = leds.createNestedArray("pin");
for (uint8_t s=0; s<busses.getNumBusses(); s++) {
Bus *bus = busses.getBus(s);
uint8_t pins[5];
bus->getPins(pins);
leds_pin.add(pins[0]); // need to elaborate this for multipin strips
}
*/
leds[F("pwr")] = strip.currentMilliamps; leds[F("pwr")] = strip.currentMilliamps;
leds["fps"] = strip.getFps(); leds["fps"] = strip.getFps();
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0; leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
@ -503,6 +485,10 @@ void serializeInfo(JsonObject root)
leds["lc"] = totalLC; leds["lc"] = totalLC;
leds[F("rgbw")] = strip.hasRGBWBus(); // deprecated, use info.leds.lc
leds[F("wv")] = totalLC & 0x02; // deprecated, true if white slider should be displayed for any segment
leds["cct"] = totalLC & 0x04; // deprecated, use info.leds.lc
root[F("str")] = syncToggleReceive; root[F("str")] = syncToggleReceive;
root[F("name")] = serverDescription; root[F("name")] = serverDescription;

View File

@ -83,10 +83,11 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
autoSegments = request->hasArg(F("MS")); autoSegments = request->hasArg(F("MS"));
correctWB = request->hasArg(F("CCT")); correctWB = request->hasArg(F("CCT"));
cctFromRgb = request->hasArg(F("CR")); cctFromRgb = request->hasArg(F("CR"));
strip.cctBlending = request->arg(F("CB")).toInt(); strip.cctBlending = request->arg(F("CB")).toInt();
Bus::setCCTBlend(strip.cctBlending); Bus::setCCTBlend(strip.cctBlending);
Bus::setAutoWhiteMode(request->arg(F("AW")).toInt()); strip.autoWhiteMode = (request->arg(F("AW")).toInt());
strip.setTargetFps(request->arg(F("FR")).toInt()); Bus::setAutoWhiteMode(strip.autoWhiteMode);
strip.setTargetFps(request->arg(F("FR")).toInt());
for (uint8_t s = 0; s < WLED_MAX_BUSSES; s++) { for (uint8_t s = 0; s < WLED_MAX_BUSSES; s++) {
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin

View File

@ -338,9 +338,9 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',SET_F("MS"),autoSegments); sappend('c',SET_F("MS"),autoSegments);
sappend('c',SET_F("CCT"),correctWB); sappend('c',SET_F("CCT"),correctWB);
sappend('c',SET_F("CR"),cctFromRgb); sappend('c',SET_F("CR"),cctFromRgb);
sappend('v',SET_F("CB"),strip.cctBlending); sappend('v',SET_F("CB"),strip.cctBlending);
sappend('v',SET_F("FR"),strip.getTargetFps()); sappend('v',SET_F("FR"),strip.getTargetFps());
sappend('v',SET_F("AW"),Bus::getAutoWhiteMode()); sappend('v',SET_F("AW"),strip.autoWhiteMode);
for (uint8_t s=0; s < busses.getNumBusses(); s++) { for (uint8_t s=0; s < busses.getNumBusses(); s++) {
Bus* bus = busses.getBus(s); Bus* bus = busses.getBus(s);