На каком-то зарубежном сайте нашел вот такую реализацию новогодней иллюминации. Эффект, вроде бы простой, но тут интересна реализация. Публикуется с комментариями автора. Используется библиотека FastLEDю Подходит для WS2811.

#include "FastLED.h"
 
#define LED_PIN     6
#define LED_TYPE    WS2811
#define COLOR_ORDER RGB
#define NUM_LEDS   27
CRGB leds[NUM_LEDS];
 
//  Twinkling 'holiday' lights that fade up and down in brightness.
//  Colors are chosen from a palette; a few palettes are provided.
//
//  The basic operation is that all pixels stay black until they
//  are 'seeded' with a relatively dim color.  The dim colors
//  are repeatedly brightened until they reach full brightness, then
//  are darkened repeatedly until they are fully black again.
//
//  A set of 'directionFlags' is used to track whether a given
//  pixel is presently brightening up or darkening down.
//
//  For illustration purposes, two implementations of directionFlags
//  are provided: a simple one-byte-per-pixel flag, and a more
//  complicated, more compact one-BIT-per-pixel flag.
//
//  Darkening colors accurately is relatively easy: scale down the
//  existing color channel values.  Brightening colors is a bit more
//  error prone, as there's some loss of precision.  If your colors
//  aren't coming our 'right' at full brightness, try increasing the
//  STARTING_BRIGHTNESS value.
//
//  -Mark Kriegsman, December 2014
 
#define MASTER_BRIGHTNESS   200
 
#define STARTING_BRIGHTNESS 64
#define FADE_IN_SPEED       32
#define FADE_OUT_SPEED      20
#define DENSITY            255
 
void setup()
{
  delay(3000);
  FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(MASTER_BRIGHTNESS);
}
 
void loop()
{
  
  chooseColorPalette();
  colortwinkles();
  FastLED.show();
  FastLED.delay(20);
}
 
 
CRGBPalette16 gPalette;
 
void chooseColorPalette()
{
  uint8_t numberOfPalettes = 5;
  uint8_t secondsPerPalette = 10;
  uint8_t whichPalette = (millis() / (1000 * secondsPerPalette)) % numberOfPalettes;
 
  CRGB r(CRGB::Red), b(CRGB::Blue), w(85, 85, 85), g(CRGB::Green), W(CRGB::White), l(0xE1A024);
 
  switch( whichPalette)
  {
    case 0: // Red, Green, and White
      gPalette = CRGBPalette16( r, r, r, r, r, r, r, r, g, g, g, g, w, w, w, w );
      break;
    case 1: // Blue and White
      //gPalette = CRGBPalette16( b,b,b,b, b,b,b,b, w,w,w,w, w,w,w,w );
      gPalette = CloudColors_p; // Blues and whites!
      break;
    case 2: // Rainbow of colors
      gPalette = RainbowColors_p;
      break;
    case 3: // Incandescent "fairy lights"
      gPalette = CRGBPalette16( l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l );
      break;
    case 4: // Snow
      gPalette = CRGBPalette16( W, W, W, W, w, w, w, w, w, w, w, w, w, w, w, w );
      break;
  }
}
 
enum { GETTING_DARKER = 0, GETTING_BRIGHTER = 1 };
 
void colortwinkles()
{
  // Make each pixel brighter or darker, depending on
  // its 'direction' flag.
  brightenOrDarkenEachPixel( FADE_IN_SPEED, FADE_OUT_SPEED);
 
  // Now consider adding a new random twinkle
  if( random8() < DENSITY )
  {
    int pos = random16(NUM_LEDS);
    if( !leds[pos])
    {
      leds[pos] = ColorFromPalette( gPalette, random8(), STARTING_BRIGHTNESS, NOBLEND);
      setPixelDirection(pos, GETTING_BRIGHTER);
    }
  }
}
 
void brightenOrDarkenEachPixel( fract8 fadeUpAmount, fract8 fadeDownAmount)
{
  for( uint16_t i = 0; i < NUM_LEDS; i++)
  {
    if( getPixelDirection(i) == GETTING_DARKER)
    {
      // This pixel is getting darker
      leds[i] = makeDarker( leds[i], fadeDownAmount);
    }
    else
    {
      // This pixel is getting brighter
      leds[i] = makeBrighter( leds[i], fadeUpAmount);
      // now check to see if we've maxxed out the brightness
      if( leds[i].r == 255 || leds[i].g == 255 || leds[i].b == 255)
      {
        // if so, turn around and start getting darker
        setPixelDirection(i, GETTING_DARKER);
      }
    }
  }
}
 
CRGB makeBrighter( const CRGB& color, fract8 howMuchBrighter)
{
  CRGB incrementalColor = color;
  incrementalColor.nscale8( howMuchBrighter);
  return color + incrementalColor;
}
 
CRGB makeDarker( const CRGB& color, fract8 howMuchDarker)
{
  CRGB newcolor = color;
  newcolor.nscale8( 255 - howMuchDarker);
  return newcolor;
}
 
 
// For illustration purposes, there are two separate implementations
// provided here for the array of 'directionFlags':
// - a simple one, which uses one byte (8 bits) of RAM for each pixel, and
// - a compact one, which uses just one BIT of RAM for each pixel.
 
// Set this to 1 or 8 to select which implementation
// of directionFlags is used.  1=more compact, 8=simpler.
#define BITS_PER_DIRECTION_FLAG 1
 
 
#if BITS_PER_DIRECTION_FLAG == 8
// Simple implementation of the directionFlags array,
// which takes up one byte (eight bits) per pixel.
uint8_t directionFlags[NUM_LEDS];
 
bool getPixelDirection( uint16_t i)
{
  return directionFlags[i];
}
 
void setPixelDirection( uint16_t i, bool dir)
{
  directionFlags[i] = dir;
}
#endif
 
 
#if BITS_PER_DIRECTION_FLAG == 1
// Compact (but more complicated) implementation of
// the directionFlags array, using just one BIT of RAM
// per pixel.  This requires a bunch of bit wrangling,
// but conserves precious RAM.  The cost is a few
// cycles and about 100 bytes of flash program memory.
uint8_t  directionFlags[ (NUM_LEDS + 7) / 8];
 
bool getPixelDirection( uint16_t i)
{
  uint16_t index = i / 8;
  uint8_t  bitNum = i & 0x07;
  // using Arduino 'bitRead' function; expanded code below
  return bitRead( directionFlags[index], bitNum);
  // uint8_t  andMask = 1 << bitNum;
  // return (directionFlags[index] & andMask) != 0;
}
 
void setPixelDirection( uint16_t i, bool dir)
{
  uint16_t index = i / 8;
  uint8_t  bitNum = i & 0x07;
  // using Arduino 'bitWrite' function; expanded code below
  bitWrite( directionFlags[index], bitNum, dir);
  //  uint8_t  orMask = 1 << bitNum;
  //  uint8_t andMask = 255 - orMask;
  //  uint8_t value = directionFlags[index] & andMask;
  //  if( dir ) {
  //    value += orMask;
  //  }
  //  directionFlags[index] = value;
}
#endif