I'm want to make pixels on a string blink independently and randomly

Hello all,

I have a string of 50 Neopixels that I'm experimenting with. It is the 5 volt kind. WS2811

[

The adafruit_neopixel library is the only library I've been able to get working on this. No luck with the FastLED library. That's fine for now. My real problem here is that this code is very difficult for me to understand and there's not a lot of values I can change around to get a sense of what is going on.

What the code does is turn on one pixel at a time to a random color. The pixels stay lit as the entire string slowly populates with randomly assigned colors. Eventually each pixel is randomly chosen again to become a new random color.

What I'd like for this program (or a similar program) to do is to assign each pixel a random blinking status. Each pixel would blink independently for a random amount of time. Their time off would have a minimum of 1000 ms and a maximum of 10000 ms. Their time lit would be similar.

Picture a string of christmas mini lights, except each bulb is a flasher and they're all wired in parallel or something. You would have roughly anywhere from zero to 30 lights to the entire strand lit at any given moment with each bulb having their own individual lifespans. Like fireflies.

Here is the code I'm playing with.

    #include <Adafruit_NeoPixel.h>

#define PIN 6
#define LED_COUNT 50
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, PIN, NEO_RGB + NEO_KHZ800);

void setup() {
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

void loop()
{
  randomPixelColor(100);

}

void randomPixelColor(int wait)
{
  int i= random(strip.numPixels());

  uint32_t c = random(2147483647); // I have no idea what this crazy number does.
  strip.setPixelColor(i, c);
  strip.show();
  delay(wait);

}    // end void randomPixelColor()

I'd appreciate any ideas.

Thanks](https://www.amazon.com/WESIRI-Diffused-Digital-Addressable-Controller/dp/B076V6FSB6/ref=sr_1_1?s=electronics&ie=UTF8&qid=1513490960&sr=8-1&keywords=wesiri+pixels)

uint32_t c = random(2147483647); // I have no idea what this crazy number does.

This limit the number of colours displayable to a reasonable amount :slight_smile:

You need to define an array to hold the last on time (mS) and the status (on/off) of each led.
Scan the array periodically, making random changes which conform to your rules, then redisplay the whole lot.

6v6gt:

uint32_t c = random(2147483647); // I have no idea what this crazy number does.

This limit the number of colours displayable to a reasonable amount :slight_smile:

2147483647 is 0x7FFFFFFF, the 'biggest' color possible is 0xFFFFFF, so I see no restriction.

I see no reason for that crazy number.

Rumblegram:
What I'd like for this program (or a similar program) to do is to assign each pixel a random blinking status. Each pixel would blink independently for a random amount of time. Their time off would have a minimum of 1000 ms and a maximum of 10000 ms. Their time lit would be similar.

So, working through your requirements, for each pixel you want:

  1. blinking status.
  2. an off time
  3. an on time

Also since we have a time (for on and off), we must also need some sort of timer, so now we have:

  1. a status (are we currently ON or OFF)
  2. an off time
  3. an on time
  4. something to count time

There is also the colour; assuming you want to set any LED to blink on/off for the given times with a given colour (instead of randomly colouring the LED on each blink), we now need:

  1. a status (are we currently ON or OFF)
  2. an off time
  3. an on time
  4. something to count time
  5. the LED colour

So, you need 50 sets of all of these things so any LED can do something different to any other.

The ideal software things we can use here are structures and arrays:

// Information about one LED
//
struct oneLED{
 int status;             // 1. a status (are we currently 1=ON or 0=OFF)
 int offTime;           // 2. an off time
 int onTime;            // 3. an on time
 int timer;             // 4. something to count time
 uint32_t colour;       // 5. the LED colour

};

// an array of 50 LEDs
//
oneLED LEDarray[50];

Then you can fill up your array of LEDs with suitable values

// fill array with descriptions of all LEDs
// - you either want to do this once in setup(), or every few seconds or something.
for( i=0; i<strip.numPixels(); i++ )
{
  LEDarray[ i ].status= random( 0, 1 );          // random on/off
  LEDarray[ i ].timer= 0; 
  LEDarray[ i ].offTime= random( 1000, 10000 );
  LEDarray[ i ].onTime= random( 1000, 10000 );
  LEDarray[ i ].colour= random(2147483647);  // 0x7FFFFFF in hex, random Red,Green and Blue
}

When you have that set up, you need to update all the LED status's and output the lot to the strip:

// For each LED, work out if the timer has run out, turn the LED status to on or off and reload the timer
// with the next on or off time.
// - we'll skip this for now
//


// For each LED, read it's status and colour to update the strip
//
for( i=0; i<strip.numPixels(); i++ )
{
  if( LEDarray[ i ].status == 1 )
  {
     strip.setPixelColor(i, c);    // LED on
  }else{
     strip.setPixelColor(i, 0);   // LED off
  }
}
strip.show();

For starters, both those bits of code in loop() should so what you already have, it sets the colours of all the LEDS in the array, then it goes through the array and outputs them all.

Try and work out what you need in between to deal with the timers.

Yours,
TonyWilk

Rumblegram:
I'd appreciate any ideas.

I tested this on a 100 LED strip and it worked well enough, though the colors seem a bit pastel using the random color function.

The density of lit LEDs seems low, but that would be manageable too.

here is the sketch:

#include <Adafruit_NeoPixel.h>

#define PIN 6
#define LED_COUNT 100

class BlinkyPixel : public Adafruit_NeoPixel {
  public:
    BlinkyPixel(int numLeds, int pin, int type) : (numLeds, pin, type)
    {
      timer = new Timer[numLeds];
    };
    void update(void);
    void init();
  private:
    struct Timer{
      uint32_t nextUpdateMillis;
      bool state;
    };
    Timer* timer;
};

void BlinkyPixel::init()
{
  begin();
  show();
  randomSeed(analogRead(A0));
  for (size_t i = 0; i < numPixels(); i++)
  {
    timer[i].state = random(2);
    timer[i].state? setPixelColor(i,random(0xFF), random(0xFF), random(0xFF)) : setPixelColor(i, 0, 0, 0);
    timer[i].nextUpdateMillis = millis() + random(500, 1000);
  }
  show();
}

void BlinkyPixel::update()
{
  for (size_t i = 0; i < numPixels(); i++)
  {
    if (millis() >= timer[i].nextUpdateMillis)
    {
      
      if (timer[i].state)
      {
        setPixelColor(i, 0, 0, 0);
      }
      else 
      {
        setPixelColor(i, random(0xFF), random(0xFF), random(0xFF));
        if(i == 0) Serial.println(F("Switching State ON"));
      }
      timer[i].state = !timer[i].state;
      timer[i].nextUpdateMillis = millis() + random(1000, 10000);
    }
    show();
  }
}

BlinkyPixel strip(LED_COUNT, PIN, NEO_RGB + NEO_KHZ800);


void setup() 
{
  strip.init();
}

void loop() 
{
  strip.update();
}

same thing but will randomly select from predetermined set of colors:

#include <Adafruit_NeoPixel.h>

#define PIN 6
#define LED_COUNT 100

uint32_t colors[] = {
  0x00FF0000,  // Red
  0x0000FF00,  // Green
  0x000000FF,  // Blue
  0x00FFFFFF,  // White
};


class BlinkyPixel : public Adafruit_NeoPixel {
  public:
    BlinkyPixel(int numLeds, int pin, int type) : (numLeds, pin, type)
    {
      timer = new Timer[numLeds];
    };
    void update(void);
    void init();
  private:
    struct Timer{
      uint32_t nextUpdateMillis;
      bool state;
    };
    Timer* timer;
};

void BlinkyPixel::init()
{
  begin();
  show();
  randomSeed(analogRead(A0));
  for (size_t i = 0; i < numPixels(); i++)
  {
    timer[i].state = random(2);
    timer[i].state? setPixelColor(i,colors[random(sizeof(colors)/sizeof(uint32_t))]) : setPixelColor(i, 0, 0, 0);
    //timer[i].state? setPixelColor(i,random(0xFF), random(0xFF), random(0xFF)) : setPixelColor(i, 0, 0, 0);

    timer[i].nextUpdateMillis = millis() + random(1000, 10000);
  }
  show();
}

void BlinkyPixel::update()
{
  for (size_t i = 0; i < numPixels(); i++)
  {
    if (millis() >= timer[i].nextUpdateMillis)
    {
      
      if (timer[i].state)
      {
        setPixelColor(i, 0, 0, 0);
      }
      else 
      {
        setPixelColor(i,colors[random(sizeof(colors)/sizeof(uint32_t))]);
        //setPixelColor(i, random(0xFF), random(0xFF), random(0xFF));
      }
      timer[i].state = !timer[i].state;
      timer[i].nextUpdateMillis = millis() + random(1000, 10000);
    }
    show();
  }
}


BlinkyPixel strip(LED_COUNT, PIN, NEO_RGB + NEO_KHZ800);


void setup() 
{
  strip.init();
}

void loop() 
{
  strip.update();
}

TonyWilk, thank you. You have gift wrapped for me a lucid breakdown of a very handsome code. I hate that I can't unwrap it. I don't know enough about functions and syntax to construct this into a proper program. I'm assuming your first block of code comes before the setup(or does that even matter?). The second block goes in setup. The third would come after that. Possibly after void or void ()loop? Let me show you what I did to your code. I have left some of my original code remaining like the library and other things I've come across as routine. The way I have it set up, I'm running into a lot of "expected unqualified errors" when compiling.

#include <Adafruit_NeoPixel.h>
 
#define PIN 6
#define LED_COUNT 50
 
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, PIN, NEO_RGB + NEO_KHZ800);
 


// Information about one LED
//
struct oneLED{
 int status;            // 1. a status (are we currently 1=ON or 0=OFF)
 int offTime;           // 2. an off time
 int onTime;            // 3. an on time
 int timer;             // 4. something to count time
 uint32_t colour;       // 5. the LED colour

};

// an array of 50 LEDs
//
oneLED LEDarray[50];
 
void setup() //{
 // strip.begin();
 // strip.show(); // Initialize all pixels to 'off'
//}

// fill array with descriptions of all LEDs
// - you either want to do this once in setup(), or every few seconds or something.
  for( i=0; i<strip.numPixels(); i++ )
{
  LEDarray[ i ].status= random( 0, 1 );          // random on/off
  LEDarray[ i ].timer= 0;
  LEDarray[ i ].offTime= random( 1000, 10000 );
  LEDarray[ i ].onTime= random( 1000, 10000 );
  LEDarray[ i ].colour= random(2147483647);  // 0x7FFFFFF in hex, random Red,Green and Blue
}
  void loop() {
  int i = random(50);
  strip.setPixelColor(i, strip.Color(random(25),random(25),random(25)));
  strip.show();
    delay(100);

   strip.setPixelColor(i, strip.Color(0,0,0)); //This clears the strand to black
   strip.show();
    delay(1000); //How do I make the delay random with a min/max time 
}

{
// For each LED, work out if the timer has run out, turn the LED status to on or off and reload the timer
// with the next on or off time.
// - we'll skip this for now
//


// For each LED, read it's status and colour to update the strip
//
for( i=0; i<strip.numPixels(); i++ )
{
  if( LEDarray[ i ].status == 1 )
  {
     strip.setPixelColor(i, c);    // LED on
  }else{
     strip.setPixelColor(i, 0);   // LED off
  }
}
strip.show();

BulldogLowell, your first code does exactly what I want. It works perfectly. Unfortunately, your second code isn't going through too well. The lights get excited for a moment and then turn off. That may be due to my low amp power source, though. I'm not sure. The only difference I see between your two codes are these llines. I like your idea of using pre selected colors to randomly switch between. If you notice I turned down the brightness a little bit with the hex values.

uint32_t colors[] = {
  0x00993300,  // Red
  0x00009933,  // Green
  0x000000FF,  // Blue
  0x00333399,  // White
};
else
      {
        setPixelColor(i,colors[random(sizeof(colors)/sizeof(uint32_t))]);
        //setPixelColor(i, random(0xFF), random(0xFF), random(0xFF));
      }
      timer[i].state = !timer[i].state;
      timer[i].nextUpdateMillis = millis() + random(1000, 10000);
    }

I don't know enough about functions and syntax to construct this into a proper program.

Ok, I've tried to simplify it so this is a complete sketch... try and work your way through this:

// Information about one LED
// - since you seem to be happy changing the blink time and colour
//   on every blink, we don't need to keep them any more
// - all we need now is ON or OFF and a timer 
//
struct oneLED{
 int status;            // 1. a status (are we currently 1=ON or 0=OFF)
 uint32_t timeout;      // 4. something to count time, the time in milliseconds when this times out
};

#define NO_OF_LEDS 50
#define NO_OF_COLOURS 7

//--------------------------
// an array of 50 LEDs
//
oneLED LEDarray[NO_OF_LEDS];

// you now want an array of colours to choose from
//
uint32_t myColours[NO_OF_COLOURS]={
  0x00200000,     // red
  0x00002000,     // green     // These are set 'dim' at the moment
  0x00000020,     // blue      // in case your power supply
  0x00202000,     // yellow    // can't handle full brightness
  0x00200020,     // purple
  0x00002020,     // cyan
  0x00202020      // white  
};

//--------------------------
void setup() {
  int i;
  //Serial.begin(19200);
  
  // fill array with setup values for  all LEDs
  // 
  for( i=0; i<NO_OF_LEDS; i++ )
  {
    LEDarray[ i ].status= 0;          // start with all LEDs off
    LEDarray[ i ].timeout= 0; 
  }

}

//--------------------------
void loop() 
{
  int i;
  uint32_t now_millis;
  uint32_t colour;

  // For each LED, work out if the timer has run out
  // - if it has:
  //    turn the LED status to OFF or to ON with a random colour 
  //    and reload the timer with a random value
  //
  now_millis= millis();  // get time now
  
  // For each LED, read it's status and colour to update the strip
  //
  for( i=0; i<NO_OF_LEDS; i++ )
  {
    // is time 'now' past the time we set for this LED ?
    if( now_millis > LEDarray[i].timeout )
    {
      // set next timeout 1000 to 10000 in the future
      LEDarray[i].timeout = now_millis + random( 1000, 10000 );

      if( LEDarray[i].status == 1 )  
      {
        // LED is currently ON, turn it off:
        LEDarray[i].status = 0;
        strip.setPixelColor(i, 0);   // LED off
      }else
      {
        // LED is currently OFF, give it a colour to turn it on:
        LEDarray[i].status = 1;
        colour= myColours[ random( NO_OF_COLOURS ) ];   //pick a random colour
        strip.setPixelColor(i, colour);    // LED on
      }
    }
  }
  strip.show();
}

Notice that I've defined the entries in myColours[] with low numbers (e.g. red= 0x00200000) to set a low brightness (instead of 0x00FF0000 which would be full bright red) because your power supply might not be big enough - so start with low brightness and see if it works.

Try changing bits yourself - but do keep separate copies of your sketches, it's a real pain when you had something working, altered it and now the 'good version' is gone.

Yours,
TonyWilk

Rumblegram:
BulldogLowell[/b], your first code does exactly what I want. It works perfectly. Unfortunately, your second code isn't going through too well. The lights get excited for a moment and then turn off. That may be due to my low amp power source, though. I'm not sure. The only difference I see between your two codes are these llines. I like your idea of using pre selected colors to randomly switch between. If you notice I turned down the brightness a little bit with the hex values.

Thanks, having tested both, they work fine if you have enough power. I initially tested on a strip of 240 and saw the same kind of failure, my power supply wasn't enough!

Adjusting the brightness on the color selections was a good idea, ultimately draw less power but you could also call to setBrightness() like this:

strip.setBrightness(64);

in setup() and it will automatically scale down each color (0 to 255 scale) when the Neopixel library sends the values to the pixels.

Also you can see that I prefer a functional approach versus slogging through a bunch of lines in my main program loop() function. :wink:

Bulldog, I upgraded to a 3 amp power source behind my string but that second code of yours still isn't working. I'm going to try it with another string of NEOpixels tomorrow and see if something isn't fried. Any other ideas of what I should troubleshoot? Pins? Library install?

BTW that setBrightness() is pretty handy with your first code so I imagine it will be perfect when I get your second code with the set colors working. Thanks

TonyWilk, my setup isn't responding to your last sketch. Your new sketch is very different from the first one so I'm gonna study it some and get back to you.

Thank you

Rumblegram:
Bulldog, I upgraded to a 3 amp power source behind my string but that second code of yours still isn't working. I'm going to try it with another string of NEOpixels tomorrow and see if something isn't fried. Any other ideas of what I should troubleshoot? Pins? Library install?

BTW that setBrightness() is pretty handy with your first code so I imagine it will be perfect when I get your second code with the set colors working. Thanks

  1. Check that you have the correct local settings for your RGB setup, mine is different:
(LED_COUNT, PIN, NEO_RGB + NEO_KHZ800);
  1. try it with 10 or 20 pixels using he same string:
#define LED_COUNT 50
  1. verify your ledcount nd pin are correct.

  2. comment out white here

uint32_t colors[] = {
  0x00FF0000,  // Red
  0x0000FF00,  // Green
  0x000000FF,  // Blue
  //0x00FFFFFF,  // White //<<<<<<, comment this out
};

I tested this... it works.

here it is again, in case there is an error above:

#include <Adafruit_NeoPixel.h>

#define PIN 6
#define LED_COUNT 50

const int buttonPin = 2;

uint32_t colors[] = {
  0x00FF0000,  // Red
  0x0000FF00,  // Green
  0x000000FF,  // Blue
  0x00FFFFFF,  // White
};


class BlinkyPixel : public Adafruit_NeoPixel {
  public:
    BlinkyPixel(int numLeds, int pin, int type) : (numLeds, pin, type)
    {
      timer = new Timer[numLeds];
    };
    void update(void);
    void init(int brightness);
    void init(void);
  private:
    struct Timer{
      uint32_t nextUpdateMillis;
      bool state;
    };
    Timer* timer;
};

void BlinkyPixel::init(int brightness)
{
  begin();
  setBrightness(brightness);
  show();
  randomSeed(analogRead(A0));
  for (size_t i = 0; i < numPixels(); i++)
  {
    timer[i].state = random(2);
    timer[i].state? setPixelColor(i,colors[random(sizeof(colors)/sizeof(uint32_t))]) : setPixelColor(i, 0, 0, 0);
    //timer[i].state? setPixelColor(i, random(0x00FFFFFF)) : setPixelColor(i, 0, 0, 0);
    //timer[i].state? setPixelColor(i,random(0xFF), random(0xFF), random(0xFF)) : setPixelColor(i, 0, 0, 0);
    timer[i].nextUpdateMillis = millis() + random(1000);
  }
  show();
}

void BlinkyPixel::init(void)
{
  begin();
  show();
  randomSeed(analogRead(A0));
  for (size_t i = 0; i < numPixels(); i++)
  {
    timer[i].state = random(2);
    timer[i].state? setPixelColor(i,colors[random(sizeof(colors)/sizeof(uint32_t))]) : setPixelColor(i, 0, 0, 0);
    //timer[i].state? setPixelColor(i, random(0x00FFFFFF)) : setPixelColor(i, 0, 0, 0);
    //timer[i].state? setPixelColor(i,random(0xFF), random(0xFF), random(0xFF)) : setPixelColor(i, 0, 0, 0);
    timer[i].nextUpdateMillis = millis() + random(1000);
  }
  show();
}

void BlinkyPixel::update(void)
{
  bool doUpdate = false;
  for (size_t i = 0; i < numPixels(); i++)
  {
    doUpdate = true;
    if (millis() >= timer[i].nextUpdateMillis)
    {
      if (timer[i].state)
      {
        setPixelColor(i, 0, 0, 0);
      }
      else 
      {
        setPixelColor(i,colors[random(sizeof(colors)/sizeof(uint32_t))]);
        //setPixelColor(i, random(0x00FFFFFF));
        //setPixelColor(i, random(0xFF), random(0xFF), random(0xFF));
      }
      timer[i].state = !timer[i].state;
      timer[i].nextUpdateMillis = millis() + random(100, 1000);
    }
  }
  if(doUpdate) 
  {
    show();
  }
}


BlinkyPixel strip(LED_COUNT, PIN, NEO_GRB + NEO_KHZ800);

void setup() 
{
//  Serial.begin(9600);
  pinMode(buttonPin, INPUT_PULLUP);
  strip.init(255);
}

void loop() 
{
  static bool state = true;
  if (state)
  {
    strip.update();
  }
  
  if (pressed(buttonPin))
  {
    state = !state;
    if (!state)
    {
      for (size_t i = 0; i < strip.numPixels(); i++)
      {
        strip.setPixelColor(i, 0, 0, 0);
      }
      strip.show();
    }
    else
    {
      strip.init();
    }
  }
}

bool pressed(int pin)
{
  static uint32_t lastPressMillis = 0;
  bool lastState = HIGH;
  const uint16_t debounceTime = 50;
  int currentState = digitalRead(pin);
  if (currentState != lastState and millis() - lastPressMillis > debounceTime)
  {
    lastState = currentState;
    if (currentState == LOW)
    {
      lastPressMillis = millis();
//      Serial.println(F("pressed"));
      return true;
    }
  }
  return false;
}

I added a an overload of init() where you can add the brightness....