diff --git a/wled00/FX.h b/wled00/FX.h index 19660a887..4bdec48f9 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -619,7 +619,7 @@ class WS2812FX { } void - finalizeInit(uint16_t countPixels), + finalizeInit(), service(void), blur(uint8_t), fill(uint32_t), @@ -636,7 +636,8 @@ class WS2812FX { trigger(void), setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0), resetSegments(), - populateDefaultSegments(), + makeAutoSegments(), + fixInvalidSegments(), setPixelColor(uint16_t n, uint32_t c), setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), show(void), @@ -650,6 +651,7 @@ class WS2812FX { gammaCorrectCol = true, applyToAllSelected = true, setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p), + checkSegmentAlignment(void), // return true if the strip is being sent pixel updates isUpdating(void); @@ -680,6 +682,8 @@ class WS2812FX { ablMilliampsMax, currentMilliamps, triwave16(uint16_t), + getLengthTotal(void), + getLengthPhysical(void), getFps(); uint32_t @@ -839,9 +843,6 @@ class WS2812FX { uint16_t _cumulativeFps = 2; - void load_gradient_palette(uint8_t); - void handle_palette(void); - bool _triggered; @@ -875,7 +876,10 @@ class WS2812FX { void blendPixelColor(uint16_t n, uint32_t color, uint8_t blend), - startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot); + startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot), + estimateCurrentAndLimitBri(void), + load_gradient_palette(uint8_t), + handle_palette(void); uint16_t* customMappingTable = nullptr; uint16_t customMappingSize = 0; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 598148fe1..f89df5ed1 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -65,25 +65,22 @@ #endif //do not call this method from system context (network callback) -void WS2812FX::finalizeInit(uint16_t countPixels) +void WS2812FX::finalizeInit(void) { RESET_RUNTIME; - _length = countPixels; + isRgbw = isOffRefreshRequred = false; - //if busses failed to load, add default (FS issue...) + //if busses failed to load, add default (fresh install, FS issue, ...) if (busses.getNumBusses() == 0) { const uint8_t defDataPins[] = {DATA_PINS}; const uint16_t defCounts[] = {PIXEL_COUNTS}; const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0])); const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0])); uint16_t prevLen = 0; - for (uint8_t i = 0; i < defNumBusses; i++) { + for (uint8_t i = 0; i < defNumBusses && i < WLED_MAX_BUSSES; i++) { uint8_t defPin[] = {defDataPins[i]}; uint16_t start = prevLen; - uint16_t count = _length; - if (defNumBusses > 1 && defNumCounts) { - count = defCounts[(i < defNumCounts) ? i : defNumCounts -1]; - } + uint16_t count = defCounts[(i < defNumCounts) ? i : defNumCounts -1]; prevLen += count; BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, COL_ORDER_GRB); busses.add(defCfg); @@ -92,60 +89,30 @@ void WS2812FX::finalizeInit(uint16_t countPixels) deserializeMap(); - uint16_t segStarts[MAX_NUM_SEGMENTS] = {0}; - uint16_t segStops [MAX_NUM_SEGMENTS] = {0}; - - setBrightness(_brightness); - - //TODO make sure segments are only refreshed when bus config actually changed (new settings page) - uint8_t s = 0; - for (uint8_t i = 0; i < busses.getNumBusses(); i++) { - Bus* b = busses.getBus(i); - - if (autoSegments) { //make one segment per bus - segStarts[s] = b->getStart(); - segStops[s] = segStarts[s] + b->getLength(); - - //check for overlap with previous segments - for (uint8_t j = 0; j < s; j++) { - if (segStops[j] > segStarts[s] && segStarts[j] < segStops[s]) { - //segments overlap, merge - segStarts[j] = min(segStarts[s],segStarts[j]); - segStops [j] = max(segStops [s],segStops [j]); segStops[s] = 0; - s--; - } - } - s++; - } - + _length = 0; + for (uint8_t i=0; igetStart() + bus->getLength() > MAX_LEDS) break; + //RGBW mode is enabled if at least one of the strips is RGBW + isRgbw |= bus->isRgbw(); + //refresh is required to remain off if at least one of the strips requires the refresh. + isOffRefreshRequred |= bus->isOffRefreshRequired(); + uint16_t busEnd = bus->getStart() + bus->getLength(); + if (busEnd > _length) _length = busEnd; #ifdef ESP8266 - if ((!IS_DIGITAL(b->getType()) || IS_2PIN(b->getType()))) continue; + if ((!IS_DIGITAL(bus->getType()) || IS_2PIN(bus->getType()))) continue; uint8_t pins[5]; - b->getPins(pins); - BusDigital* bd = static_cast(b); + if (!bus->getPins(pins)) continue; + BusDigital* bd = static_cast(bus); if (pins[0] == 3) bd->reinit(); #endif } + ledCount = _length; - if (autoSegments) { - for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { - setSegment(i, segStarts[i], segStops[i]); - } - } else { - //expand the main seg to the entire length, but only if there are no other segments - uint8_t mainSeg = getMainSegmentId(); - - if (getActiveSegmentsNum() < 2) { - setSegment(mainSeg, 0, _length); - } else { - //there are multiple segments, leave them, but prune length to total - for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) - { - if (_segments[i].start >= _length) setSegment(i, 0, 0); - if (_segments[i].stop > _length) setSegment(i, _segments[i].start, _length); - } - } - } + //segments are created in makeAutoSegments(); + + setBrightness(_brightness); } void WS2812FX::service() { @@ -292,12 +259,7 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) #define MA_FOR_ESP 100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA) //you can set it to 0 if the ESP is powered by USB and the LEDs by external -void WS2812FX::show(void) { - - // avoid race condition, caputre _callback value - show_callback callback = _callback; - if (callback) callback(); - +void WS2812FX::estimateCurrentAndLimitBri() { //power limit calculation //each LED can draw up 195075 "power units" (approx. 53mA) //one PU is the power it takes to have 1 channel 1 step brighter per brightness step @@ -310,65 +272,72 @@ void WS2812FX::show(void) { actualMilliampsPerLed = 12; // from testing an actual strip } - if (ablMilliampsMax > 149 && actualMilliampsPerLed > 0) //0 mA per LED and too low numbers turn off calculation - { - uint32_t puPerMilliamp = 195075 / actualMilliampsPerLed; - uint32_t powerBudget = (ablMilliampsMax - MA_FOR_ESP) * puPerMilliamp; //100mA for ESP power - if (powerBudget > puPerMilliamp * _length) //each LED uses about 1mA in standby, exclude that from power budget - { - powerBudget -= puPerMilliamp * _length; - } else - { - powerBudget = 0; - } - - uint32_t powerSum = 0; - - for (uint16_t i = 0; i < _length; i++) //sum up the usage of each LED - { - uint32_t c = busses.getPixelColor(i); - byte r = c >> 16, g = c >> 8, b = c, w = c >> 24; - - if(useWackyWS2815PowerModel) - { - // ignore white component on WS2815 power calculation - powerSum += (MAX(MAX(r,g),b)) * 3; - } - else - { - powerSum += (r + g + b + w); - } - } - - - if (isRgbw) //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less - { - powerSum *= 3; - powerSum = powerSum >> 2; //same as /= 4 - } - - uint32_t powerSum0 = powerSum; - powerSum *= _brightness; - - if (powerSum > powerBudget) //scale brightness down to stay in current limit - { - float scale = (float)powerBudget / (float)powerSum; - uint16_t scaleI = scale * 255; - uint8_t scaleB = (scaleI > 255) ? 255 : scaleI; - uint8_t newBri = scale8(_brightness, scaleB); - busses.setBrightness(newBri); - currentMilliamps = (powerSum0 * newBri) / puPerMilliamp; - } else - { - currentMilliamps = powerSum / puPerMilliamp; - busses.setBrightness(_brightness); - } - currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate - currentMilliamps += _length; //add standby power back to estimate - } else { + if (ablMilliampsMax < 150 || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation currentMilliamps = 0; busses.setBrightness(_brightness); + return; } + + uint16_t pLen = getLengthPhysical(); + uint32_t puPerMilliamp = 195075 / actualMilliampsPerLed; + uint32_t powerBudget = (ablMilliampsMax - MA_FOR_ESP) * puPerMilliamp; //100mA for ESP power + if (powerBudget > puPerMilliamp * pLen) { //each LED uses about 1mA in standby, exclude that from power budget + powerBudget -= puPerMilliamp * pLen; + } else { + powerBudget = 0; + } + + uint32_t powerSum = 0; + + for (uint8_t b = 0; b < busses.getNumBusses(); b++) { + Bus *bus = busses.getBus(b); + if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses + uint16_t len = bus->getLength(); + uint32_t busPowerSum = 0; + for (uint16_t i = 0; i < len; i++) { //sum up the usage of each LED + uint32_t c = bus->getPixelColor(i); + byte r = c >> 16, g = c >> 8, b = c, w = c >> 24; + + if(useWackyWS2815PowerModel) { //ignore white component on WS2815 power calculation + busPowerSum += (MAX(MAX(r,g),b)) * 3; + } else { + busPowerSum += (r + g + b + w); + } + } + + if (bus->isRgbw()) { //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less + busPowerSum *= 3; + busPowerSum = busPowerSum >> 2; //same as /= 4 + } + powerSum += busPowerSum; + } + + uint32_t powerSum0 = powerSum; + powerSum *= _brightness; + + if (powerSum > powerBudget) //scale brightness down to stay in current limit + { + float scale = (float)powerBudget / (float)powerSum; + uint16_t scaleI = scale * 255; + uint8_t scaleB = (scaleI > 255) ? 255 : scaleI; + uint8_t newBri = scale8(_brightness, scaleB); + busses.setBrightness(newBri); //to keep brightness uniform, sets virtual busses too + currentMilliamps = (powerSum0 * newBri) / puPerMilliamp; + } else { + currentMilliamps = powerSum / puPerMilliamp; + busses.setBrightness(_brightness); + } + currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate + currentMilliamps += pLen; //add standby power back to estimate +} + +void WS2812FX::show(void) { + + // avoid race condition, caputre _callback value + show_callback callback = _callback; + if (callback) callback(); + + estimateCurrentAndLimitBri(); // some buses send asynchronously and this method will return before // all of the data has been sent. @@ -586,6 +555,20 @@ uint32_t WS2812FX::getLastShow(void) { return _lastShow; } +uint16_t WS2812FX::getLengthTotal(void) { + return _length; +} + +uint16_t WS2812FX::getLengthPhysical(void) { + uint16_t len = 0; + for (uint8_t b = 0; b < busses.getNumBusses(); b++) { + Bus *bus = busses.getBus(b); + if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses + len += bus->getLength(); + } + return len; +} + void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) { if (n >= MAX_NUM_SEGMENTS) return; Segment& seg = _segments[n]; @@ -654,23 +637,67 @@ void WS2812FX::resetSegments() { _segment_runtimes[0].reset(); } -void WS2812FX::populateDefaultSegments() { - uint16_t length = 0; - for (uint8_t i=0; igetStart(); - length += bus->getLength(); - _segments[i].stop = _segments[i].start + bus->getLength(); - _segments[i].mode = DEFAULT_MODE; - _segments[i].colors[0] = DEFAULT_COLOR; - _segments[i].speed = DEFAULT_SPEED; - _segments[i].intensity = DEFAULT_INTENSITY; - _segments[i].grouping = 1; - _segments[i].setOption(SEG_OPTION_SELECTED, 1); - _segments[i].setOption(SEG_OPTION_ON, 1); - _segments[i].opacity = 255; +void WS2812FX::makeAutoSegments() { + uint16_t segStarts[MAX_NUM_SEGMENTS] = {0}; + uint16_t segStops [MAX_NUM_SEGMENTS] = {0}; + + if (autoSegments) { //make one segment per bus + uint8_t s = 0; + for (uint8_t i = 0; i < busses.getNumBusses(); i++) { + Bus* b = busses.getBus(i); + + segStarts[s] = b->getStart(); + segStops[s] = segStarts[s] + b->getLength(); + + //check for overlap with previous segments + for (uint8_t j = 0; j < s; j++) { + if (segStops[j] > segStarts[s] && segStarts[j] < segStops[s]) { + //segments overlap, merge + segStarts[j] = min(segStarts[s],segStarts[j]); + segStops [j] = max(segStops [s],segStops [j]); segStops[s] = 0; + s--; + } + } + s++; + } + for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { + setSegment(i, segStarts[i], segStops[i]); + } + } else { + //expand the main seg to the entire length, but only if there are no other segments + uint8_t mainSeg = getMainSegmentId(); + + if (getActiveSegmentsNum() < 2) { + setSegment(mainSeg, 0, _length); + } } + + fixInvalidSegments(); +} + +void WS2812FX::fixInvalidSegments() { + //make sure no segment is longer than total (sanity check) + for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) + { + if (_segments[i].start >= _length) setSegment(i, 0, 0); + if (_segments[i].stop > _length) setSegment(i, _segments[i].start, _length); + } +} + +//true if all segments align with a bus, or if a segment covers the total length +bool WS2812FX::checkSegmentAlignment() { + for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) + { + if (_segments[i].start >= _segments[i].stop) continue; //inactive segment + bool aligned = false; + for (uint8_t b = 0; bgetStart() && _segments[i].stop == bus->getStart() + bus->getLength()) aligned = true; + } + if (_segments[i].start == 0 && _segments[i].stop == _length) aligned = true; + if (!aligned) return false; + } + return true; } //After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply) diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 380959c15..799019f30 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -24,6 +24,10 @@ #define DEBUG_PRINTF(x...) #endif +#define GET_BIT(var,bit) (((var)>>(bit))&0x01) +#define SET_BIT(var,bit) ((var)|=(uint16_t)(0x0001<<(bit))) +#define UNSET_BIT(var,bit) ((var)&=(~(uint16_t)(0x0001<<(bit)))) + //temporary struct for passing bus configuration to bus struct BusConfig { uint8_t type = TYPE_WS2812_RGB; @@ -32,10 +36,12 @@ struct BusConfig { uint8_t colorOrder = COL_ORDER_GRB; bool reversed = false; uint8_t skipAmount; + bool refreshReq; uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255}; - BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip=0) { - type = busType; count = len; start = pstart; - colorOrder = pcolorOrder; reversed = rev; skipAmount = skip; + BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0) { + refreshReq = (bool) GET_BIT(busType,7); + type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh) + count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip; uint8_t nPins = 1; if (type >= TYPE_NET_DDP_RGB && type < 96) nPins = 4; //virtual network bus. 4 "pins" store IP address else if (type > 47) nPins = 2; @@ -120,6 +126,10 @@ class Bus { return false; } + inline bool isOffRefreshRequired() { + return _needsRefresh; + } + bool reversed = false; protected: @@ -127,6 +137,7 @@ class Bus { uint8_t _bri = 255; uint16_t _start = 0; bool _valid = false; + bool _needsRefresh = false; }; @@ -143,6 +154,7 @@ class BusDigital : public Bus { _pins[1] = bc.pins[1]; } reversed = bc.reversed; + _needsRefresh = bc.refreshReq || bc.type == TYPE_TM1814; _skip = bc.skipAmount; //sacrificial pixels _len = bc.count + _skip; _iType = PolyBus::getI(bc.type, _pins, nr); @@ -204,7 +216,7 @@ class BusDigital : public Bus { } inline bool isRgbw() { - return (_type == TYPE_SK6812_RGBW || _type == TYPE_TM1814); + return Bus::isRgbw(_type); } inline uint8_t skippedLeds() { @@ -216,7 +228,7 @@ class BusDigital : public Bus { } void cleanup() { - DEBUG_PRINTLN("Digital Cleanup"); + DEBUG_PRINTLN(F("Digital Cleanup.")); PolyBus::cleanup(_busPtr, _iType); _iType = I_NONE; _valid = false; @@ -326,7 +338,7 @@ class BusPwm : public Bus { } bool isRgbw() { - return (_type > TYPE_ONOFF && _type <= TYPE_ANALOG_5CH && _type != TYPE_ANALOG_3CH); + return Bus::isRgbw(_type); } inline void cleanup() { @@ -481,7 +493,7 @@ class BusManager { static uint32_t memUsage(BusConfig &bc) { uint8_t type = bc.type; uint16_t len = bc.count; - if (type < 32) { + if (type > 15 && type < 32) { #ifdef ESP8266 if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem if (type > 29) return len*20; //RGBW @@ -496,7 +508,7 @@ class BusManager { } if (type > 31 && type < 48) return 5; if (type == 44 || type == 45) return len*4; //RGBW - return len*3; + return len*3; //RGB } int add(BusConfig &bc) { @@ -513,7 +525,7 @@ class BusManager { //do not call this method from system context (network callback) void removeAll() { - //Serial.println("Removing all."); + DEBUG_PRINTLN(F("Removing all.")); //prevents crashes due to deleting busses while in use. while (!canAllShow()) yield(); for (uint8_t i = 0; i < numBusses; i++) delete busses[i]; @@ -573,16 +585,6 @@ class BusManager { return len; } - // a workaround - static inline bool isRgbw(uint8_t type) { - return Bus::isRgbw(type); - } - - //Return true if the strip requires a refresh to stay off. - static bool isOffRefreshRequred(uint8_t type) { - return type == TYPE_TM1814; - } - private: uint8_t numBusses = 0; Bus* busses[WLED_MAX_BUSSES]; diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 1a499404b..13bcdd964 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -1,4 +1,5 @@ #include "wled.h" +#include "wled_ethernet.h" /* * Serializes and parses the cfg.json and wsec.json settings files, stored in internal FS. @@ -85,10 +86,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(strip.rgbwMode, hw_led[F("rgbwm")]); JsonArray ins = hw_led["ins"]; + + uint16_t lC = 0; + if (fromFS || !ins.isNull()) { - uint8_t s = 0; //bus iterator - strip.isRgbw = false; - strip.isOffRefreshRequred = false; + uint8_t s = 0; // bus iterator busses.removeAll(); uint32_t mem = 0; for (JsonObject elm : ins) { @@ -107,22 +109,21 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { uint8_t colorOrder = (int)elm[F("order")]; uint8_t skipFirst = elm[F("skip")]; uint16_t start = elm["start"] | 0; + if (length==0 || start + length > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop uint8_t ledType = elm["type"] | TYPE_WS2812_RGB; bool reversed = elm["rev"]; - + bool refresh = elm["ref"] | false; + ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh + s++; + uint16_t busEnd = start + length; + if (busEnd > lC) lC = busEnd; BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst); - if (bc.adjustBounds(ledCount)) { - //RGBW mode is enabled if at least one of the strips is RGBW - strip.isRgbw = (strip.isRgbw || BusManager::isRgbw(ledType)); - //refresh is required to remain off if at least one of the strips requires the refresh. - strip.isOffRefreshRequred |= BusManager::isOffRefreshRequred(ledType); - s++; - mem += busses.memUsage(bc); - if (mem <= MAX_LED_MEMORY) busses.add(bc); - } + mem += BusManager::memUsage(bc); + if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip() } - strip.finalizeInit(ledCount); + // finalization done in beginStrip() } + if (lC > ledCount) ledCount = lC; // fix incorrect total length (honour analog setup) if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus // read multiple button configuration @@ -501,6 +502,25 @@ void serializeConfig() { #ifdef WLED_USE_ETHERNET JsonObject ethernet = doc.createNestedObject("eth"); ethernet["type"] = ethernetType; + if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { + JsonArray pins = ethernet.createNestedArray("pin"); + for (uint8_t p=0; p=0) pins.add(ethernetBoards[ethernetType].eth_power); + if (ethernetBoards[ethernetType].eth_mdc>=0) pins.add(ethernetBoards[ethernetType].eth_mdc); + if (ethernetBoards[ethernetType].eth_mdio>=0) pins.add(ethernetBoards[ethernetType].eth_mdio); + switch (ethernetBoards[ethernetType].eth_clk_mode) { + case ETH_CLOCK_GPIO0_IN: + case ETH_CLOCK_GPIO0_OUT: + pins.add(0); + break; + case ETH_CLOCK_GPIO16_OUT: + pins.add(16); + break; + case ETH_CLOCK_GPIO17_OUT: + pins.add(17); + break; + } + } #endif JsonObject hw = doc.createNestedObject("hw"); @@ -526,7 +546,9 @@ void serializeConfig() { ins[F("order")] = bus->getColorOrder(); ins["rev"] = bus->reversed; ins[F("skip")] = bus->skippedLeds(); - ins["type"] = bus->getType(); + ins["type"] = bus->getType() & 0x7F;; + ins["ref"] = bus->isOffRefreshRequired(); + ins[F("rgbw")] = bus->isRgbw(); } // button(s) @@ -551,7 +573,7 @@ void serializeConfig() { JsonObject hw_ir = hw.createNestedObject("ir"); hw_ir["pin"] = irPin; - hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled ) + hw_ir["type"] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled ) JsonObject hw_relay = hw.createNestedObject(F("relay")); hw_relay["pin"] = rlyPin; diff --git a/wled00/const.h b/wled00/const.h index 95faba519..854945a4d 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -241,10 +241,10 @@ #define NTP_PACKET_SIZE 48 -// maximum number of LEDs - more than 1500 LEDs (or 500 DMA "LEDPIN 3" driven ones) will cause a low memory condition on ESP8266 +//maximum number of rendered LEDs - this does not have to match max. physical LEDs, e.g. if there are virtual busses #ifndef MAX_LEDS #ifdef ESP8266 -#define MAX_LEDS 1664 // can't rely on memory limit to limit this to 1600 LEDs +#define MAX_LEDS 1664 //can't rely on memory limit to limit this to 1600 LEDs #else #define MAX_LEDS 8192 #endif diff --git a/wled00/data/index.js b/wled00/data/index.js index e77a37975..7bf47b25e 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -1296,9 +1296,9 @@ var plJson = {"0":{ "end": 0 }}; -//var plSelContent = ""; function makePlSel(incPl=false) { var plSelContent = ""; + delete pJson["0"]; // remove filler preset var arr = Object.entries(pJson); for (var i = 0; i < arr.length; i++) { var n = arr[i][1].n ? arr[i][1].n : "Preset " + arr[i][0]; diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 53f1b43da..187fd289f 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -160,13 +160,16 @@ } } if (change) { + gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state if (t > 31 && t < 48) d.getElementsByName("LC"+n)[0].value = 1; // for sanity change analog count just to 1 LED } + gId("rf"+n).onclick = (t == 31) ? (function(){return false}) : (function(){}); // prevent change for TM1814 isRGBW |= (t == 30 || t == 31 || (t > 40 && t < 46 && t != 43)); // RGBW checkbox, TYPE_xxxx values from const.h gId("co"+n).style.display = ((t>=80 && t<96) || t == 41 || t == 42) ? "none":"inline"; // hide color order for PWM W & WW/CW gId("dig"+n+"c").style.display = (t > 40 && t < 48) ? "none":"inline"; // hide count for analog gId("dig"+n+"r").style.display = (t>=80 && t<96) ? "none":"inline"; // hide reversed for virtual gId("dig"+n+"s").style.display = ((t>=80 && t<96) || (t > 40 && t < 48)) ? "none":"inline"; // hide skip 1st for virtual & analog + gId("dig"+n+"f").style.display = (t>=16 && t<32 || t>=50 && t<64) ? "inline":"none"; // hide refresh gId("rev"+n).innerHTML = (t > 40 && t < 48) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog gId("psd"+n).innerHTML = (t > 40 && t < 48) ? "Index:":"Start:"; // change analog start description } @@ -328,9 +331,9 @@ ${i+1}: -
-
Reversed:  
-
Skip 1st LED:
+

Reversed:
+

Skip 1st LED:
+

Off Refresh:  
`; f.insertAdjacentHTML("beforeend", cn); } diff --git a/wled00/html_settings.h b/wled00/html_settings.h index 8d001ad88..5c2b07cb4 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -77,7 +77,7 @@ onclick="B()">Back // Autogenerated from wled00/data/settings_leds.htm, do not edit!! const char PAGE_settings_leds[] PROGMEM = R"=====(LED Settings