Amateurfunk-EchoLink mit einem Wählscheibentelefon – ein verrücktes Projekt mit glücklichem Ausgang

15. März 2026

Mit einem alten Wählscheibentelefon gezielt EchoLink-Nodes weltweit anrufen – klingt unmöglich, funktioniert aber. Dieser Artikel beschreibt den langen Weg dorthin und was dabei über die Zusammenarbeit mit einer KI gelernt wurde.

Die Idee klingt absurd: Ein altes Wählscheibentelefon, das keine Raute-Taste kennt und nur Impulswahl beherrscht, soll sich mit beliebigen EchoLink-Nodes weltweit verbinden können. EchoLink ist ein System, das Amateurfunkstationen über das Internet miteinander verbindet und normalerweise eine moderne Software oder zumindest ein DTMF-fähiges Telefon voraussetzt. Das Ziel war also von Anfang an sportlich.

Bildschirmfoto zu 2026 03 16 10 00
Das Diagramm zeigt den vollständigen Signalweg vom Wählscheibentelefon bis ins EchoLink-Netz. Die Fritz!Box wandelt das alte Telefon in einen SIP-Client um und leitet den Anruf über den Raspberry Pi an den Esprimo weiter. Dort übernimmt das Python-Script die Steuerung von SVXLink über ein Pseudo-Terminal und ersetzt damit alle Tasteneingaben, die sonst manuell nötig wären.

Was ist EchoLink: EchoLink ist ein System das Amateurfunkstationen weltweit über das Internet miteinander verbindet. Die Grundidee ist einfach: Wer eine Amateurfunklizenz besitzt, kann sich mit einem anderen Funkamateur irgendwo auf der Welt unterhalten, ohne dass die Funkwellen die Distanz tatsächlich überbrücken müssen. Stattdessen wird die Verbindung über das Internet hergestellt, entweder von Computer zu Computer, vom Mobiltelefon zu einer Funkstation oder von Relais zu Relais.

EchoLink gibt es seit 2002 und es ist kostenlos nutzbar, allerdings ausschließlich für lizenzierte Funkamateure. Die Zulassung wird über das offizielle Rufzeichen geprüft, das jeder Funkamateur von der zuständigen Behörde seines Landes erhält. Weltweit sind mehrere hunderttausend Stationen registriert, von denen zu jeder Tages- und Nachtzeit tausende gleichzeitig online sind.

Neben Einzelverbindungen zwischen zwei Stationen gibt es sogenannte Konferenzserver, auf denen sich beliebig viele Teilnehmer gleichzeitig treffen können, ähnlich wie in einem Chatroom, nur eben per Sprache. Bekannte deutsche Konferenzräume sind zum Beispiel GERMANY, auf denen sich Funkamateure aus dem deutschsprachigen Raum treffen. Jede Station und jeder Konferenzraum hat eine eindeutige Nodenummer, über die sie weltweit erreichbar ist.

Zunächst zur ehrlichen Einschätzung:
Der praktische Nutzen dieses Projekts ist sehr begrenzt. Kaum jemand wird ein Wählscheibentelefon besitzen und gleichzeitig EchoLink nutzen wollen. Die Bedienung ist umständlicher als jede moderne Alternative, und der Aufwand für die Installation steht in keinem vernünftigen Verhältnis zum Ergebnis. Aber genau das ist der Charme der Sache. Ein Telefon aus den 1970er Jahren, das über Asterisk und SVXLink ins weltweite EchoLink-Netzwerk telefoniert – das hat eine ganz eigene Faszination, die sich rational kaum erklären lässt.


Über eine  sprachgesteuerte Vermittlung sich mit dem Telefon in das Echolink-Netzwerk einwählen.

Die Hardware-Konstellation ist bewusst zweigeteilt. Ein Raspberry Pi 3B dient als Haupt-Asterisk-Instanz und ist die Schnittstelle zur Außenwelt – er verwaltet die SIP-Accounts der angeschlossenen Telefone und nimmt Anrufe aus dem Heimnetz entgegen. Im gleichen LAN ist er per IAX2-Protokoll mit einem zweiten Asterisk verbunden, der auf dem Hauptrechner läuft, einem Intel Esprimo Q520 mit 8 GB RAM und Ubuntu MATE. Diese Aufteilung hat zwei Vorteile: Der Raspberry wird entlastet, und die gesamte Entwicklungsarbeit an SVXLink und den Python-Scripts kann direkt auf dem Hauptrechner stattfinden, ohne ständig zwischen Geräten wechseln zu müssen. Auf dem Esprimo laufen also der zweite Asterisk mit PJSIP auf Port 5075, SVXLink mit der EchoLink-Anbindung und zusätzlich die sprachgesteuerte Vermittlung Fräulein vom Amt, die OpenAI Whisper zur Spracherkennung nutzt und bereits in einem früheren Artikel beschrieben wurde. All das auf einer Maschine mit bescheidener Hardware – der Esprimo ist kein Kraftpaket, bewältigt die Aufgabe aber problemlos.

Das Wählscheibentelefon ist über die analoge Telefonbuchse einer Fritz!Box angeschlossen, die als ATA fungiert und das alte Gerät in ein vollwertiges SIP-Telefon verwandelt. Die Fritz!Box versteht auch die Impulswahl älterer Telefone und leitet die gewählte Nummer als SIP-Anruf an Asterisk weiter. Die fehlende Raute-Taste ist dabei kein Problem mehr – das Python-AGI-Script echolink_connect.py übernimmt die gesamte Steuerung, die sonst manuell erledigt werden müsste. Nachdem Asterisk die Verbindung zu SVXLink aufgebaut hat, schreibt das Script mit gezielten Zeitverzögerungen eine Befehlssequenz in das Pseudo-Terminal von SVXLink: Zuerst werden mit zwei Hash-Zeichen eventuell noch laufende EchoLink-Verbindungen getrennt und das Modul deaktiviert, dann wird das EchoLink-Modul mit der Sequenz 2# neu aktiviert, und schließlich wird die gewählte Nodenummer gefolgt von einem Hash-Zeichen übergeben. Was früher bedeutet hätte, diese Tasten manuell auf einem DTMF-Telefon eintippen zu müssen, erledigt das Script vollautomatisch im Hintergrund.

Das technische Fundament bildet SVXLink, eine leistungsfähige Open-Source-Software zur Repeatersteuerung unter Linux, die unter anderem EchoLink unterstützt. Die entscheidende Erweiterung ist der pjSipLogic-Branch von Adi/DL1HRC, der SVXLink um eine SIP-Logik erweitert und damit die Verbindung zur Telefonwelt ermöglicht. Diese Erweiterung ist experimentell und muss aus dem Quellcode kompiliert werden, was bereits eine erste Hürde darstellt. Ohne das GitHub-Repository von DL1HRC wäre das Projekt nicht möglich gewesen.

20260223
Der besondere Charme besteht, darin, dass man die EchoLink-Nodes mit einem alten Wählscheibentelefon anwählen kann. Dank des Pythonskripts werden nämlich nur Ziffern für die Eingabe benötigt. Für unterwegs geht es auch mit einem Softphone für das Smartphone.

Die eigentliche Intelligenz steckt in einem Python-AGI-Script namens echolink_connect.py, das von Asterisk aufgerufen wird sobald jemand die Vorwahl 73 gefolgt von einer EchoLink-Nodenummer wählt. Das Script übernimmt die komplette Steuerung: Es baut zunächst die SIP-Verbindung zu SVXLink auf, schreibt dann in einer bestimmten Reihenfolge Steuerbefehle in ein Pseudo-Terminal, das SVXLink überwacht. Dabei werden zunächst eventuell noch laufende EchoLink-Verbindungen getrennt, dann das EchoLink-Modul aktiviert und schließlich die gewünschte Nodenummer übergeben. Alles vollautomatisch, ohne dass der Anrufer eine einzige Taste drücken muss.

Die Konfiguration von SVXLink besteht im Wesentlichen aus drei Teilen. Die svxlink.conf definiert zwei Logiken – eine SimplexLogic mit dem EchoLink-Modul und eine SipLogic für die Telefonanbindung – die über einen sogenannten SipLink miteinander verbunden sind. Die SipLogic.conf enthält die SIP-Zugangsdaten für den lokalen Asterisk. Die ModuleEchoLink.conf konfiguriert EchoLink selbst mit Rufzeichen, Passwort und dem entscheidenden Parameter MUTE_LOGIC_LINKING=0, ohne den kein Audio vom EchoLink zurück zum Telefon fließt. Eine eigene TCL-Datei namens SipLogic.tcl im local-Verzeichnis der SVXLink-Events sorgt dafür, dass DTMF-Töne vom Telefon an die richtige Logik weitergeleitet werden.

Ein entscheidendes Dokument für das Gesamtverständnis war eine PDF-Anleitung von DL1HRC,

https://github.com/dl1hrc/documentation/blob/main/SvxLink-Contributions.pdf

die den genauen Aufbau der SipLogic beschreibt und insbesondere Abschnitt 3.1d zeigt, wie EchoLink über die SipLogic angewählt werden kann. Ohne dieses Dokument wäre die korrekte Verschaltung der beiden SVXLink-Logiken über das DTMF_CTRL_PTY-Pseudo-Terminal nicht klar gewesen.

Die entsprechenden Abschnitte habe ich herauskopiert und an Claude Sonnet übermittelt, das mir dann bei der Konfiguration und beim Kompilieren von svxlink Schritt für Schritt geholfen hat.

Kompilieren: In der PDF- Anleitung  https://github.com/dl1hrc/documentation/blob/main/SvxLink-Contributions.pdf von DL1HRC findet sich die Installationsanleitung für die pjSipLogic-Erweiterung in Abschnitt 3.1 sowie die allgemeine Installationsanleitung ab Abschnitt 2.2. Dort sind die Schritte für die Entwicklungsumgebung, die Installation des pjSIP-Frameworks und das Kompilieren von SVXLink beschrieben. Bild 3 in der Anleitung zeigt die Schrittfolge als Übersicht.

Ein wichtiger Hinweis der in der Anleitung steht und den man unbedingt beachten muss: Das Kompilieren darf nicht als root durchgeführt werden. Das betrifft sowohl das Kompilieren von pjSIP als auch von SVXLink selbst. Der Grund ist dass beim Kompilieren unter root Dateien mit falschen Besitzverhältnissen angelegt werden können, was später beim Start des SVXLink-Dienstes als svxlink-User zu Berechtigungsfehlern führt. Außerdem warnt DL1HRC ausdrücklich davor dass Reste früherer SVXLink-Installationen zu Problemen führen können — eine bestehende Installation sollte daher vorher mit sudo apt remove --purge svxlink-server entfernt werden.

Wer das Kompilieren noch nie gemacht hat, dem empfiehlt sich folgendes Vorgehen: Man kopiert das entsprechende Kapitel aus dem PDF von DL1HRC heraus und übergibt es zusammen mit den tatsächlichen Fehlermeldungen aus dem Terminal direkt an Claude Sonnet. Die KI erklärt dann jeden Schritt, deutet Fehlermeldungen und schlägt Korrekturen vor. Genau so ist dieses Projekt entstanden — durch schrittweise Zusammenarbeit, bei der keine tiefe Programmiererfahrung vorausgesetzt wurde, sondern die KI als geduldiger und kenntnisreicher Begleiter durch den gesamten Prozess geführt hat.

Zusammenarbeit mit  Claude Sonnet 4.6 : Was dieses Projekt aber wirklich bemerkenswert macht, ist nicht das technische Ergebnis selbst, sondern wie es zustande kam. Als Programmieranfänger wäre dieses Projekt ohne die Hilfe von Claude, dem KI-Assistenten von Anthropic, schlicht nicht realisierbar gewesen. Über zwei Tage hinweg wurden Schritt für Schritt Konfigurationsfehler analysiert, Logdateien ausgewertet und Lösungsansätze entwickelt. Was dabei auffiel: Die KI ging bei der Fehlersuche probabilistisch vor wie ein erfahrener Programmierer. Sie suchte proaktiv nach Alternativen, auf die man als Anfänger nie gekommen wäre – etwa der entscheidende Wechsel von der RepeaterLogic zur SimplexLogic auf Hinweis von DL1HRC, oder die Lösung des PTY-Berechtigungsproblems durch Hinzufügen des Asterisk-Users zur tty-Gruppe. Beim Python-AGI-Script wurden mehrere Ansätze durchprobiert und verworfen, bis die richtige Kombination aus direkter stdin/stdout-Kommunikation mit Asterisk und parallelem Schreiben ins SVXLink-PTY gefunden war.

Besonders beeindruckend war, dass sich die KI in die Zielsetzung hineinversetzen konnte, ohne dass jedes Detail neu erklärt werden musste. Sie verstand den Zusammenhang zwischen den einzelnen Komponenten, erinnerte sich an frühere Fehlermeldungen und zog daraus Schlüsse für neue Probleme. Das ist eine neue Qualität der Mensch-Maschine-Zusammenarbeit, die hier sehr deutlich spürbar wurde – nicht als Ersatz für menschliches Verständnis, sondern als geduldiger, kenntnisreicher Partner, der auch um Mitternacht noch neue Ideen hat.

Das Ergebnis übertrifft die ursprüngliche Erwartung sogar noch. Nicht nur lässt sich vom Wählscheibentelefon durch einfaches Wählen von 73 gefolgt von der Nodenummer jeder EchoLink-Node weltweit erreichen. Über die bereits vorhandene Sprachvermittlung Fräulein vom Amt, die Whisper zur Spracherkennung nutzt, kann man einfach den Namen der Konferenz sprechen und wird automatisch verbunden. Ein Telefon aus den 1970ern, das per Stimme EchoLink-Konferenzen weltweit anruft – das hätte sich wohl niemand träumen lassen.

Die Konfigurationsdateien für SVXLink:

# /etc/svxlink/svxlink.conf
[GLOBAL]
LOGIC_CORE_PATH=/usr/lib/x86_64-linux-gnu/svxlink
LOGICS=SimplexLogic,SipLogic
CFG_DIR=svxlink.d
TIMESTAMP_FORMAT="%c"
CARD_SAMPLE_RATE=48000
LINKS=SipLink

[SipLink]
CONNECT_LOGICS=SimplexLogic,SipLogic
DEFAULT_ACTIVE=1

[SimplexLogic]
TYPE=Simplex
RX=Rx1
TX=Tx1
MODULES=ModuleEchoLink
CALLSIGN=SM5ZBS-L
SHORT_IDENT_INTERVAL=60
LONG_IDENT_INTERVAL=60
EVENT_HANDLER=/usr/share/svxlink/events.tcl
DEFAULT_LANG=de_DE
RGR_SOUND_DELAY=0
DTMF_CTRL_PTY=/var/spool/svxlink/dtmf_repeater

[Rx1]
TYPE=Dummy
AUDIO_DEV=none

[Tx1]
TYPE=Dummy
AUDIO_DEV=none
# /etc/svxlink/svxlink.d/ModuleEchoLink.conf
[ModuleEchoLink]
NAME=EchoLink
ID=2
TIMEOUT=60
CALLSIGN=SM5ZBS-L
PASSWORD=DeinEcholinkPasswort
SYSOPNAME=Volker
LOCATION=Finspang JO78tr
SERVERS=servers.echolink.org
MUTE_LOGIC_LINKING=0
DESCRIPTION="SM5ZBS-L EchoLink node"
# /etc/svxlink/svxlink.d/SipLogic.conf
[SipLogic]
TYPE=Sip
DEFAULT_LANG=de_DE
SIPSERVER=127.0.0.1:5075
SIPREGISTRAR=127.0.0.1:5075
SIPPORT=5060
CALLERNAME=SM5ZBS-L <svxlink>
USERNAME=svxlink
PASSWORD=passwort_fuer_sip
SIPSCHEMA=Digest
SIPEXTENSION=default
AUTOANSWER=1
SIP_LOGLEVEL=0
CALL_TIMEOUT=45
SEMI_DUPLEX=0
VOX_FILTER_DEPTH=20
VOX_THRESH=1000
SQL_HANGTIME=1500
SIP_CTRL_PTY=/var/spool/svxlink/sip_pty
DTMF_CTRL_PTY=/var/spool/svxlink/dtmf_repeater
EVENT_HANDLER=/usr/share/svxlink/events.tcl
SIP_PREAMP=3
SIP_LIMITER_THRESH=-1.0
IGNORE_REGISTRATION=1
# AUTOCONNECT=sip:88351864@127.0.0.1:5075
ACCEPT_INCOMING=^(.*)$

SVXLink  Event-Handler: Ort: /usr/share/svxlink/events.d/local/SipLogic.tcl

namespace eval SipLogic {
  variable stored_digits ""

  proc dtmf_digit_received {digit caller} {
    variable port
    variable stored_digits
    puts "Dtmf digit received $digit from $caller"
    if {$digit == "#"} {
      set port [open "/var/spool/svxlink/dtmf_repeater" w+]
      puts $port $stored_digits
      puts $port "#"
      close $port
      set stored_digits ""
    } else {
      set stored_digits "$stored_digits$digit"
    }
    return 0
  }

  proc callTerminated {reason} {
    puts "SIP call terminated, disconnecting EchoLink"
    catch {
      set port [open "/var/spool/svxlink/dtmf_repeater" w+]
      puts $port "#"
      close $port
    }
  }
}

SVXLinks Sounds:  /usr/share/svxlink/sounds/de_DE/ — installiert aus https://github.com/dl1hrc/svxlink-sounds-de_DE-petra  . Es fehlt noch eine welcome.wav in /usr/share/svxlink/sounds/de_DE/SipLogic/welcome.wav, die man mit 16.000 Hz selbst sampeln muss ( welcome.wav.zip ). Das geht Audacity. Der Sprecher ist von ElevenLabs.

Konfigurations-Dateien für Asterisk: Sie befinden sich wie üblich in /etc/asterisk

;===============================================================================
; extensions.conf - Einfacher Dialplan für 3000-3999
;===============================================================================

[general]
static=yes
writeprotect=no


;-------------------------------------------------------------------------------
; Kontext: telefone
;-------------------------------------------------------------------------------
[telefone]

exten => _73.,1,NoOp(EchoLink Node Zielnummer ${EXTEN:2})
 same => n,Noop(Echolink Anrufer: "${CALLERID(name)}" <${CALLERID(num)}>) 
 same => n,AGI(echolink_connect.py,${EXTEN:2})
 same => n,Hangup()

; EchoLink via SVXLink (Vorwahl 77) Alternative Einwahl
exten => _77.,1,NoOp(EchoLink Node ${EXTEN:2})
 same => n,Noop(Echolink: "${CALLERID(name)}" <${CALLERID(num)}>) 
 same => n,Dial(PJSIP/svxlink,60,rtT)
 same => n,Hangup()

; Durchwahl 3000-3999
exten => _3XXX,1,Dial(PJSIP/${EXTEN},60,rtT)
 same => n,Hangup()
 
exten => 501,1,Answer(2)
 same => n,Playback(beep)
 ; Aufnahme: 3 Sek Stille stoppt, max 20 Sek, 's' für Stille-Erkennung
 same => n,Set(AGC(RX)=on)
 same => n,Set(VOLUME(RX)=2.5)
 same => n,Record(/tmp/sprache.wav,3,20,s)
 same => n,Playback(beep) ; Whisper braucht kurz zum Rechnen
 same => n,AGI(whisper_test.py,/tmp/sprache.wav)

 ; Überprüfung: Wenn nichts erkannt wurde, zum Fehler-Teil springen
 same => n,GotoIf($["${RECOGNIZED}" = "nichts"]?no_number,1)
 same => n,GotoIf($["${RECOGNIZED}" = "error"]?no_number,1)

 ; Ansage der Nummer zur Kontrolle
 same => n,Playback(beep)
 same => n,SayDigits(${RECOGNIZED})

 ; JETZT WÄHLEN:
 same => n,Dial(IAX2/outgoing-raspi111/${RECOGNIZED})
 same => n,Hangup()

; Fehlerbehandlung
exten => no_number,1,Playback(beep)
same => n,Hangup()

 
 ; ECHOTEST (HALL, ZEITVERZOEGERUNG DEUTSCH)
exten => 222,1,NoOp(ECHOTEST) 
 same => n,Noop(ECHOTEST: "${CALLERID(name)}" <${CALLERID(num)}>) 
 same => n,Answer()                   ; Abheben
 same => n,Set(CHANNEL(language)=de)
 same => n,Wait(2)                    ; Warten
 same => n,Playback(demo-echotest)    ; Ansage
 same => n,Echo                       ; Echotest
 same => n,Playback(demo-echodone)    ; Bestaetigung
 same => n,Hangup()                   ; Auflegen

; Konferenzraum ohne PIN (z.B. Raum 600 - wähle 600, um beizutreten)
exten => 600,1,ConfBridge(600)
same => n,Hangup()

; IAX2-Verbindung zum Raspi11
exten => _8835X.,1,NoOp(IAX2 - Esprimo ruft Raspi an mit Vorwahl 8835)
 same => n,Dial(IAX2/outgoing-raspi111/${EXTEN:4})

; ── Fräulein vom Amt ────────────────────────────────────────────────────────
; Nebenstelle 500 - Sprachvermittlung
; Dialog läuft komplett in whisper_vermittlung.py
; RECOGNIZED wird gesetzt auf: Nummer | "auflegen" | "error"

exten => 500,1,Noop(Sprachgesteuerte Vermittlung. Teilnehmer: "${CALLERID(name)}" <${CALLERID(num)}>)
 same => n,Answer(1)
 ; same => n,Set(CHANNEL(language)=de)
 ; same => n,Set(AGC(RX)=off)
 ; same => n,Set(VOLUME(RX)=2)
 ; same => n,Set(VOLUME(TX)=1)

 ; Kompletter Dialog läuft im AGI
 ; whisper_vermittlung.py übernimmt:
 ;   - Ansagen via gTTS
 ;   - Aufnahme und Erkennung
 ;   - Bestätigungsdialog
 ;   - Setzt RECOGNIZED, RECOGNIZED_TYPE, RECOGNIZED_NAME
 same => n,AGI(whisper_vermittlung.py)

 ; Auswertung
 same => n,GotoIf($["${RECOGNIZED}" = "auflegen"]?hangup,1)
 same => n,GotoIf($["${RECOGNIZED}" = "error"]?hangup,1)
 same => n,GotoIf($["${RECOGNIZED}" = "nichts"]?hangup,1)

 ; Verbinden
 same => n,NoOp(Verbinde: Typ=${RECOGNIZED_TYPE} Name=${RECOGNIZED_NAME} Nummer=${RECOGNIZED})
 same => n,Dial(IAX2/outgoing-raspi111/${RECOGNIZED})
 same => n,Hangup()

; ── Auflegen ─────────────────────────────────────────────────────────────────
exten => hangup,1,Hangup()

;-------------------------------------------------------------------------------
; Kontext: from-svxlink
; Eingehende Anrufe von SVXLink SipLogic
;-------------------------------------------------------------------------------
[from-svxlink]
exten => s,1,NoOp(Eingehender Anruf von SVXLink)
 same => n,Noop(Echolink: "${CALLERID(name)}" <${CALLERID(num)}>) 
 same => n,Dial(IAX2/outgoing-raspi111/1864,30,rtT)
 same => n,Hangup()
;===============================================================================
; PJSIP Configuration für Asterisk 16+
; Registrar: 192.168.1.235:5075  –  nur LAN 192.168.1.0/24
;===============================================================================

;-------------------------------------------------------------------------------
; Transport Definition (Netzwerk-Bindung)
;-------------------------------------------------------------------------------
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0:5075
local_net=192.168.1.0/24
local_net=127.0.0.1/32
external_media_address=192.168.1.235
external_signaling_address=192.168.1.235

;-------------------------------------------------------------------------------
; Globale Einstellungen
;-------------------------------------------------------------------------------
[global]
max_forwards=70
user_agent=Asterisk PBX

;-------------------------------------------------------------------------------
; ACL – nur LAN zugelassen
;-------------------------------------------------------------------------------
[acl-lan]
type=acl
deny=0.0.0.0/0.0.0.0
permit=192.168.1.0/24
permit=127.0.0.1/32

;-------------------------------------------------------------------------------
; Templates
;-------------------------------------------------------------------------------
[teilnehmer-template](!)
type=aor
max_contacts=1
qualify_frequency=15
default_expiration=300
maximum_expiration=3600

[teilnehmer-auth](!)
type=auth
auth_type=userpass

[teilnehmer-endpoint](!)
type=endpoint
context=telefone
transport=transport-udp
; ACL – nur LAN
deny=0.0.0.0/0.0.0.0
permit=192.168.1.0/24
permit=127.0.0.1/32
; Codec-Einstellungen
disallow=all
allow=g722,alaw,ulaw,gsm,vp8
allow_overlap=no
allow_transfer=no
allow_subscribe=no
; NAT & Media
direct_media=no
rtp_symmetric=yes
force_rport=yes
rewrite_contact=yes
ice_support=yes
; DTMF
dtmf_mode=rfc4733
; Session Timers
timers=no
timers_min_se=90
timers_sess_expires=1800
; QoS/ToS
tos_audio=ef
tos_video=af41
cos_audio=5
cos_video=4
; WebRTC
webrtc=no

;-------------------------------------------------------------------------------
; SVXLink SipLogic
;-------------------------------------------------------------------------------
[svxlink-aor](!)
type=aor
max_contacts=1
qualify_frequency=15
default_expiration=300
maximum_expiration=3600

[svxlink](teilnehmer-endpoint)
auth=svxlink
aors=svxlink
callerid="EchoLink" <7373>
context=telefone
deny=0.0.0.0/0.0.0.0
permit=127.0.0.1/32

[svxlink](teilnehmer-auth)
username=svxlink
password=passwort_fuer_sip

[svxlink](svxlink-aor)

;-------------------------------------------------------------------------------
; Teilnehmer 3001 - Kalle Anka
;-------------------------------------------------------------------------------
[3001](teilnehmer-endpoint)
auth=3001
aors=3001
callerid="Kalle Anka" <3001>

[3001](teilnehmer-auth)
username=3001
password=pass3001

[3001](teilnehmer-template)

;-------------------------------------------------------------------------------
; Teilnehmer 3002 - Donald Duck
;-------------------------------------------------------------------------------
[3002](teilnehmer-endpoint)
auth=3002
aors=3002
callerid="Donald Duck" <3002>

[3002](teilnehmer-auth)
username=3002
password=pass3002

[3002](teilnehmer-template)

;-------------------------------------------------------------------------------
; Teilnehmer 3003 - Dagobert Duck
;-------------------------------------------------------------------------------
[3003](teilnehmer-endpoint)
auth=3003
aors=3003
callerid="Dagobert Duck" <3003>

[3003](teilnehmer-auth)
username=3003
password=pass3003

[3003](teilnehmer-template)

;-------------------------------------------------------------------------------
; Teilnehmer 3004 - Max Mustermann
;-------------------------------------------------------------------------------
[3004](teilnehmer-endpoint)
auth=3004
aors=3004
callerid="Max Mustermann" <3004>

[3004](teilnehmer-auth)
username=3004
password=pass3004

[3004](teilnehmer-template)

;-------------------------------------------------------------------------------
; Teilnehmer 3005 - King Kong
;-------------------------------------------------------------------------------
[3005](teilnehmer-endpoint)
auth=3005
aors=3005
callerid="King Kong" <3005>

[3005](teilnehmer-auth)
username=3005
password=pass3005

[3005](teilnehmer-template)

;-------------------------------------------------------------------------------
; Teilnehmer 3006 - Adam Smith
;-------------------------------------------------------------------------------
[3006](teilnehmer-endpoint)
auth=3006
aors=3006
callerid="Adam Smith" <3006>

[3006](teilnehmer-auth)
username=3006
password=pass3006

[3006](teilnehmer-template)
; iax.conf sending-server ubuntu

[general]
disallow=all
allow=g722  
allow=alaw
allow=ulaw
; allow=g722  

jitterbuffer=yes
forcejitterbuffer=yes
maxjitterbuffer=400    ; ← höher als normal wegen WLAN
resyncthreshold=2000
autokill=yes
delayreject=yes
requirecalltoken=yes
authdebug=yes
; language=de 
qualify=yes


; ****************************

; Verbindung zum Raspberry 192.168.111
; vom Esprimo 192.168.1.235

[outgoing-raspi111]
description=Vorwahl 8891 zum Raspberry
type=peer
host=192.168.1.111
secret=xbodoxzack
auth=md5
context=telefone
trunk=no
qualify=yes
requirecalltoken=no
calltokenoptional=yes
authdebug=no
username=incoming-esprimo235
iaxcompat=yes
deny=0.0.0.0/0.0.0.0
permit=192.168.1.111

[incoming-raspi111]
type=user
host=192.168.1.111
secret=xbodoxzack
auth=md5
context=telefone
trunk=no
qualify=yes
requirecalltoken=no
calltokenoptional=yes
authdebug=no
username=outgoing-esprimo235
iaxcompat=yes
deny=0.0.0.0/0.0.0.0
permit=192.168.1.111


; rtp.conf

[general]
rtpstart=10501
rtpend=10700

jbenable=yes
jbmaxsize=200
jbresyncthreshold=1000
jbimpl=adaptive
; features.conf

[general]
transferdigittimeout => 3

[featuremap]
blindxfer => *

[applicationmap]

Das Python-Skript für AGI: /usr/share/asterisk/agi-bin/echolink_connect.py

#!/usr/bin/env python3
import sys
import time

# AGI Variablen lesen
env = {}
while True:
    line = sys.stdin.readline()
    if not line or line == '\n':
        break
    line = line.strip()
    if ': ' in line:
        key, val = line.split(': ', 1)
        env[key] = val

node_number = env.get('agi_arg_1', '9999')

# ANSWER
sys.stdout.write("ANSWER\n")
sys.stdout.flush()
sys.stdin.readline()

# PTY beschreiben
with open("/var/spool/svxlink/dtmf_repeater", "w") as f:
    f.write("#\n")
time.sleep(3)
with open("/var/spool/svxlink/dtmf_repeater", "w") as f:
    f.write("#\n")
time.sleep(3)
with open("/var/spool/svxlink/dtmf_repeater", "w") as f:
    f.write("2#\n")
time.sleep(3)
with open("/var/spool/svxlink/dtmf_repeater", "w") as f:
    f.write(node_number + "#\n")
time.sleep(1)

# Dial
sys.stdout.write("EXEC Dial PJSIP/svxlink,60,rtT\n")
sys.stdout.flush()
sys.stdin.readline()

Berechtigungen: Zwei Berechtigungsänderungen für das Python-Skript waren nötig.

1. Asterisk-User zur Gruppe tty — das Python-Script läuft unter dem Asterisk-User, aber das PTY `/dev/pts/1` gehört der Gruppe `tty`. Ohne diese Mitgliedschaft konnte das Script nicht ins PTY schreiben und brach stillschweigend ab:

sudo usermod -a -G tty asterisk
sudo systemctl restart asterisk

2. Verzeichnis /var/spool/svxlink/ — SVXLink muss dort die PTY-Symlinks anlegen. Das Verzeichnis gehört dem User svxlink:

sudo mkdir -p /var/spool/svxlink
sudo chown svxlink:svxlink /var/spool/svxlink

Das war der Grund warum das Script lange scheinbar funktionierte — es startete, las die AGI-Variablen, antwortete mit ANSWER — aber beim Öffnen des PTY warf Python eine Exception und beendete sich still, ohne den EXEC Dial zu senden.

Portforwarding: EchoLink benötigt zwei UDP-Ports die in der Fritz!Box weitergeleitet werden müssen:

UDP 5198 — EchoLink Audio
UDP 5199 — EchoLink Steuerung

Beide müssen auf die interne IP des Esprimo weitergeleitet werden, also auf 192.168.1.235, wo sich das Programm svxlink befindet. Ohne diese Portfreigaben verbindet sich EchoLink zwar zum Verzeichnisserver und erscheint als online, aber eingehende Verbindungen von anderen Nodes kommen nicht durch — und ausgehende Verbindungen zu manchen Nodes schlagen ebenfalls fehl.

Wichtige Befehle:

sudo tail -f /var/log/svxlink

Das ist der wichtigste Befehl — er zeigt live was SVXLink tut: eingehende Anrufe, DTMF-Digits, EchoLink-Verbindungsaufbau, Squelch-Ereignisse und Fehlermeldungen.

Wenn du mehr Details über den SIP-Teil sehen willst, erhöhe in der `SipLogic.conf` vorübergehend:

SIP_LOGLEVEL=4

Und für Asterisk parallel dazu:

sudo asterisk -rvvv
agi set debug on

Das zeigt den kompletten AGI-Dialog zwischen Asterisk und dem Python-Script sowie den Aufbau der PJSIP-Verbindung zu SVXLink.

SVXLink starten und stoppen:

sudo systemctl start svxlink
sudo systemctl stop svxlink
sudo systemctl restart svxlink

Und den aktuellen Status prüfen:

sudo systemctl status svxlink

Wichtig: wenn SVXLink als root manuell gestartet wurde, legt es die PTY-Symlinks als root an und der spätere Start als svxlink-User schlägt fehl. Dann vorher aufräumen:

sudo rm /var/spool/svxlink/dtmf_repeater
sudo rm /var/spool/svxlink/sip_pty

Ein klassischer Linux-Fallstrick mit den  Sicherheitskopien von Linux: Wenn man in einem Dateimanager wie Nautilus oder Thunar eine Sicherheitskopie einer Konfigurationsdatei anlegt, entsteht automatisch eine Datei mit einem Namen wie `svxlink.conf (Kopie)` oder `svxlink (noch eine Kopie).conf` — direkt im selben Verzeichnis `/etc/svxlink/`.

SVXLink liest beim Start alle Dateien im Konfigurationsverzeichnis die auf `.conf` enden. Eine Datei namens `svxlink (Kopie).conf` endet auf `.conf` und wird deshalb ebenfalls gelesen. Enthält diese Kopie zum Beispiel noch den alten Eintrag `CALLSIGN=SM5ZBS` statt `CALLSIGN=SM5ZBS-L`, oder eine fehlerhafte DESCRIPTION mit Einrückungen, dann schlägt SVXLink beim Start mit einem kryptischen Syntaxfehler fehl — und man sucht den Fehler in der falschen Datei, weil die eigentliche `svxlink.conf` längst korrekt ist.

Genau das ist uns passiert: SVXLink meldete `Configuration file parse error. Illegal value line syntax on line 12` und startete mehrfach neu, obwohl die aktuelle Konfiguration einwandfrei aussah. Erst als die Kopien gefunden und gelöscht wurden, startete SVXLink sauber. Die Lehre daraus: Sicherheitskopien von SVXLink-Konfigurationsdateien niemals im selben Verzeichnis ablegen, sondern in einem separaten Backup-Ordner außerhalb von `/etc/svxlink/`.

Weiterführend: 

SprachgesteuerteTelefonVermittlung150px
Das „Fräulein vom Amt“ ersetzs die kostenlose Spracherkennungssoftware Whisper in Verbindung mit Asterisk und Python. Die Spracherzeugung erfolgt online mi gTTs.
Sprachgesteuerte Telefonvermittlung mit OpenAI Whisper und Asterisk – 5. März 2026: In vielen Museen stehen sie noch – alte Telefonvermittlungen, stumm und unberührt hinter Glas. Dieses Projekt erweckt eine solche Anlage zum Leben: Besucher heben den Hörer ab, nennen einen Namen oder eine Nummer, und die Vermittlung stellt durch. Was wie Magie klingt, steckt dahinter: das quelloffene Spracherkennungsmodell Whisper von OpenAI, kombiniert mit der Telefonanlage Asterisk auf einem Raspberry Pi. – weiter

Auf einem Raspberry Pi lässt sich ein kompletter Telefonserver betreiben, der seinen Teilnehmern über Landesgrenzen hinweg kostenloses Telefonieren von unterwegs oder daheim ermöglicht.
Asterisk-Telefonserver auf einem Raspberry Pi – Installation, Konfiguration, Programmierung, SIP, IAX2, AGI-Skripte, Sicherheit und Tipps zum praktischen Betrieb – 2.11.2022: Diese Seite richtet sich an jene, welche einen Asterisk-Telefon-Server auf einem Raspberry Pi betreiben möchten und später ein kleines Netzwerk aus Asterisk-Servern planen, um ein eigenständiges Telefonnetz aufzubauen. Los geht es mit der Installation von Raspbian und Asterisk auf einem Raspberry Pi und dann nach Lust und Laune immer tiefer in die Programmierung von Asterisk. Die Themen werden laufend erweitert.

Selbstverständlich muss es nicht unbedingt ein Raspberry Pi sein. Andere Linux-Rechner gehen auch. – weiter