Second try. This is what I have done in the past. No dangling timers either! smile

Code:
// Original code by Mark Lord; free for any use; no conditions.
#define BUTTON3_PIN 19
static bool lightsAreOn;
static int  colorSelection;

// Get a non-zero timeout:
static inline long get_timeout (unsigned int t)
{
   long m = millis() + t;
   return m ? m : 1;
}

// Compare against current time, handling wraparound:
static inline bool time_after (long a, long b)
{
  return (b - a) < 0;
}
#define time_before(a,b) time_after((b),(a))

struct button_s {
  int  pin;
  bool pressed;
  bool tmp_value;
  long timer;
} button3 = {BUTTON3_PIN,0,0,0};

static bool debounce_button (struct button_s *b)
{
  bool new_value = (digitalRead(b->pin) == LOW);
  if (new_value != b->tmp_value) {
    b->tmp_value = new_value;
    b->timer     = get_timeout(10);
    return false;  // no change (debouncing)
  }
  if (b->timer && time_after(millis(), b->timer)) {
    b->timer   = 0;
    if (b->pressed != new_value) {
      b->pressed = new_value;
      return true;  // button changed
    }
  }
  return false;  // no change (yet)
}

void loop ()
{
  if (debounce_button(&button3)) {
    lightsAreOn = button3.pressed;
    if (lightsAreOn)
      colorSelection = (int)random(1,5);
    Serial.print("Pressed=");
    Serial.println(button3.pressed ? "yes" : "no");
  }
}

void setup ()
{
  Serial.begin(115200);
  pinMode(button3.pin, INPUT_PULLUP);
  colorSelection = 4;
}


not tested Tested. Works.
Whenever I can code it myself in a small number of lines (eg. above), that's what I do. Too many Arduino libraries were written by amateurs, and I can do without all of those bugs.


Edited by mlord (25/11/2022 03:45)