Rotary phone running Linux

April 14, 2022

How to connect a vintage rotary phone to raspberry pi (and use it as a wedding guestbook)

I’m a software engineer, and am not very familiar with the inner workings of most electronics. I had an idea for using an old rotary phone as a Linux peripheral device. In this blog post, I’ll show you what I learned, and how to connect an old rotary phone to a Raspberry Pi.

Requirements

To do this project, you won’t need any electronics knowledge. It is basically as simple as unscrewing a few connections, plugging together wires, and taping them down. I assume you have some knowledge of running Linux programs on the Raspberry Pi, and in particular a bit of Python experience.

The materials needed for this project are also simple.

In total, the pi and phone are by far the most expensive part of this project. Most phones I’ve seen have been around $40, or more for fancy colors. So overall, you could probably complete this project on a budget of $45-$100 depending on your selection of phone, and if you have an old Raspberry Pi lying around.

An old-fashioned rotary phone is a very simple device. The hook (the button to know if the phone is picked up) is just a basic button. The rotary dial may seem complicated, but ultimately, it is just a pair of basic buttons. The speaker and microphone are just analog audio componants. I’ll first describe how each of these individual parts can be connected to the Raspberry Pi.

Since I’ve already done this process on my phone, I don’t have photos in progress, but hopefully it should be self explanitory to take things apart. Your phone may look different on the inside anyway, but the concepts will likely be similar.

The first thing to do is to take your phone apart. No actions here need to be desctructive, or at least weren’t for me. Everything was just unscrewing connections. I removed as many wires as possible. The ones that are required for use will be connected to the componants we are interested in a way that can’t be removed. I also took out the bell, since this was very large. It functions via electromagnet, and I haven’t figured out the best way to run it via the Pi.

Connecting audio

The phone handset is connected to the base by 4 wires. These form two pairs, one for the microphone, and one for the speaker. They operate like a normal analog audio cable.

I was able to differentiate the pairs by unscrewing the plastic on the headset, after doing so I could see the color wires that connected to the speaker, which here are white and green. The remaining wires went to the microphone.

I used the 3.5 mm clips, and taped them to these wires. Then I plugged in the 3.5 mm cables into the USB audio adapter. I plugged this into my laptop, and tested both the microphone and speaker worked by recording with audacity, and playing a YouTube video.

My microphone is very clippy, which is to be expected of something so old. Perhaps your phone will be better. I accidently bought the wrong adapter here, and needed to add an auxillery cable, so my cables look very messy.

Connecting the “hook”

Next, I wanted to connect the “hook” switch. Basically, this is a button that is pressed when the phone is set down on the phone, and released when it is picked up. Under the switch on the phone, there were a series of plates and wires. To simplify things, I removed all of these wires but two. This actually complicated things, since it was tricky getting the plates to compress correctly with the wires missing. I added cardboard to pad the space.

I took the two wires, and taped them to jumper cables. Next, I connected them to the GPIO pins, one to ground, and one to a general purpose pin. I booted my pi, and ran the following python program to test it worked.

import RPi.GPIO as GPIO
import time

BUTTON_GPIO = 24 # Change to the pin you are using
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)

while True:
    if not GPIO.input(BUTTON_GPIO):
        print("phone is on hook")
    else:
        print("phone is picked up")
    time.sleep(1)

While running it, you can pick up and set down the phone handset to see if the wires are connected correctly.

Connecting the dial

The dial is the most complex part of the phone, but it basically is just two buttons.

The first here on the left is formed by the green and blue wires. For each number the dial rotates past, the circuit is closed. For example, if you dial a 4, the plates connected to these wires touch 4 times, and so the Pi sees this as 4 button presses.

The second button formed by the two white wires is closed while the dial is in motion. To simplify my wiring, I ignored this button, and instead just timed the first button, by counting how many times the button is pressed before 0.3 seconds without any change (to signify the dial reached the end).

I used tape and jumper cables to connect the green and blue wires to the GPIO on my Pi. Then I used this program to test the dial is working. It should print out the number dialed. The REST_TIME parameter may need tweaking if your dial moves very slowly.

from datetime import datetime, timedelta
import RPi.GPIO as GPIO
import time

BUTTON_GPIO = 25 # Change to the pin you are using
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
REST_TIME = 0.3 # seconds

rest_start = datetime.now()
count = 0
printed = True
pressed = True
while True:
    # If there is a new press of the button
    if not GPIO.input(BUTTON_GPIO):
        if not pressed:
            # Count how many times the button is pressed
            count+=1
            pressed = True
            printed = False
    else:
        # End the current button press
        if pressed:
            rest_start = datetime.now()
        pressed = False
    # If it has been REST_TIME seconds since the button was pressed, and we
    # haven't printed the result, print it
    if datetime.now() - rest_start > timedelta(seconds=REST_TIME) and not printed:
        # Only add this dial to queue if we should accept numbers at this time
        print(count % 10) # wrap 10 presses to 0
        # Reset values
        count = 0
        printed = True
    time.sleep(0.01)

More programs to try

From the first two programs, you can get some idea of how to read the dial and the hook button. To play and record audio, I found the programs aplay and arecord work best, and can be easily invoked via Python’s subprocess module. I also like to use espeak to have the Pi read text.

Wedding Guestbook program

Here is a simple program to create a wedding guestbook. This is an idea I, and many others had, as a cool retro thing to have at a wedding reception to have guests leave recordings at.

It is very basic, feel free to adjust it to your needs. The way it works is when someone picks up the phone, the recorder will start, and save the recording to a timestamped file. When the phone is hung up, the recording ends. If you want the user to interact with the dial, I recommend the general purpose phone program listed later.

Note, this requires you to have the program arecord installed.

import subprocess
import time
import threading

# Events allow us to wait until a variable is set
phone_hung_up = threading.Event()
phone_hung_up.set()
phone_picked_up = threading.Event()
phone_picked_up.clear()

# This thread sets the variables based on the status of the "hook" button
class HangUpThread(threading.Thread):
    def __init__(self, phone_hung_up, phone_picked_up):
        threading.Thread.__init__(self, args=(), kwargs=None)
        self.daemon = True

        self.phone_picked_up = phone_picked_up
        self.phone_hung_up = phone_hung_up
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)

    def run(self):
        while True:
            if not GPIO.input(BUTTON_GPIO):
                self.phone.phone_picked_up.clear()
                self.phone.phone_hung_up.set()
            else:
                self.phone.phone_picked_up.set()
                self.phone.phone_hung_up.clear()
            time.sleep(0.1)

HangUpThread(phone_hung_up, phone_picked_up).start()
while True:
    # Wait until the phone is picked up
    phone_picked_up.wait()
    # Start the recording process
    process = subprocess.Popen(["arecord", f"{datetime.now().strftime('%Y%m%d-%H%M%S')}.wav"])
    # Record until the phone is hung up
    phone_hung_up.wait():
    # Kill the process
    process.terminate()

General purpose phone

I wrote this program that is a general purpose way to run commands when a number is dialed. For example, you can dial a specific number, and it will play a song, or read the weather, or let your record a message. My configuration is similar to the default. I added some fun Wav file events, such as one to the George’s voicemail song from Seinfeld:

52=events.WavEvent /etc/phone/sound/seinfeld.wav

If you have any questions about this, please email me (check my website’s footer for my address). I’ve just moved apartments, and so wasn’t able to fully verify all of the sample programs here work perfectly.