summaryrefslogtreecommitdiff
path: root/content/blog/rotary_phone_running_linux.md
blob: 25fc73d6e4385773a48bfc7c495ceaebd1319db3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
---
title: "Rotary phone running Linux"
date: 2022-04-14T21:52:01-05:00
aliases:
- /post/blog/78
---
# 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.

<iframe src="https://drive.google.com/file/d/1omulMRk71ZLnNeU9ytPbbEzRNth8wofV/preview" width="640" height="480" allow="autoplay"></iframe>

## 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.

* First, you will need a Raspberry Pi. You could use a Raspberry Pi zero for
    this, but my understanding is that connecting to GPIO on the zero is
    trickier. On a normal-sized pi, you can instead use jumper cables. You will
    also need an SD card and power supply.
* You will need some wires to connect the componants to your pi. I got some
    jumper cables ([these](https://www.adafruit.com/product/4944) and
    [these](https://www.adafruit.com/product/1956)). You could use any wires
    really. I used the ones mentioned above, and taped them as needed to form a
    connection. If you are comfortable soldering, that is fine too.
* To use audio, you will need a [USB audio
    adapter](https://www.adafruit.com/product/1475). I have an older pi, which
    has a 3.5 mm output jack on the board. If you didn't need audio in, you
    could get away with just using that. Any USB audio adapter that works on the
    pi should be fine.
* Now, you will need something to plug into the 3.5 mm jacks on the adapter. I
    used [these](https://www.adafruit.com/product/4181), which makes it very
    easy to connect the phone wires to a 3.5 mm jack. Alternatively, you could
    just use an old 3.5 mm cable, and splice it onto the phone's wires.
* You will need a rotary phone. I got mine from an antique store, and I think it
    is from the 70s or 80s. Make sure the phone you choose is a rotary phone if
    you want to use the dial. There are some phones that appear to have dials,
    but the dial does not spin, and the numbers are actually buttons instead.
    You probably could get these to work if you tinkered around yourself, but I
    have no experience with them. [JWZ
    wrote](https://www.jwz.org/blog/2016/01/my-payphone-runs-linux-now/) this
    post about using a more modern payphone. If you search ebay for "rotary
    phone" you will find lots that fit the bill.
* You will need some screwdrivers to take apart the phone. My phone just uses
    regular screws.

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.

<iframe src="https://drive.google.com/file/d/147yXcljBHC5YustzxSKdR3e3zPz3KHJj/preview" width="640" height="480" allow="autoplay"></iframe>

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.

<iframe src="https://drive.google.com/file/d/1HXRcyiyssQoM8UFvF867ygjDNpQvtQ4J/preview" width="640" height="480" allow="autoplay"></iframe>

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.

<iframe src="https://drive.google.com/file/d/1ngBg4z-gllk_08xzF5WV_9jWlH2iOrN0/preview" width="640" height="480" allow="autoplay"></iframe>

## 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.

<iframe src="https://drive.google.com/file/d/1A5NbGSgC4ooElVGK-jb0b8Ix5UW6YQuz/preview"  width="640" height="480" allow="autoplay"></iframe>

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.

```python
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.

<iframe src="https://drive.google.com/file/d/1V9wChq0vLBPAYIcBnffrIViQU8G_i2MN/preview"  width="640" height="480" allow="autoplay"></iframe>

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.

```python
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.

```python
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](https://git.marks.kitchen/?p=rotary_pi;a=summary) 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.