Introduction: Vintage Rotary Phone Dial PC Volume Control

About: Writer for Hackster.io and others. Author of Idiot's Guides: 3D Printing and A Beginner's Guide to 3D Modeling: A Guide to Autodesk Fusion 360.

If you're anything like me, you find yourself changing the volume on your computer quite often. Some videos are louder than others, sometimes you want the volume muted on your computer while you listen to podcasts or music, and you might need to quickly turn the volume down if you receive a phone call. If you don't have media controls built into your computer, then you can turn a vintage rotary phone dial into a volume control for your Windows PC.

This volume control device plugs into your computer through USB, and will automatically set every open program's volume to whatever number you dial. If you dial a "2," the volume will be set to 20%. Dial an "8" and it will be set to 80%. Dialing "0" sets it to 0% and acts like mute. It's quick, satisfying, and more fun than clicking around on the volume control in your taskbar.

Supplies

Step 1: Theory of Operation

Rotary phones, including the Bell Systems Trimline used in this project, are purely analog electromechanical devices. When you rotate the dial, a spring spins the dial back to the original position. As it passes each number a switch is disconnected (or connected) for a brief moment, creating a pulse. All we have to do is count those pulses in order to determine what number was dialed.

guidomax has a fantastic Instructables tutorial that goes in depth on how exactly this works, and you can find more detail there.

For this project, we use the Arduino Nano to count the pulses. The Arduino then sends the number to the PC via the serial connection. I wrote a basic Python script that runs in the background and monitors that serial connection. When it receives bits, it takes the number and uses the Python Core Audio Windows library to set the appropriate volume.

Due to limitations with Windows and that library, the script does not set the overall system volume (the main slider in your taskbar). Instead, it sets the individual volume for every program that is currently running. The effect is the same, except that you can't maintain different relative volume levels between programs.

Step 2: Remove the Dial

This step is straightforward: just disassemble your Trimline phone handset to remove the dial mechanism. It's essentially a self-contained module, so you just need to unscrew it from the handset.

I chose the Trimline model for this project, because that dial module is more compact than the ones you'll find on most other rotary phones.

If you give it a few test spins, you should hear the switch clicking away as it returns to the home position.

Step 3: Print the Enclosure

Use the two provided STL files to print the enclosure parts. You can use whatever filament material you prefer (I used PLA). The particular settings you use aren't that important, but I did recommend using supports for the "Rotary_Top" part. You can print these two parts while you work on the rest of the project.

Step 4: Program Your Arduino

The code you'll upload to your Arduino Nano is taken straight from guidomax's tutorial, since it works perfectly for this project:

int needToPrint = 0;
int count; int in = 2;

int lastState = LOW;

int trueState = LOW;

long lastStateChangeTime = 0;

int cleared = 0;

// constants

int dialHasFinishedRotatingAfterMs = 100;

int debounceDelay = 10;

void setup() {

Serial.begin(9600);

pinMode(in, INPUT); }

void loop() {

int reading = digitalRead(in);

if ((millis() - lastStateChangeTime) > dialHasFinishedRotatingAfterMs) { // the dial isn't being dialed, or has just finished being dialed.

if (needToPrint) { // if it's only just finished being dialed, we need to send the number down the serial // line and reset the count. We mod the count by 10 because '0' will send 10 pulses.

Serial.print(count % 10, DEC);

needToPrint = 0;

count = 0;

cleared = 0; } }

if (reading != lastState) { lastStateChangeTime = millis();

}

if ((millis() - lastStateChangeTime) > debounceDelay) { // debounce - this happens once it's stablized

if (reading != trueState) { // this means that the switch has either just gone from closed->open or vice versa. trueState = reading; if (trueState == HIGH) { // increment the count of pulses if it's gone high.

count++;

needToPrint = 1; // we'll need to print this number (once the dial has finished rotating)

}

}

}

lastState = reading; }

Step 5: Wire Everything Up

The wiring for this project is really simple. The dial module should have two hexagonal posts on the back with screws in them. Those are the switch connections. Polarity doesn't matter.

Note: Ignore the colors of my wires in the photos. I mixed up ground and 5V, so these are actually reversed.

Connect one wire from Post A (GND) and connect it to a ground pin on your Arduino Nano. Take a second wire and solder it and a third wire to one side of the 470 ohm resistor. The second wire will go to Post B (+) on the dial. The third wire will get soldered to one side of the 10k ohm resistor. Take a fourth wire and solder it from the other side of the 470 ohm resistor to Pin 2 on the Arduino Nano. Finally, a fifth wire should connect the other side of the 10k ohm resistor to the 5V pin on the Arduino Nano.

We're using the resistors and the 5V pin to pull the pin to high when the switch is open (as it is during each "pulse").

Step 6: Assembly

You should notice that the Rotary_Top part of the enclosure has six small holes. These are for your threaded heat-set inserts. The top three (on the underside of the top surface) are to mount the rotary dial. The bottom three are to screw the Rotary_Base to the Rotary_Top.

The heat-set inserts can be heated up with a soldering iron (or a dedicated tool) and then pushed into the holes. The heat will melt the plastic, which will harden after heat is removed to hold the inserts securely in place. Using heat-set inserts is much more pleasant than threading screws directly into the plastic.

Insert the six heat-set inserts. Then use a few short (10mm or so) M3 machine screws to mount the dial. Take note of the notch in the cutout, which is where the metal finger stop will go. Then carefully place the Arduino Nano—with USB cable connected—inside the enclosure (it is loose, not mounted), and screw the base into place.

You'll probably want to use double-sided tape or 3M Command Strips to affix the enclosure to your desk, so it won't move around when you rotate the dial.

Step 7: Setup the Python Script

First, make sure you have Python installed (use Python 3, as Python 2 is being phased out).

You'll then need to install the two required libraries: PyCAW and PySerial.

Use:

"pip install pycaw" and "pip install pyserial" (from the Python window or Windows Powershell)

Then check to see what port your Arduino Nano is connected to. You can check that from within the Arduino IDE. Make sure you have that port selected, then open the serial monitor. Make sure your baud rate is set to 9600, and then dial some numbers to make sure they show up in the serial monitor.

If they do, edit the "rotary.py" code with your port number. If you run the script, then you should now be able to change the volume by dialing a number.

The final step is to setup the script to run in the background automatically when you boot your PC.

To do that, change "rotary.py" to "rotary.pyw" which will allow it to run in the background. Then place that script in the following folder: C:\Users\current_user\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\

Obviously you'll need to change "current_user" to your actual user folder name.

That's it! Whenever you computer starts up, that Python script will start running. It'll monitor the serial connection from the Arduino, and will set all the program volumes to whatever you dial!

Arduino Contest 2020

Runner Up in the
Arduino Contest 2020