In need of code for 32 relay switching randomly

(deleted)

So you got all relays act individually? That's a good start.
Are you using a Mega for this? Or port expanders? The Uno doesn't have that many outputs.

Relay off: does that mean the output signal is LOW or HIGH? Normally when you say a relay is "off" I'd assume that the contacts are open and the lights are off.

Basic layout of this sketch is a finite state machine, started by the button press. Time a lamp is on can increase based on the time it's in the sequence - start at 0.5 second on time at 0 seconds, increasing steadily to 2 seconds when the 20 seconds is reached. Or any other form of progress of course, but you have to define it accurately. Also that on time can be randomised, with the limits (min/max) changing over time.

How many lamps may be on at the same time - minimum/maximum? How long should a lamp remain off before it can be switched on again?

(deleted)

josharoymans:
Hello MVmarle,

That's a new one :slight_smile:

I think it would be nice that during the sequence the lights switch randomly with a maximum of 4 lights on at the same time.

Reading about "random" I understand that in theory it might flash the same light a few times after each other. So preferably the code would "spread" the randomness.

Or enforce lights can not go on again for 1 second after they were off. That's easier.

Furthermore I'd rather talk about "light on" or "light off", and know which one relates to a logic HIGH and which one LOW. How the relays are wired is actually irrelevant to the code.

So the sequence as I understand it now (read your OP carefully: it's contradictory in what you want with lights all on or all off or just a group!):

  • when idle: a specific set of 7 lights on (your chandelier).
  • upon button press: all lights switch off for two seconds.
  • random pattern of lights switching on and off for a period of 20 seconds:
  • maximum 4 lights on at the same time (any minimum? or when one switches off, another switches on, so always 4?)
  • lights remain on for a randomised time of 0.5-1 seconds, that time increasing to 2 seconds near the end of the sequence.
  • after the 20 seconds: the original 7 get switched on, and we're back to idle state.

Suggestion: increase the number of lights on to 7. Then after the 20 seconds are finished, let the lights that are on complete their 2 seconds, and when done replaced by one of the 7 of the chandelier, until all 7 chandelier lights are on and the sequence is completed. It should look like the lights start to "walk home", preventing an abrupt end.
Or start with 4 lights (I would start by lighting up 1, then after say 0.3 seconds the second, etc - so staggered a bit), increase to 5 at 10 seconds in, 6 at 15 seconds, and add the 7th at 20 seconds, which is when the lights start to "walk home".
Should be a nice little light show.

Here's is my approach. Here's a video of it in action: https://streamable.com/exw07

// ------------------------------------------------------------------------------------------------------------- //

constexpr bool ON = HIGH; // define how the pin state relates to the lamp states
constexpr bool OFF = LOW;

// the minimum blink duration in the begining (milliseconds)
constexpr unsigned long minDuration = 1;
// the difference between the minimum and maximum blink duration in the beginning (milliseconds) 
constexpr unsigned long variance = 500; 
// the blink duration at the end (milliseconds)
constexpr unsigned long maxDuration = 2000; 

// ------------------------------------------------------------------------------------------------------------- //

using pin_t = uint8_t;

class RandomlyBlinkingLamp {
  public:
    RandomlyBlinkingLamp() : pin(0) {}
    RandomlyBlinkingLamp(pin_t pin) : pin(pin) {}
    
    void setup() {
      pinMode(pin, OUTPUT);
    }

    void on() {
      digitalWrite(pin, ON);
      interval = 0;
    }

    void off() {
      digitalWrite(pin, OFF);
      interval = 0;
    }

    void startRandomlyBlinking(bool endState) {
      interval = newRandomInterval();
      previousMillis = millis();
      // digitalWrite(pin, interval & 1); // random initial state instead of fade-in from current state
      this->endState = endState;
    }
    
    void loop() {
      if (interval && (millis() - previousMillis >= interval)) {
        previousMillis += interval;
        interval = newRandomInterval();
        if (!interval)
          digitalWrite(pin, endState); // fade out to end state
        else
          toggle();
      }
    }

  private:
    pin_t pin;
    unsigned long interval = 0;
    unsigned long previousMillis = 0;
    bool endState;

    void toggle() {
      digitalWrite(pin, !digitalRead(pin));
    }

    static unsigned long newRandomInterval() {
      unsigned long elapsed = millis() - timerStart;
      if (elapsed >= (timerDuration - maxDuration))
        return 0;
      unsigned long minDelay = map(elapsed, 0, timerDuration - maxDuration, minDuration, maxDuration);
      unsigned long maxDelay = map(elapsed, 0, timerDuration - maxDuration, minDuration + variance, maxDuration);
      unsigned long interval = random(minDelay, maxDelay + 1);
      return interval;
    }

    static unsigned long timerDuration;
    static unsigned long timerStart;

  public:
    static void startTimer(unsigned long duration) {
      timerDuration = duration;
      timerStart = millis();
    }

    static bool timerFinished() {
      return millis() - timerStart >= timerDuration;
    }
};

unsigned long RandomlyBlinkingLamp::timerDuration;
unsigned long RandomlyBlinkingLamp::timerStart;

// ------------------------------------------------------------------------------------------------------------- //

// Change Lamp pin numbers according to your connections
RandomlyBlinkingLamp ceilingLamps[32] = {  3,  4,  5,  6,    7,  8,  9, 10, 
                                          11, 12, 13, 14,   15, 16, 17, 18,
                                          19, 20, 21, 22,   23, 24, 25, 26,
                                          27, 28, 29, 30,   31, 32, 33, 34 };
RandomlyBlinkingLamp chandelierLamps[7] = {   35, 36, 37,   38, 39, 40, 41 };

constexpr pin_t buttonPin = 2;

// ------------------------------------------------------------------------------------------------------------- //

void setup() {
  for (RandomlyBlinkingLamp &lamp : ceilingLamps)
    lamp.setup();
  for (RandomlyBlinkingLamp &lamp : chandelierLamps)
    lamp.setup();
  pinMode(buttonPin, INPUT_PULLUP);
}

// ------------------------------------------------------------------------------------------------------------- //

void loop() {
  
  // All lamps on
  for (RandomlyBlinkingLamp &lamp : ceilingLamps)
    lamp.on();
  for (RandomlyBlinkingLamp &lamp : chandelierLamps)
    lamp.on();

  // wait for button press
  while(digitalRead(buttonPin) == LOW);  
  while(digitalRead(buttonPin) == HIGH);

  // All lamps off for 2 seconds
  for (RandomlyBlinkingLamp &lamp : ceilingLamps)
    lamp.off();
  for (RandomlyBlinkingLamp &lamp : chandelierLamps)
    lamp.off();
    
  delay(2000);
  
  // Randomly blink all lamps for 20 seconds, slowing down to 2 seconds interval at the end
  RandomlyBlinkingLamp::startTimer(20000); // milliseconds
  for (RandomlyBlinkingLamp &lamp : ceilingLamps)
    lamp.startRandomlyBlinking(OFF);
  for (RandomlyBlinkingLamp &lamp : chandelierLamps)
    lamp.startRandomlyBlinking(ON);
  while (!RandomlyBlinkingLamp::timerFinished()) {
    for (RandomlyBlinkingLamp &lamp : ceilingLamps)
      lamp.loop();
    for (RandomlyBlinkingLamp &lamp : chandelierLamps)
      lamp.loop();
  }

  // wait for button press
  while(digitalRead(buttonPin) == HIGH);
  while(digitalRead(buttonPin) == LOW);  
  delay(50); // debounce

}

The on/off time of the lights evolves as follows: starting fast, then slowing down to 2 seconds between transitions:

Pieter

(deleted)

josharoymans:
I cant seem to find the button, or where to connect it to my Mega.

On which nr should I connect the button?

Edit this line to select the pin of the button:

constexpr pin_t buttonPin = 2;

josharoymans:
Also the code includes 39 lamps correct? In total it should be 32, of which 7 is the chandelier.

You can just change the pin numbers in the arrays as well, and change the number of elements from 32 to 25.

// Change Lamp pin numbers according to your connections
RandomlyBlinkingLamp ceilingLamps[32] = {  3,  4,  5,  6,    7,  8,  9, 10, 
                                          11, 12, 13, 14,   15, 16, 17, 18,
                                          19, 20, 21, 22,   23, 24, 25, 26,
                                          27, 28, 29, 30,   31, 32, 33, 34 };
RandomlyBlinkingLamp chandelierLamps[7] = {   35, 36, 37,   38, 39, 40, 41 };

(deleted)

(deleted)

I see. It would be a good idea to use proper debouncing. See attachment.

LED-random-art-exh-normal-debounce.zip (3.21 KB)

(deleted)

(deleted)