LED lighted buttons, Timers and activating keyboard commands

I have a project where a client wants us to create a panel with 18 LED lit buttons. Each button when pressed will turn on it's LED and trigger a 45 second video to play from a laptop. Seems easy enough to trigger video playback on a laptop using keyboard.h library and turninig on/off the LED from the buttons isn't complicated either.

However, the client wants the posibility of two things to happen ('or' statement), press one button, the button LED lights and the video plays for 45 seconds and then the button LED turns off, OR if another button is pressed it's LED turns on and plays that corresponding video.

I am not sure how to approach the coding for this project and given that there are 18 LED buttons with 18 videos to play the coding seams long and perhaps complex. looking for any advice.

I plan to use a Due since it has a lot of available IO and can act as a keyboard to send mapped commands to a media player on a laptop.

cheers...

Back at you.

When the second button is pressed during the first button video, does the first button video stop?

Please post code that handles any buttons and LEDs, and sends commands to the external system, however that is done.

Is there any need to hear from the external system? How does your thing know, for example… Oh wait, you said all videos were 45 seconds.

a7

Hi Alto,

thanks for the quick reply. I haven't started to code this yet because I was still trying to figure how to approach it. I didn't want to go down a rabbit hole since this could get lengthy with all the buttons.

Yes, when the second button is pressed it will interupt the first video then start playing the video associated with its button. For example, Button_1 would have a keyboard.h command to send an 'A' to the laptop where that key is mapped to control a video. Button_2, when pressed would interupt the first video and play it's corresponding video, say mapped to the letter 'B'. The interupts all work fine within the media playback software. Where I am having trouble is turning on and off the LED's on the buttons. Seems easy enough, but they have to be on when pressed for 45 seconds then turn off or they turn off when another button is pressed. Like an overide or interupt. There are 18 of them, so I am looking at trying to make all these states work without it being a huge sketch.

OK, I see.

This is straight ahead. I am tempted to say if someone is paying you to do this you probably know how to…

If  button X is pressed, the LED X comes on, and the timer is initiated.

(If another button LED was on, it is turned off, and a message sent.)

A message is sent to start video X

If the running timer expires, turn off LED X. And send a message?

Code writes itself. :expressionless:

No one can help more until we start seeing how deep this hole is, for you. Since we have no idea what your skill level is, it is impossible to provide appropriate examples or advice.

Arrays will make it easy. Some would start throwing structs and classes and libraries at you.

Ask nice or just be that random lucky poster and someone might just dash off some code for you.

What Arduino board are you using? 18 buttons and 18 LEDs…

Also, do you have a particular illuminated LED/pushbutton in hand?

a7

Indeed and I do understand it's hard to help somone with coding when they have no code to demonstrate. Thats a valid point and I need to start getting something into the sketch to at least verify a few things such as perhaps using millis for timing and perhaps setting a const. int ledDuration for the LED 'ON' state. I am a discrite component level designer and sort of fumble my way through the Arduino. That said, I am old, but not too old to learn.

Below is some context of how this will be set-up. I plan to use the Due because it can act as a USB keyboard when connected to a PC. The software we are using for the video player is Resolume and you can easily map keboard keys and use the library keyboard.h to send commands to Resolume. We have used this library many times before with the Leonardo and it works quite well. Each button will have a keybaord command assigned to it in the sketch. The small Mosfet driver board is just used to switch a seperate 12V supply to power on the LED's in the buttons. The Due only has 3.3V IO so you need to external driver to keep your board safe.

Due Video:
Due Vid

Due Set-up:
Due Set-up

OK I never used a Due.

It has a crap-ton of I/O pins. Doing a direct one pin one LED - one pin one pushbutton arrangement would certainly be possible.

I suggest instead using matrix scanning for both switches and LEDs. That would take more software, but make wiring a bit less nightmarish. Nothing you wouldn't be able to write, steal borrow or find a library to do.

5 shared columns, 4 rows for switches and 4 rows for LEDs means you could use as few as 13 I/O pins.

On the video I see that neat illuminate switch. I can't help but notice it lights up when you release the button. If you chose that, cool. If that just happened, IMO the LED should come on when you press the button and that is also the time to send any message out as well as extinguish/cancel a video in progress.

I have no life. I honestly wish this was my problem not yours, looks like it will turn out kinda pretty, inside and out.

a7

Now I am starting to disagree with myself. Don't worry, it happens quite often.

I think (at this moment!) that just going ahead with the simple but wiry solution of using one pin for each LED and one pin for each switch will...

...leave you with the most time to get the software working well.

In between: scan matrix for the switches, one/per pins for the LEDs.

With just 18 it's sorta in the could-go-either way; often we are talking about using an UNO or similarly resource-constrained Arduino board, and you'd have to use something to create the function of many more I/Os than you actually have.

a7

This is an interesting project, huh? It might have gotten a bit easier or perhaps more complicated depending on how you look at it. I was on a zoom meeting late yesterday with the media designer and he indicated that the buttons do NOT need to override each other. For example, if you press button 4 it will light up, play it's video and then the LED will turn off. Pretty simple since the mechanism for stopping and transitions of the videos reside in the Resolume player. All I need to do is send it a command to start the video. That is pretty easy with the keyboard.h library. Not sure if you have ever used it before, but I use it all the time with the Leonardo. I used to use a MIDI controller sketch with an UNO and that was so cumbersome. The Windows machines we use with Resolume had to have MIDI drivers installed then a Serial to MIDI interface program. All of it had to be synched properly, so we needed an easier way.

Since I have so many damn connections to make the Due seemed like the obvious choice. I could have done this with the Leonardo, but it doesn't give me flexibility if they (client) add another button or some other control element. I would be out of I/O and then I would probably just go jump off the roof.

Not having the buttons override each other is great. However, now each video will play at different durations. Well that sucks...so, now I might have 18 different durations before the button_LED needs to turn off.

OK, since no code yet, don't blame me if I point out a few obvious things, and ask a few questions that arise.

Zeroeth, I hope you know how to use for loops.

First, you should use arrays, at least, to organize and hold and make access to all the stuff for the 18 things easy. By index.

Each "thing" is an LED, a button, a message code and the constant time of the associated video. If you know about the C/C++ feature called a struct, that might be handy, but arrays as a first step is entirely adequate if you are learning as you go.

Uh oh, where do these video durations come from, and how are they to be fixed in the code if when some genius decides to change them?

What sense is the base system to make of the fact that as specified to this point, you could end up with 7 illuminated buttons all ticking away on their individual timers… is the base system doing seven things, or just the last? I don't care, but someone will… why are six LEDs still on?

With direct wiring of switches and LEDs, the code is trivially simple. Cough.

pseudo-code alert!

every 50 milliseconds
for each of the 18 "things":
   if the button is pressed
        turn on LED
        start timer
        send message
    if the timer is expired
        extinguish the LED

The "every 50 milliseconds" will provide an adequately rapid response, and totally sidestep any issues with contact bounce from your switches. So no multiple messages sent from a single user action.

The only mildly advanced part of this pseudo-code is the "every 50 milliseconds".

You can go noob, and just stick delay(50); into you loop() as the last (or first!) thing it does. I am obsessed with avoiding delay(), but in this case I think it is reasonable to use it.

Or you could take a small step towards "accomplished amateur" by employing the basic technique revealed in the classic Arduino "blink without delay" pattern, a version of which is in the IDE examples or a google away. And make the loop() run at exactly 20 Hz. Or whatever speed.

Which sooner later you will want and need to learn about (blink without delay). It's not a big deal, just needs a bit of work and the Aha! moment you'll experience, so maybe this is the time.

HTH

a7

Well, I had thought of using 'millis' timer for the LED timing and would go something like below. however, you bring up a good point about someone getting bored with the current video and decides to press another button. That buttons LED would light up, but because of the lockout function in Resolume, the previous video would contrinue to play until it ended. Two LED's would be on and that ain't good. Its almost, I hate to say, something that 'delay' could be used to lock out any user monkey business until the timing sequence is done. Thoughts?

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long duration1 = 10000
const  unsigned long duration2 = 20000
// and so forth for the different video time intervals, duration3, 4, etc.
const byte ledPin1 = 12

void setup()
{
pinMode (ledPin1, OUTPUT);  // I guess for 18 more pins
startMillis = millis();  //start her up
} 

void loop()

// code here for the button press, turn on ledPin1, send key stroke to Resolume//
{ 
currentMillis = millis();  // get the current time
if (currentMillis - startMillis >=  duration1)
digitalWrite (ledPin1, LOW);
// more code like above for the other buttons, LEDs, keystroke commands...Ugh!//

Yuck. :wink:

I suggest when a button has been pressed that for the duration of the video the other buttons react by blinking on briefly, so the user sees the system seeing the input and kinda rejecting it.

This could easily be done by checking if there is already a video playing, and lighting the new LED but not sending a message, and setting the timer to 300 ms instead of the stored duration for the corresponding video.

const unsigned long duration1 = 10000
const unsigned long duration2 = 20000

Stop. Do no pass Go, do not collect $200.

You need to learn about arrays before you go any further and end up with 18 blocks of nearly identical code which will be a nightmare to write, difficult to make error free and very annoying to enhance or modify.

Arrays:

unsinged long videoDuration[18]  = {
         10000, 20000, ... 
}

Any time you are naming things with a numeral attached is a sign that arrays might be better. Any time you are cutting, pasting and editing code to make one more of something is a sign that arrays (and/or functions) might be better.

Functions.

So two things to get a grip on code-chops wise. Neither is terribly hard to get conceptually I will allow that there is some pesky syntax to become aware of and fluent with. Pesky.

a7

OK, Array's....copy that. Time to get a beer, some doritos and a breadboard. Now, the 'For' loop to me always had an increment counter attached to it. Such as number of button presses or LED blinks or motor turns until something happens or a state changes. I really don't need anything to happen here except for time to go by then turn off the LED.

Oh, one more consideration. This is not a sequential thing. The user can and likley will, randomly select a button to press. They can just as easily select button 10 over button 1 to start their journey. In an array, how does button 10 get assigned a certain duration, button 1, etc.? I guess i should Google that.

A for loop can iterate over anything. Like 18 buttons.

The pseudo code I wrote above will execute in, to a first approximation, no time at all, and do all 18 LEDs in, again, no significant time.

pseudo-code alert!

every 50 milliseconds
for each of the 18 "things":
   if the button is pressed

        turn on LED

        if a video is in progress
            start timer 333 ms (flash. busy.)
        else
            send message
            set timer to the video duration
            set global video in progress (save number of video)

    if the timer is expired

        extinguish the LED
        if this was the video in progress
            clear the global video in progress  (set to impossible number as a flag)

The for above is literally standing in for a for loop.

In an array, how does button 10 get assigned a certain duration?

Because the duration for video N will be retrieved from the array at index N.

Same as the pin numbers for the LEDs:

    const unsinged char ledPins[18] = {
        34, 35, 36, 55, ... 
    }

And the pins where the switches are:

    const unsinged char buttonPins[18] = {
        11, 12, 13, … 
    }

And so forth. I think the article I linked above should make it all clear. If not, google or ask questions here.

a7

Thank you for the article and getting me started down the road on the array functions. I really appreciate all your help. I have read many articles and watched a few videos. That said, the code below is very 'caveman', in approach. It's a battle axe vs a scalpel, but I needed to get something working as a proof of concept pretty quickly. This code shows 5- buttons and 5 LED’s with a little lag time before they turn on after the video starts (client wants this, ugh!).

This is easier to keep track of than repeating if statements 18 times and using delay. Anyway, I will send some video showing how this will control the media player. It’s kinda cool.

#include <Keyboard.h>    //  Keyboard firmware: Law_042619


//---------------------------------------------------------
//                           Setup
//---------------------------------------------------------

int led1 = 2;   // LED on pin 2
int led2 = 3;   // LED on pin 3
int led3 = 4;   // LED on pin 4
int led4 = 5;   // LED on pin 5
int led5 = 6;   // LED on pin 6

void setup() {
  pinMode(8, INPUT_PULLUP); // sets pin 3 to input & pulls it high w/ internal resistor
  pinMode(9, INPUT_PULLUP); // sets pin 4 to input & pulls it high w/ internal resistor
  pinMode(10, INPUT_PULLUP); // sets pin 5 to input & pulls it high w/ internal resistor
  pinMode(11, INPUT_PULLUP); // sets pin 6 to input & pulls it high w/ internal resistor
  pinMode(12, INPUT_PULLUP); // sets pin 7 to input & pulls it high w/ internal resistor

  pinMode(led1, OUTPUT); //led1 is an output
  pinMode(led2, OUTPUT); //led2 is an output
  pinMode(led3, OUTPUT); //led3 is an output
  pinMode(led4, OUTPUT); //led4 is an output
  pinMode(led5, OUTPUT); //led5 is an output


  Serial.begin(9600);       // begin serial comms for debugging
}

//---------------------------------------------------------
//              Loop
//---------------------------------------------------------
void loop()
{

  Keyboard.begin();         //begin keyboard
  if (digitalRead(8) == 0)  // if button 8 is pushed
  {
    Keyboard.write('z');  // send single character "z"
    delay(2000);           // delay so you don't get 20 A's
    digitalWrite(led1, HIGH); //turn on led1
    delay(10000);
    digitalWrite(led1, LOW); //turn off led1 after 12 seconds
  }

  if (digitalRead(9) == 0)  // if button 9 is pressed
  {
    Keyboard.write('x'); // send single letter "x"
    delay(2000);
    digitalWrite(led2, HIGH); //turn on led2
    delay(10000);
    digitalWrite(led2, LOW); //turn off led1 after 12 seconds
  }

  if (digitalRead(10) == 0)  //if button 10 is pressed
  {
    Keyboard.write('c');         // send single letter "c"
    delay(2000);
    digitalWrite(led3, HIGH); //turn on led3
    delay(10000);
    digitalWrite(led3, LOW); //turn off led1 after 12 seconds
  }

  if (digitalRead(11) == 0)  //if button 11 is pressed
  {
    Keyboard.write('v');         // send single letter "v"
    delay(2000);
    digitalWrite(led4, HIGH); //turn on led4
    delay(10000);
    digitalWrite(led4, LOW); //turn off led1 after 12 seconds

  }

  if (digitalRead(12) == 0)  //if button 5 is pressed
  {
    Keyboard.write('b');         // send single letter "b"
    delay(2000);
    digitalWrite(led5, HIGH); //turn on led5
    delay(10000);
    digitalWrite(led5, LOW); //turn off led1 after 12 seconds
  }

   Keyboard.end();                 //stops keyboard

}type or paste code here

Clients… can't live with them, can't… well, you know.

In this pattern

  if (digitalRead(11) == 0)  //if button 11 is pressed
  {
    Keyboard.write('v');         // send single letter "v"
    delay(2000);
    digitalWrite(led4, HIGH); //turn on led4
    delay(10000);
    digitalWrite(led4, LOW); //turn off led1 after 12 seconds

  }

Do I correctly see a 2000 ms delay between pressing the button/launching the video and the lighting of the corresponding LED?

Is 10000 ms just a "for example", to be adjusted to the actual length (minus the already 2000 ms BTW) of the corresponding video?

TBH I wrote the sketch "my way", did I say I have no life? Anyway, your way looks good, but when I am at the big rig again I will post a pattern using arrays but still relying on delay() for you to ponder. Or use.

One simple concept and 18 blocks of code become one, and all things that might need tweaking are in one place, not s c a t t e r e d over 100+ lines of code.

Although I must observe that cut/paste/edit really makes productivity go up - you can knock out dozens of lines of code in no time. :wink:

Now the client want a delay between pressing a button and the LED coming on. Tell him or her that is the stupidest thing I ever heard of, you can say I said so. User interface convention is to provide feedback for user action in a timely fashion.

Even if there was some good reason, two seconds is an eternity during which a certain personality type might find myself pushing buttons at random looking for one what works…

It may get worse: if the requirement becomes something like "start flashing the LED immediately the button is pressed, go solid after N ms when we can be sure the video is rolling, extinguish when we think the vid is over"

The open loop nature of this is a bit of a nightmare. I don't know if your controlled system has any means for sending the Arduino a signal "all done" that could be used instead of the blind proxy (time elapsed) the system now uses.

Did you ever post a link to the exact switch? Do you like them? I've purchased a few special switches now and again and I can say buying randomly results in random satisfaction or, sadly, no joy.

a7

Yes, the 2 second delay between the buuton press and 'keyboard.write' command is more out of frustration than anything else. Did I tell you I had another project for the same client? This one is just 5 buttons, 5 LED's, trigger 5 videos AND turn on 5 light boxes. the light boxes are an external backlit 'branded' box. Think messaging or theme as a specific video clip is played.

This project is for the same 'global' project with the same client. This one is a bit weird because they want to delay the light boxes by 2 seconds after the video starts. I was just going to use the same I/O pins for the LED's to trigger some relays (see pdf below) to turn on/off the light boxes. Well, that 2 second delay thing wrecked my chi. I didn't want to have to call out 5 more pins and digitalWrite more code. I was starting to get nauseous thinking about it.

iot2spec.pdf (187.9 KB)

If/when you do the cut/paste/edit, keep an eye out for mistakes, even ones that won't make a difference like the comment above. :expressionless:

Here's something that is meant to be functionally equivalent to your sketch. You will see your code pattern in the function doCheckButtons() using arrays so just one copy.

Try it out here, read it below.

// video switch control panel
// https://wokwi.com/projects/348441099924144723

const byte MAXBUTTONS = 18;  // room for 18
const byte REALBUTTONS = 4;  // only four actually in the tables and wired

const byte buttonPin[MAXBUTTONS] =
{
  25, 27, 29, 31,             // and so forth, the pins where the buttons are
};

const char letterToSend[MAXBUTTONS] =
{
  's', 'd', 'v', 'k',         // the character to send
};
 
const byte ledPin[MAXBUTTONS] = 
{
  2, 3, 4, 5,                 // the pins where the LEDs are
};

const unsigned long videoDuration[MAXBUTTONS] = {
  4000, 5000, 6000, 77000UL,  // the duration in ms of the videos
};

const int stupidTurnOnDelayFactor = 2000;  // waaaaay too long!

void doCheckButtons()
{
  for (unsigned char buttonN = 0; buttonN < REALBUTTONS; buttonN++) {
    if (digitalRead(buttonPin[buttonN]) == 0)  // if button is pressed
    {
// I don't have a Leonardo or Due, so no   
//      Keyboard.write(letterToSend[buttonN]); // send a single letter

Serial.print("launching '");
Serial.print(letterToSend[buttonN]);
Serial.println("'...");

      delay(stupidTurnOnDelayFactor);
      digitalWrite(ledPin[buttonN], HIGH); //turn on the led
      delay(videoDuration[buttonN]);
      digitalWrite(ledPin[buttonN], LOW); //turn off the led after duration + stupidFactor

Serial.println("        and back waiting...");
    }
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("hello world!\n");

  for (unsigned char buttonN = 0; buttonN < REALBUTTONS; buttonN++) {
    pinMode(buttonPin[buttonN], INPUT_PULLUP);

    pinMode(ledPin[buttonN], OUTPUT);
    digitalWrite(ledPin[buttonN], LOW);
  }
}

void loop() {
  doCheckButtons();
}

So the first button/LED/video, at index 0, has a pulled up button on pin 25, an LED wired to pin 2, sends the letter 's' to the controlled system when the button is pressed, and turns off the LED after 4000 (+ 2000) ms, 6 seconds later. The parameters for each thing like that are now available by number, the index into the various arrays.

a7

Wow, a7 you have really outdone yourself. Might be easy-breezy code on your end, but it has opended me up to lots of possibilties. Learning a lot here. I will write in the keyboard function and see how this all works out. Fair warning, however, I will probably have questions.

Perfect. Standing by. Actually going to the beach, but you know.

a7