From 36e0a1eb23cec2b324ac39efeb60e4a91005e2d5 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Sat, 29 Aug 2020 22:26:39 +0200 Subject: [PATCH] Individual LED control via JSON (closes #226 ) --- CHANGELOG.md | 6 ++++++ wled00/FX.h | 5 +++-- wled00/FX_fcn.cpp | 31 +++++++++++++++++++++++++++---- wled00/const.h | 1 + wled00/json.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++ wled00/wled.h | 2 +- 6 files changed, 85 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe3fec07..a48f9d20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,17 @@ ### Development versions after 0.10.0 release +#### Build 2008290 + +- Added individual LED control support to JSON API +- Added internal Segment Freeze/Pause option + #### Build 2008250 - Made `platformio_override.ini` example easier to use by including the `default_envs` property - FastLED uses `now` as timer, so effects using e.g. `beatsin88()` will sync correctly - Extended the speed range of Pacifica effect +- Improved TPM2.net receiving (#1100) - Fixed exception on empty MQTT payload (#1101) #### Build 2008200 diff --git a/wled00/FX.h b/wled00/FX.h index 0c5241b4..f1011822 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -434,6 +434,7 @@ class WS2812FX { init(bool supportWhite, uint16_t countPixels, bool skipFirst), service(void), blur(uint8_t), + fill(uint32_t), fade_out(uint8_t r), setMode(uint8_t segid, uint8_t m), setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), @@ -448,7 +449,8 @@ class WS2812FX { 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), - setRgbwPwm(void); + setRgbwPwm(void), + setPixelSegment(uint8_t n); bool reverseMode = false, //is the entire LED strip reversed? @@ -632,7 +634,6 @@ class WS2812FX { void load_gradient_palette(uint8_t); void handle_palette(void); - void fill(uint32_t); bool _useRgbw = false, diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index f9c1fef9..579a0cb6 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -81,12 +81,17 @@ void WS2812FX::service() { if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary { if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check - _virtualSegmentLength = SEGMENT.virtualLength(); doShow = true; - handle_palette(); - uint16_t delay = (this->*_mode[SEGMENT.mode])(); + uint16_t delay = FRAMETIME; + + if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen + _virtualSegmentLength = SEGMENT.virtualLength(); + handle_palette(); + delay = (this->*_mode[SEGMENT.mode])(); //effect function + if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++; + } + SEGENV.next_time = nowUp + delay; - if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++; } } } @@ -386,6 +391,12 @@ void WS2812FX::setBrightness(uint8_t b) { if (_brightness == b) return; _brightness = (gammaCorrectBri) ? gamma8(b) : b; _segment_index = 0; + if (b == 0) { //unfreeze all segments on power off + for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) + { + _segments[i].setOption(SEG_OPTION_FREEZE, false); + } + } if (SEGENV.next_time > millis() + 22 && millis() - _lastShow > MIN_SHOW_DELAY) show();//apply brightness change immediately if no refresh soon } @@ -535,6 +546,18 @@ void WS2812FX::resetSegments() { _segment_runtimes[0].reset(); } +//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply) +void WS2812FX::setPixelSegment(uint8_t n) +{ + if (n < MAX_NUM_SEGMENTS) { + _segment_index = n; + _virtualSegmentLength = SEGMENT.length(); + } else { + _segment_index = 0; + _virtualSegmentLength = 0; + } +} + void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) { if (i2 >= i) diff --git a/wled00/const.h b/wled00/const.h index ac3549b5..9fac4339 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -101,6 +101,7 @@ #define SEG_OPTION_ON 2 #define SEG_OPTION_MIRROR 3 //Indicates that the effect will be mirrored within the segment #define SEG_OPTION_NONUNITY 4 //Indicates that the effect does not use FRAMETIME or needs getPixelColor +#define SEG_OPTION_FREEZE 5 //Segment contents will not be refreshed #define SEG_OPTION_TRANSITIONAL 7 //Timer mode types diff --git a/wled00/json.cpp b/wled00/json.cpp index 40dd3f24..c18d9250 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -74,6 +74,53 @@ void deserializeSegment(JsonObject elem, byte it) seg.intensity = elem["ix"] | seg.intensity; seg.palette = elem["pal"] | seg.palette; } + + JsonArray iarr = elem["i"]; //set individual LEDs + if (!iarr.isNull()) { + strip.setPixelSegment(id); + + //freeze and init to black + if (!seg.getOption(SEG_OPTION_FREEZE)) { + seg.setOption(SEG_OPTION_FREEZE, true); + strip.fill(0); + } + + uint16_t start = 0, stop = 0; + byte set = 0; //0 nothing set, 1 start set, 2 range set + + for (uint16_t i = 0; i < iarr.size(); i++) { + if(iarr[i].is()) { + if (!set) { + start = iarr[i]; + set = 1; + } else { + stop = iarr[i]; + set = 2; + } + } else { + JsonArray icol = iarr[i]; + if (icol.isNull()) break; + + byte sz = icol.size(); + if (sz == 0 && sz > 4) break; + + int rgbw[] = {0,0,0,0}; + byte cp = copyArray(icol, rgbw); + + if (set < 2) stop = start + 1; + for (uint16_t i = start; i < stop; i++) { + strip.setPixelColor(i, rgbw[0], rgbw[1], rgbw[2], rgbw[3]); + } + if (!set) start++; + set = 0; + } + } + strip.setPixelSegment(255); + strip.trigger(); + } else { //return to regular effect + seg.setOption(SEG_OPTION_FREEZE, false); + } + } } diff --git a/wled00/wled.h b/wled00/wled.h index 0f2ee1f8..bfa72d02 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2008250 +#define VERSION 2008290 // ESP8266-01 (blue) got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.4.2 and the setting 512K(No SPIFFS).