Fully Customizable Multimedia Knob - Upgrade Your Home Entertainment Setup!

by JGJMatt in Circuits > Arduino

7777 Views, 169 Favorites, 0 Comments

Fully Customizable Multimedia Knob - Upgrade Your Home Entertainment Setup!

Instructable cover.png
20230503_122746.jpg

Hello fellow makers!



If you are anything like me and love having music playing at home while you are busy you will know how nice it is to have a quick tactile way to quickly change the volume, scroll to your next favourite or just stop/mute it instantly without the need to usher your smart home assistant.





But it doesn't stop there you can completely customize it to function to you hearts desire..


Want elegant way to control your movie nights?..

You sure can!


Want a way to quick swap weapons while gaming?..

You got it!


Want a nice way to scroll through pages or slides?..

Now you can!


Want to have so dedicated hotkeys while designing?..

Just pick what you want!




With a click function, left and right scroll and multiple modes you can set up this knob just like you want it, and the best part is you only need two electronic parts that cost next to nothing!



Let's get making...

What You Will Need:

To create your own multimedia knob you will need the following:




Optional:



Design and Print the Knob:

20230501_082559.jpg

First step will be to design and print the enclosure and knob for your customisable controller.


I will be including three different designs one is a printed inner with a mold to cast concrete into for a stylish weighted controller and the other is for a fully 3D printed version that is easier to make but because of its light weight it tend to move around alot and will probably need some sticky tape on the bottom to keep it at bay. The third simply has space on top for a 3mm acrylic circle which an LED can be fitted to for some extra style points!


Tinkercad Link


The components were designed using Fusion 360 and is super easy to print in any filament with no supports needed.

I have included the step files as well as making it available on Tinkercad for easy customization to suit your needs.



As mine will be placed on my desk that is infront of a window and will be exposed to a lot of sun I decided to print it using SBS filament which is similar to ABS.

Optional: the LED Lighting

20230428_161844.jpg
20230428_155049.jpg
20230428_150058.jpg
20230428_161218.jpg

This step is optional and only necessary if like me you want your button to have some snazzy underglow.


Start by cutting a 55mm circle out of clear/opaque acrylic/polycarbonate/plexiglass, this can be done with a holesaw or by hand but as I was busy with another project on my little DIY CNC I quickly used that.

The centre hole needs to be 7mm.



I sanded the clear plastic with some 400 grit sandpaper to make it opaque for better light distribution. Then simply glued it onto our 3D printed main body using some 2 part CA glue.


Next I made a 5mm hole through the body and acrylic for a 5mm LED to fit through. I then snipped off the legs from a blue diffused 5mm LED and soldered on some wires.



I then glued the LED in place with the same CA glue and sanded it flat with the acrylic.


Test to make sure it works then we can move on to the next step.

Optional: Casting the Concrete Base

20230430_172208.jpg

If you decided on the concrete base for the button then we can now get to casting it.


I started by sticking the main printed body down onto a plastic plate using some blue-tak this will keep it in place and prevent the concrete from seeping into the electronics cavity.


Next I placed the mold over the main body and centred it using the printed centring jig and held in place by blue-tak before removing the centring jig again.


Next I mixed up a small cup of concrete premix and vigorously tapped out as much of the trapped air as possible before pouring it into the mold.


Let it cure for at least a day before demolding.

Refine the Enclosure:

20230501_094624.jpg
20230503_093925.jpg
20230503_104013.jpg

With our concrete base made we can start refining the enclosure.


I started by sanding down the surface of the button to give the filler a coarse surface to grab onto. I smeared the entire button with a thin layer of filler before sanding with 220 grit sandpaper and priming.


Once the primer has dried completely we can wet sand it with 400 grit sandpaper and move on to the final spray painting.



I chose to spray mine with this beautiful gunmetal color with my airbrush that almost makes it look like a casted metal piece. Now set it aside to dry completely.


Next up I sanded the concrete a little to soften the edges and I also used a drill bit scrape a slot into the concrete for the cable to lay in.


Coding:

image_2023-05-09_101644147.png

Both of these codes needs to be placed in your Arduino library under the same folder.

// Modified version of code by IAmOrion aka James Tanner

#include "TrinketHidCombo.h" 
#include "Settings.h" 


#define TRINKET


#ifdef TRINKET
  #include <avr/power.h>
#endif


#define LATCHSTATE 3
int buttonState = HIGH, lastButtonState = HIGH;
long lastDebounceTime = 0, debounceDelay = 50, lastAction = 0;
int _position = 0, _positionExt = 0, buttonCounter = 0;
int8_t _oldState; bool shouldActionButton=true, btnReset=true, rotaryMode=false;


const int8_t encoderStates[] = {
  0, -1, 1, 0,
  1, 0, 0, -1,
  -1, 0, 0, 1,
  0, 1, -1, 0
};


void setup() {
  #ifdef TRINKET
    if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  #endif
  
  pinMode(encoderPinA, INPUT);
  pinMode(encoderPinB, INPUT);
  pinMode(encoderButton, INPUT);
  digitalWrite(encoderPinA, HIGH);
  digitalWrite(encoderPinA, HIGH);
  digitalWrite(encoderButton, LOW);
  _oldState = 3; 
  TrinketHidCombo.begin();
}


void loop() {
  static int pos = 0;
  tick();
  int newPos = getPosition();
  if (pos != newPos) {
     lastAction = millis(); shouldActionButton=false; btnReset=false; rotaryMode=true;
    if (newPos < pos) {
      switch (buttonCounter) {
        case 0:
          // Default Left mode
          TrinketHidCombo.pressMultimediaKey(LEFT_ACTION);
          break;
        case 1:
          // Mode 1 Left
          TrinketHidCombo.pressMultimediaKey(LEFT_ACTION_MODE1);
          break;
        case 2:
          // Mode 2 Left
          TrinketHidCombo.pressMultimediaKey(LEFT_ACTION_MODE2);
          break;
        case 3:
          // Mode 3 Left
          TrinketHidCombo.pressMultimediaKey(LEFT_ACTION_MODE3);
          break;
        default:
          break;
      }
    }
    else if (newPos > pos){
      switch (buttonCounter) {
        case 0:
          // Default Right mode
          TrinketHidCombo.pressMultimediaKey(RIGHT_ACTION);
          break;
        case 1:
          // Mode 1 Right
          TrinketHidCombo.pressMultimediaKey(RIGHT_ACTION_MODE1);
          break;
        case 2:
          // Mode 2 Right
          TrinketHidCombo.pressMultimediaKey(RIGHT_ACTION_MODE2);
          break;
        case 3:
          // Mode 3 Right
          TrinketHidCombo.pressMultimediaKey(RIGHT_ACTION_MODE3);
          break;
        default:
          break;
      }
    }
    pos = newPos;
  }
  int reading = digitalRead(encoderButton);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {
        shouldActionButton=true; btnReset=false;
        if (allowMenuLoop){ buttonCounter++; } else { if (!rotaryMode) { buttonCounter++; } else { doBtnReset(); } } 
        if (buttonCounter > buttonModes){buttonCounter=0;}
        lastAction = millis();
      } else if (buttonState == LOW){
        // may do something with onRelease at a later date...
      }
    } 
  }
  lastButtonState = reading;


  if ((millis() - lastAction) > buttonPressTimeout) {
    if (shouldActionButton) {
      switch (buttonCounter) {
        case 0:
          break;
        case 1:
          TrinketHidCombo.pressMultimediaKey(BUTTON_ACTION_SINGLE);
          break;
        case 2:
          TrinketHidCombo.pressMultimediaKey(BUTTON_ACTION_DOUBLE);
          break;
        case 3:
          TrinketHidCombo.pressMultimediaKey(BUTTON_ACTION_TRIPLE);
          break;
        default:
          break;
      }
      shouldActionButton=false;
    }
    if (!btnReset){
      doBtnReset();
    }
  }
  TrinketHidCombo.poll();
}


void doBtnReset() {
    buttonCounter = 0;rotaryMode=false;
    btnReset=true;
}


int  getPosition() {
  return _positionExt;
}


void setPosition(int newPosition) {
  _position = ((newPosition<<2) | (_position & 0x03));
  _positionExt = newPosition;
}


void tick(void) {
  int sig1 = digitalRead(encoderPinA);
  int sig2 = digitalRead(encoderPinB);
  int8_t thisState = sig1 | (sig2 << 1);
  if (_oldState != thisState) {
    _position += encoderStates[thisState | (_oldState<<2)];
    if (thisState == LATCHSTATE)
      _positionExt = _position >> 2;
    _oldState = thisState;
  }


Settings.h



#define encoderPinA 0 // Change these values if button is not functioning corectly
#define encoderPinB 2
#define encoderButton 1


int buttonModes = 3;
long buttonPressTimeout = 500;
bool allowMenuLoop=false;

// These can be modified to do what you want using the keys specified below

#define LEFT_ACTION MMKEY_VOL_DOWN
#define LEFT_ACTION_MODE1 MMKEY_SCAN_PREV_TRACK
#define LEFT_ACTION_MODE2 KEYCODE_ESC
#define LEFT_ACTION_MODE3 KEYCODE_ESC

#define RIGHT_ACTION MMKEY_VOL_UP
#define RIGHT_ACTION_MODE1 MMKEY_SCAN_NEXT_TRACK
#define RIGHT_ACTION_MODE2 KEYCODE_ESC
#define RIGHT_ACTION_MODE3 KEYCODE_ESC


#define BUTTON_ACTION_SINGLE MMKEY_PLAYPAUSE
#define BUTTON_ACTION_DOUBLE MMKEY_MUTE
#define BUTTON_ACTION_TRIPLE KEYCODE_ESC


/*


System control keys


SYSCTRLKEY_POWER
SYSCTRLKEY_SLEEP
SYSCTRLKEY_WAKE
Multimedia keys


MMKEY_VOL_UP
MMKEY_VOL_DOWN
MMKEY_SCAN_NEXT_TRACK
MMKEY_SCAN_PREV_TRACK
MMKEY_STOP
MMKEY_PLAYPAUSE
MMKEY_MUTE
MMKEY_BASSBOOST
MMKEY_LOUDNESS
MMKEY_KB_EXECUTE
MMKEY_KB_HELP
MMKEY_KB_MENU
MMKEY_KB_SELECT
MMKEY_KB_STOP
MMKEY_KB_AGAIN
MMKEY_KB_UNDO
MMKEY_KB_CUT
MMKEY_KB_COPY
MMKEY_KB_PASTE
MMKEY_KB_FIND
Control keys


KEYCODE_LEFT_CONTROL
KEYCODE_LEFT_SHIFT
KEYCODE_LEFT_ALT
KEYCODE_LEFT_GUI
KEYCODE_RIGHT_CONTROL
KEYCODE_RIGHT_SHIFT
KEYCODE_RIGHT_ALT
KEYCODE_RIGHT_GUI
Regular keys


KEYCODE_1
KEYCODE_2
KEYCODE_3
KEYCODE_4
KEYCODE_5
KEYCODE_6
KEYCODE_7
KEYCODE_8
KEYCODE_9
KEYCODE_0
KEYCODE_A
KEYCODE_B
KEYCODE_C
KEYCODE_D
KEYCODE_E
KEYCODE_F
KEYCODE_G
KEYCODE_H
KEYCODE_I
KEYCODE_J
KEYCODE_K
KEYCODE_L
KEYCODE_M
KEYCODE_N
KEYCODE_O
KEYCODE_P
KEYCODE_Q
KEYCODE_R
KEYCODE_S
KEYCODE_T
KEYCODE_U
KEYCODE_V
KEYCODE_W
KEYCODE_X
KEYCODE_Y
KEYCODE_Z
KEYCODE_COMMA
KEYCODE_PERIOD
KEYCODE_MINUS
KEYCODE_EQUAL
KEYCODE_BACKSLASH
KEYCODE_SQBRAK_LEFT
KEYCODE_SQBRAK_RIGHT
KEYCODE_SLASH
KEYCODE_F1
KEYCODE_F2
KEYCODE_F3
KEYCODE_F4
KEYCODE_F5
KEYCODE_F6
KEYCODE_F7
KEYCODE_F8
KEYCODE_F9
KEYCODE_F10
KEYCODE_F11
KEYCODE_F12
KEYCODE_APP
KEYCODE_ENTER
KEYCODE_BACKSPACE
KEYCODE_ESC
KEYCODE_TAB
KEYCODE_SPACE
KEYCODE_INSERT
KEYCODE_HOME
KEYCODE_PAGE_UP
KEYCODE_DELETE
KEYCODE_END
KEYCODE_PAGE_DOWN
KEYCODE_PRINTSCREEN
KEYCODE_ARROW_RIGHT
KEYCODE_ARROW_LEFT
KEYCODE_ARROW_DOWN
KEYCODE_ARROW_UP


*/

Test the Electronics:

20230503_105805.jpg

Before soldering anything we want to make sure the electronics work.


If you haven't used a Digispark Attiny85 board before you will need to install it's drivers and install it onto the Arduino IDE which I will go over in the next step.


I first uploaded a simple blink code onto my Digispark board to make sure it was functioning correctly.

Then I uploaded the code and unplugged it when it was done.


Next connect the Digispark to the rotary encoder with jumper wires as follow:

 Digispark to KY-040

 P0  to DT

P1  to SW

P2  to CLK

 VCC to GND > This is not a mistake

 GND to 5V ^


Once connected plug it into your computer and see if turning the rotary encoder adjusts the main volume.


If it doesn't work as intended double check your pins or change the pinout in the code to one following:


#define encoderPinA 0
#define encoderPinB 1
#define encoderButton 2

or

#define encoderPinA 0
#define encoderPinB 2
#define encoderButton 1

or

#define encoderPinA 1
#define encoderPinB 0
#define encoderButton 2

or

#define encoderPinA 1
#define encoderPinB 2
#define encoderButton 0

or

#define encoderPinA 2
#define encoderPinB 0
#define encoderButton 1

or

#define encoderPinA 2
#define encoderPinB 1
#define encoderButton 0

Fix Digispark (Attiny85) "USB Device Not Recognised" Message

F8O9G9ZIDWXMRXV.LARGE_.jpg

If you are receiving the infamous "USB Device Not Recognised" pop-up when inserting the the Digispark/Attiny85 board into your computers USB port you can try the following which fixed all of my previous unusable Digisparks.


  • First you need to make sure you have the Digispark drivers installed that is included in the download below.


  • Then your Digispark has to be included on the Arduino IDE.
  1. Open the arduino IDE and go to file > preferences.
  2. Add http://digistump.com/package_digistump_index.json to the additional boards manager URLs.
  3. Go to tools > board > boards manager.
  4. Search for digistump, and install Digistump AVR boards.


  • Then you will need an Arduino board (UNO/Nano etc.) with the "ArduinoISP" sketch loaded that can be found under "Examples".


  • With the code loaded connect your Digispark to the Arduino as pictured above via jumper wires.


  • In the downloaded folder under "Attiny85 Firmware update" open the" t85_default.hex" file using notepad and change the COM port to the port your Arduino is plugged into as shown in the picture below, Save the file.


Drivers and Firmware Update LINK


  • Next copy both the "t85_default.hex" and "burn_attiny85_bootloader.bat" files over to your main Arduino IDE installation location eg. C:\Program Files (x86)\Arduino


  • Now run the "burn_attiny85_bootloader.bat" file.


Soldering:

20230503_120107.jpg

With the electronics working as they should we can solder them together permanently.


Using short flexible wires solder each point from the Digispark to the rotary encoder as you had them connected with the jumper wires.


Next we need a USB connection.

Using a beautiful braided USB data cable I got from a bargain bin sale I snipped off the micro USB side of the cable and exposed the wires.



Solder the wires from the USB cable onto the Digispark as shown in the picture below.



Last piece to solder was the LED that was soldered to the USB 5V through a 100ohm resistor to limit the current going to the LED.


Plug in the USB into your computer to make sure everything still functions correctly.

Assembling:

20230503_122510.jpg
20230503_122433.jpg

It's finally time to ensemble your multimedia button!


Start by pushing the rotary encoder through the 7mm hole in the top of the enclosure and tightening it with the included washer and nut.



Next I pressed the Digispark into place underneath the rotary encoder and used some hot melt glue to keep it in place. (I still need to modify the design to include a lid but will update here when it is completed)



To protect my desk and keep the button from slipping I cut out a disk of thin black foam (sold at craftshops as kids party foam) and glued it to the bottom of the button.



Now simply push on the button cap and your multimedia button is done and ready for work!

Enjoy!

20230503_122603.jpg
20230503_122812.jpg

I hope you guys find this Instructable useful and if you have any questions please feel free to leave me a message or comment bellow.



If you found this Instructable helpful and would like to support my future projects you can Buy Me A Coffee.



Thank you for taking the time to read through my project and as always..


Happy making!

---