Browse Source

First release

git@elektrollart.org 3 months ago
parent
commit
772989185a
4 changed files with 295 additions and 1 deletions
  1. 152
    1
      README.md
  2. 1
    0
      dial.txt
  3. BIN
      img/pytap-plan.png
  4. 142
    0
      run.py

+ 152
- 1
README.md View File

@@ -1,2 +1,153 @@
1
-# fetapi
1
+# FeTaPi
2 2
 
3
+1. Beweggründe
4
+2. Was wird benötigt
5
+3. Hardware
6
+4. Software
7
+5. Kurzfassung (tl;dr)
8
+6. Funktion des Skriptes
9
+
10
+## Beweggründe
11
+FeTaPi ist ein in Python 3 geschriebener Skript, welcher es ermöglicht ein Fernsprechtischapparat (FeTap) mit SIP zu betreiben. Dabei wird die Wählscheibe als direkte Eingabe genutzt und ein SIP Client (linphone), welcher auf dem Raspberry Pi betrieben wird, sorgt für die Telefonie. Der Wecker des FeTaps wird hierbei als Klingel für eingehende Anrufe benutzt und der Hörer über eine USB Soundkarte betrieben.
12
+
13
+Ziel war es, die alten Fernsprechtischapparate der alten Post, erneut ein Leben zu geben und an das [Eventphone](https://eventphone.de/) anzubinden, um zum Beispiel auf Events des CCCs diese Telefone ohne TAE Stecker zu nutzen. 
14
+
15
+Es werden nur minimale Lötarbeiten benötigt, welche man aus der folgenden Grafik entnehmen kann.
16
+
17
+## Was wird benötigt
18
+
19
+1. Raspberry Pi Zero
20
+2. Lötwerkzeug
21
+3. 1 Kanal Relais 5V/230V
22
+4. USB Soundkarte
23
+5. USB auf MicorUSB Adapater
24
+6. 9V Batterie + Betterieclip
25
+7. Fetap 791-1
26
+8. Jumper Kabel 
27
+
28
+## Hardware
29
+
30
+![https://git.elektrollart.org/Elektroll/fetapi/raw/branch/master/img/pytap-plan.png](https://git.elektrollart.org/Elektroll/fetapi/raw/branch/master/img/pytap-plan.png)
31
+
32
+![https://www.elektrollart.org/wp-content/uploads/IMG_7392.jpg](https://www.elektrollart.org/wp-content/uploads/IMG_7392.jpg)
33
+*Fotografie aller Bauteile*
34
+
35
+Am Telefonhörer müssen die Leitungen vom Hörer (Gelb und Grün) und vom Mikrofon (Braun und Weiß) an eine USB Soundkarte angebracht werden. Hierzu wurden die Kabel an Klinkenstecker gelötet und diese in die Soundkarte gesteckt. Hierzu wird noch ein Adapter von USB auf Micro USB benötigt, da ich ein Raspberry Pi Zero benutze und dieser nur einen MicroUSB Anschluss hat.
36
+
37
+![](https://www.elektrollart.org/wp-content/uploads/IMG_7342-2.jpg)
38
+![](https://www.elektrollart.org/wp-content/uploads/IMG_7396.jpg)
39
+*Fotografie der Wählscheibe von Oben und von der Seite*
40
+
41
+Die Wählscheibe besteht aus zwei Kontakten die zur Impulswahl führen. Der Kontakt, wenn die Drehscheibe angezogen wird (Weiß und Braun) und den Impuls für die gewählte Nummer (Grün und Gelb). Hier wird nur Grün und Gelb benötigt. Zwar könnte man Weiß und Braun für die Kontrolle nehmen und nur die Nummer wählen, wenn Braun und Weis deren Kontakt schließen, aber für das Ziel spielt das hierbei keine Relevanz. Grün und Gelb werden beim zurück rotieren der Scheibe vermehrt den Kontakt abbrechen und wieder aufbauen. Diese Impulse werden gezählt, um die gewählte Nummer zu definieren. Die Kabel aus der Wählscheibe (Grün und Gelb) werden an Jumper Kabel gelötet (oder anderweitig verbunden), damit man diese an das GPIO Head (GPIO 26 und GPIO 21) vom Raspberry Pi anbringen kann.
42
+
43
+![https://www.elektrollart.org/wp-content/uploads/IMG_7341-1.jpg](https://www.elektrollart.org/wp-content/uploads/IMG_7341-1.jpg)
44
+*Fotografie der Platine*
45
+
46
+Auf der Platine des FeTAp befindet sich oben Rechts die Telefongabel (GU), welche die Telefonate terminiert oder annimmt, je nachdem ob die Gabel nach unten gedrückt ist oder oben steht. Hier entnahm ich aus dem gedrückten Zustand der Gabel die Kontakte auf der Platine (Blau und Rot). Damit soll beim geschlossenen Kreislauf eine Anrufbereitschaft bestehen, bzw. wenn die Gabel runtergedrückt wird, das Telefonat beenden. Beim wechsel von gedrückt nach Oben wird der Kontakt gelöst und das Telefonat soll entgegengenommen werden, bzw. es darf eine Nummer gewählt werden. An die Kontakte TWB3 und NS3 auf der Platine können Jumper Kabel gelötet werden, bzw. auf die beiden mittleren Kontakte (Rot und Blau) unter der Gabel (diese muss vom Board gelötet werden) welche ans Raspberry Pi GPIO Head GPIO 20 und GPIO 6 gesteckt wurden.
47
+
48
+![https://www.elektrollart.org/wp-content/uploads/IMG_7394.jpg](https://www.elektrollart.org/wp-content/uploads/IMG_7394.jpg)
49
+*Fotografie der Gabel von Unten*
50
+
51
+Um den Wecker zu betreiben, habe ich eine 9V Batterie und ein Relais Modul genommen. Das Relais wird an den GPIO 3.3 Volt (Grau), GND (Grün) und GPIO 17 (Magenta) Pin verbunden. Vom Relais geht ein Kabel von NO (Blau) an den Minus Pol des Weckers. Von COM (Schwarz) geht ein Kabel an den Minus Pol der Batterie. Der Plus Pol der Batterie ist mit dem Plus Pol des Weckers verbunden.
52
+
53
+## Software 
54
+
55
+Für den Betrieb wird ein Raspberry Pi, mit Debian Buster, Python 3, linphone und Pulseaudio benötigt:
56
+
57
+1. [Download](https://downloads.raspberrypi.org/raspios_lite_armhf_latest) Raspberry Pi OS (32-bit) Lite (Buster)
58
+Source: https://www.raspberrypi.org/downloads/raspberry-pi-os/
59
+
60
+2. Zip Archiv entpacken
61
+
62
+3. Image auf die SD-Karte schreiben (unter Linux):
63
+```
64
+$ dd if=/path/to/file/2020-05-27-raspios-buster-lite-armhf.img of=/dev/mmcblk0 bs=1M
65
+(/dev/mmcblk0 die SD-Karte gelesen vom intern verbauten Lesegerät )
66
+```
67
+
68
+4. Nach Abschluss des Schreibvorganges wird die root und boot Partition 
69
+```
70
+$ mount /dev/mmcblk0p2 /media/root
71
+$ mount /dev/mmcblk0p1 /media/root/boot
72
+```
73
+
74
+5. Wifi Credentials in die wpa_supplicant.conf eintragen
75
+```
76
+$ nano /media/root/etc/wpa_supplicant/wpa_supplicant.conf
77
+```
78
+add  wifi credentials
79
+```
80
+network={
81
+        ssid="Netzwerkname"
82
+        psk="meinschluessel"
83
+}
84
+```
85
+6. OnBoard Soundkarte deaktivieren
86
+```
87
+echo 'blacklist snd-bcm2835' >> /media/root/etc/modules
88
+```
89
+6. SSH aktivieren
90
+```
91
+$ touch /media/root/boot/ssh
92
+```
93
+7. root und boot unmounten
94
+```
95
+$ umount /media/root/boot
96
+$ umount /media/root
97
+$ sync
98
+```
99
+8. Den Raspberry Pi starten
100
+9. Via SSH zum Raspberry Pi verbinden:
101
+```
102
+ssh pi@xxx.xxx.xxx.xxx
103
+password: raspberry
104
+``` 
105
+10. Abhängigkeiten installieren
106
+```
107
+$ sudo apt update
108
+$ sudo apt install git linphone pulseaudio python3-pip
109
+$ pip3 install RPi.GPIO
110
+```
111
+11. FeTaPi Repository klonen
112
+```
113
+$ git clone https://git.elektrollart.org/Elektroll/fetapi.git 
114
+```
115
+12. In die run.py unter Zeile 25 die SIP Zugangsdaten eintragen
116
+13. Pulseaudio aktivieren und script ausführen:
117
+```
118
+pulseaudio --start
119
+python3 run.py
120
+```
121
+14. Wenn alles nach funktioniert, kann der Autostart eingerichtet werden.
122
+```
123
+echo "cd /home/pi/fetapi/;/usr/bin/python3 /home/pi/fetapi/run.py" >> /home/pi/.bashrc
124
+sudo raspi-config
125
+```
126
+Stellt ein, dass ein automatischer Login in die CLI nach dem Boot ausgeführt wird.
127
+
128
+
129
+## Kurzfassung:
130
+
131
+1. Lautsprecher und Mikrofon an eine USB Soundkarte anbringen
132
+2. Die Kontakte Gelb und Grün an GPIO 26 und 21 anbringen
133
+3. Telefongabel Rot und Blau an GPIO 20 und 6 anbringen
134
+4. GPIO 17, 3.3v und GND mit dem Relai verbinden, diesen mit dem Wecker verbinden
135
+4. Script auf ein RPi mit Debian Buster kopieren
136
+5. SIP Credentials in Zeile 25 eintragen
137
+6. Autostart einrichten
138
+
139
+## Funktion des Skriptes:
140
+
141
+In der Funktion **dialnumber** wird die Rufnummer der Wählscheibe gelesen, in dem beim Zurück rotieren der Wählscheibe, die Kontaktabbrüche von GPIO 21 und GPIO 26 gezählt werden. In Zeile 56 steht **time.sleep(0.109)**, dieser Wert wird als Pause zwischen den Impulsen benötigt und kann gegebenenfalls feiner eingestellt werden, sollte die Wählscheibe schneller oder langsamer rotiert, als die in meinem Telefon. 
142
+
143
+Solange GPIO 6 und GPIO 20 einen geschlossenen Kreis bilden, läuft eine Schleife in dem der Status von linphone nach eingehenden Anrufen geprüft wird. In der Funktion **CALL** wird dies mit **if RINGVALUE == 'IncomingReceived':** getätigt. Bei einem eingehenden Anruf wird dann die Funktion **wecker** geschaltet. Diese Funktion gibt nur an das Relais Modul ein Up und Down weiter, welcher den Kreislauf der 9V Batterie mit dem Wecker schließt und damit den Wecker klingeln lässt. 
144
+
145
+Sobald der Hörer abgehoben wird und GPIO 6 und GPIO 20 keinen Kreislauf haben, wird nach einem eingehenden Anruf geprüft. Bei einem eingehenden Anruf wird die Funktion **answer** aufgerufen. Diese fragt bei linphonem nach der eingehenden Call ID und gibt diese ID an linphone zur Rufannahme weiter. 
146
+
147
+Sollte hingegen beim Hörer heben kein eingehender Anruf vorhanden sein, soll die **dialnumber** Funktion aufgerufen werden. 
148
+
149
+Die **dialnumber** Funktion macht solange nichts, bis eine Nummer gewählt wurde. Sobald die erste Nummer gewählt ist, startet ein Countdown, welcher bei jeder weiteren gewählten Nummer resetet wird. Sobald der Countdown runtergezählt wurde, wird die Nummer in die dial.txt geschrieben und von liphone via SHELL aufgerufen und die Nummer gewählt. 
150
+
151
+In allen Situationen wird beim Schließen des Kreislaufes von GPIO 6 und GPIO 20 das Telefonat oder die Rufnummernwahl beendet. Das wird in der Funktion hangup definiert. 
152
+
153
+![](https://www.elektrollart.org/wp-content/uploads/IMG_7407-1024x633.jpg)

+ 1
- 0
dial.txt View File

@@ -0,0 +1 @@
1
+ 

BIN
img/pytap-plan.png View File


+ 142
- 0
run.py View File

@@ -0,0 +1,142 @@
1
+#!/usr/bin/env python
2
+import RPi.GPIO as GPIO
3
+import time
4
+import os
5
+import sys
6
+import re
7
+import subprocess
8
+
9
+GPIO.setmode(GPIO.BCM)
10
+GPIO.setup(26,GPIO.IN, pull_up_down = GPIO.PUD_UP)
11
+GPIO.setup(21,GPIO.OUT)
12
+GPIO.setup(6,GPIO.IN, pull_up_down = GPIO.PUD_UP)
13
+GPIO.setup(20,GPIO.OUT)
14
+GPIO.setmode(GPIO.BCM)
15
+GPIO.setup(17, GPIO.OUT)
16
+
17
+os.system('linphonecsh exit')
18
+time.sleep(1)
19
+os.system('linphonecsh init')
20
+time.sleep(1)
21
+os.system('linphonecsh soundcard playback')
22
+time.sleep(1)
23
+os.system('linphonecsh soundcard ring') 
24
+time.sleep(1)
25
+os.system('linphonecsh register --username <Nummer> --host hg.eventphone.de --password <password>')
26
+
27
+def wecker():
28
+  GPIO.output(17, 1)
29
+  time.sleep(0.04)
30
+  GPIO.output(17, 0)
31
+  time.sleep(0.04)
32
+  GPIO.output(17, 1)
33
+  time.sleep(0.04)
34
+  GPIO.output(17, 0)
35
+  time.sleep(0.04)
36
+  GPIO.output(17, 1)
37
+  time.sleep(0.04)
38
+  GPIO.output(17, 0)
39
+  time.sleep(0.04)
40
+  GPIO.output(17, 1)
41
+  time.sleep(0.04)
42
+  GPIO.output(17, 0)
43
+  time.sleep(0.04)
44
+  GPIO.output(17, 1)
45
+  time.sleep(0.04)
46
+  GPIO.output(17, 0)
47
+  time.sleep(0.04)
48
+  GPIO.output(17, 1)
49
+  time.sleep(0.04)
50
+  GPIO.output(17, 0)
51
+  time.sleep(0.04)
52
+  GPIO.output(17, 1)
53
+  time.sleep(0.04)
54
+  GPIO.output(17, 0)
55
+  time.sleep(0.04)
56
+  GPIO.output(17, 1)
57
+  time.sleep(0.04)
58
+  GPIO.output(17, 0)
59
+  time.sleep(0.04)
60
+
61
+
62
+def hangup():
63
+  FORK = GPIO.input(6)
64
+  if FORK == 1:
65
+    os.system('linphonecsh generic terminate')
66
+    time.sleep(0.0001)
67
+  else:
68
+      GPIO.input(6)
69
+
70
+def answer():
71
+  FORK = GPIO.input(6)
72
+  if FORK == 1:
73
+    os.system("linphonecsh generic \"answer $(linphonecsh generic 'calls' | sed -n 4p | awk '{print $1}')\"")
74
+    time.sleep(0.0001)
75
+  else:
76
+      GPIO.input(6)
77
+
78
+def dialnumber():                 
79
+  DIAL = GPIO.input(26)           
80
+  NOM = 0                         
81
+  timeout = False                 
82
+  countdown = 100                 
83
+  while countdown > 0:            
84
+        if timeout:               
85
+          countdown = countdown -1
86
+        if DIAL != 1:             
87
+          if NOM == 0:            
88
+            DIAL = GPIO.input(26) 
89
+          else:                   
90
+            if NOM == 10:         
91
+              print("0", end='')
92
+            else:                 
93
+              print(NOM, end='')
94
+          NOM = 0                 
95
+          time.sleep(0.01)        
96
+        elif DIAL == 1:           
97
+          NOM = NOM +1            
98
+          time.sleep(0.109)       
99
+          DIAL = GPIO.input(26)   
100
+          countdown = 500         
101
+          timeout = True          
102
+
103
+def CALL():
104
+  FORK = GPIO.input(6)
105
+  time.sleep(0.1)
106
+  if FORK == 1:
107
+    FORK = GPIO.input(6)
108
+    time.sleep(0.0001)
109
+    RINGCHECK = 'linphonecsh generic \'calls\' | sed -n 4p | awk \'{print $5}\''
110
+    RINGVALUE = subprocess.check_output(['bash', '-c', RINGCHECK ]).decode().strip()
111
+    if RINGVALUE == 'IncomingReceived':
112
+      wecker()
113
+      FORK = GPIO.input(6)
114
+      time.sleep(0.0001)
115
+    else:
116
+      FORK = GPIO.input(6)
117
+      time.sleep(0.0001)
118
+  else:
119
+    FORK = GPIO.input(6)
120
+    CMD = 'linphonecsh generic "answer $(linphonecsh generic \'calls\' | sed -n 4p | awk \'{print $1}\')"'
121
+    VALUE = subprocess.check_output(['bash', '-c', CMD ]).decode().strip()
122
+    if VALUE == 'There are no calls to answer.':
123
+      orig_stdout = sys.stdout
124
+      f = open('dial.txt', 'w')
125
+      sys.stdout = f
126
+      dialnumber()
127
+      time.sleep(0.0001)
128
+      sys.stdout = orig_stdout
129
+      f.close()
130
+      os.system('linphonecsh dial $(cat dial.txt)')
131
+    else:
132
+      FORK = GPIO.input(6)
133
+      answer()
134
+    while FORK == 0:
135
+      FORK = GPIO.input(6)
136
+      time.sleep(0.001)
137
+    else:
138
+      FORK = GPIO.input(6)
139
+      hangup()
140
+
141
+while True:
142
+  CALL()