27.12.2024 (aktualisiert am 8. Jan. 2025)
Dieses Python-basierte AGI-Skript ermöglicht es Asterisk-Telefonsystemen, die aktuelle Temperatur eines bestimmten Ortes in Deutschland abzufragen. Der Nutzer gibt eine 5-stellige deutsche Postleitzahl ein, und das Skript liefert die Temperatur für den entsprechenden Ort
Download korrigierte deutschsprachige Fassung mit Sprachdateien: Temperaturen nach PLZ Sprache Deutsch AGI-Skript Soundfiles deutsch.zip
Bedienungsanleitung: Um das Skript zu nutzen, wählen Sie laut Beispiel die Durchwahl 506 auf Ihrem Asterisk-Telefonsystem. Nach dem Wählen werden Sie aufgefordert, eine 5-stellige deutsche Postleitzahl einzugeben. Das Skript prüft Ihre Eingabe und bestätigt sie. Anschließend wird die aktuelle Temperatur für den Ort, der dieser Postleitzahl entspricht, angesagt.
Funktionsweise:
Nach der Eingabe der Postleitzahl wird diese durch eine Anfrage an OpenStreetMap in geographische Koordinaten (Breiten- und Längengrad) umgewandelt.
Mit diesen Koordinaten wird dann eine Anfrage an die met.no API gestellt, die die aktuelle Temperatur liefert.
Die Temperatur wird in Grad Celsius angesagt. Falls ein Fehler auftritt (z.B. eine ungültige Postleitzahl oder eine API-Anfragefehler), wird eine entsprechende Fehlermeldung ausgegeben.
Das Skript ist auf eine Eingabe von genau 5 Ziffern begrenzt, um sicherzustellen, dass nur gültige Postleitzahlen verarbeitet werden.
Das AGI-Skript in Python:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Temperaturangabe mittels deutscher Postleitzahlen # Deutsche Fassung # Mittwoch, 8. Januar 2025 # Korrigierte Version, Fehler mit führender O in den # Postleitzahlen behoben. # Weitere deutsche Audiodateien hinzugefügt # Volker Lange-Janson SM5ZBS # Verwende gerne dieses Programm und passe es an. # Teste es z.B. mit den PLZ 76532 # und 06231 (fuehrende Null) und 80000 (ungültig) import requests import sys import re # Nachfolgendes wird für die Kommunikation mit Asterisk benötigt: #################################################################### # Read the incoming AGI environment variables env = {} while True: line = sys.stdin.readline().strip() if line == '': break key, data = line.split(':', 1) if not key.startswith('agi_'): sys.stderr.write("Did not work!\n") sys.stderr.flush() continue env[key.strip()] = data.strip() sys.stderr.write("AGI Environment Dump:\n") sys.stderr.flush() for key, value in env.items(): sys.stderr.write(f" -- {key} = {value}\n") sys.stderr.flush() def checkresult(params): params = params.rstrip() if re.search('^200', params): result = re.search('result=(\d+)', params) if not result: sys.stderr.write(f"FAIL ('{params}')\n") sys.stderr.flush() return -1 else: result = result.group(1) sys.stderr.write(f"PASS ({result})\n") sys.stderr.flush() return int(result) else: error_code = re.search('result=(-?\d+)', params) if error_code: error_code = int(error_code.group(1)) sys.stderr.write(f"FAIL (unexpected result '{params}', error code {error_code})\n") sys.stderr.flush() return error_code else: sys.stderr.write(f"FAIL (unexpected result '{params}')\n") sys.stderr.flush() return -2 def saynumber(params): sys.stderr.write(f"SAY NUMBER {params} \"\"\n") sys.stderr.flush() sys.stdout.write(f"SAY NUMBER {params} \"\"\n") sys.stdout.flush() result = sys.stdin.readline().strip() return checkresult(result) def sayit(params): sys.stderr.write(f"STREAM FILE {params} \"\"\n") sys.stderr.flush() sys.stdout.write(f"STREAM FILE {params} \"\"\n") sys.stdout.flush() result = sys.stdin.readline().strip() checkresult(result) def getnumber(prompt, timelimit, digcount): sys.stderr.write(f"GET DATA {prompt} {timelimit} {digcount}\n") sys.stderr.flush() sys.stdout.write(f"GET DATA {prompt} {timelimit} {digcount}\n") sys.stdout.flush() result = sys.stdin.readline().strip() return checkresult(result) ################################################################## # Hier fängt das eigentliche Programm an def say_digits(number): """ Sagt jede Ziffer einer Zahl einzeln. """ for digit in str(number): saynumber(digit) limit = 60 digitcount = 5 score = 0 count = 0 ttanswer = 20000 postcode = getnumber("/usr/share/asterisk/sounds/eigene/plztemps/de/zipcode_de_G711.org_", ttanswer, digitcount) # Sicherstellen, dass die Postleitzahl als String behandelt wird postcode = str(postcode).zfill(5) # Führende Nullen sicherstellen sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/you-entered-zipcode_de_G711.org_") say_digits(postcode) sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/irepeat_de_G711.org_") say_digits(postcode) # Funktionen zur API-Nutzung def get_coordinates_from_postcode(postcode): """ Wandelt eine deutsche Postleitzahl in Koordinaten um, basierend auf Nominatim (OpenStreetMap). """ url = "https://nominatim.openstreetmap.org/search" params = { "postalcode": postcode, "country": "Germany", "format": "json" } headers_osm = { "User-Agent": "VolkerLange-Janson/1.0 (janson@janson-soft.de)" } try: response = requests.get(url, params=params, headers=headers_osm) response.raise_for_status() results = response.json() if results: lat = results[0]["lat"] lon = results[0]["lon"] return float(lat), float(lon) else: raise ValueError("Keine Ergebnisse für diese Postleitzahl gefunden!") except requests.RequestException as e: sys.stderr.write(f"Fehler bei der API-Anfrage: {e}\n") sys.stderr.flush() raise except ValueError as e: sys.stderr.write(f"Fehler bei der Verarbeitung der Postleitzahl: {e}\n") sys.stderr.flush() raise def get_weather(lat, lon): """ Holt die Wetterdaten von der API von met.no """ url = f"https://api.met.no/weatherapi/locationforecast/2.0/compact?lat={lat}&lon={lon}" headers_metno = { "User-Agent": "AktuelleTemperaturDeutschePostleitzahl/1.0 (janson@janson-soft.de)" } try: response = requests.get(url, headers=headers_metno) response.raise_for_status() data = response.json() temperature = data["properties"]["timeseries"][0]["data"]["instant"]["details"]["air_temperature"] return round(temperature) except requests.RequestException as e: sys.stderr.write(f"Fehler bei der API-Anfrage für das Wetter: {e}\n") sys.stderr.flush() sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/error2_de_G711.org_") raise except KeyError as e: sys.stderr.write(f"Fehler beim Verarbeiten der API-Daten: {e}\n") sys.stderr.flush() sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/error3_de_G711.org_") raise try: # Koordinaten aus der Postleitzahl berechnen lat, lon = get_coordinates_from_postcode(postcode) # Temperatur von der API holen temperature = get_weather(lat, lon) # Ausgabe der Temperatur sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/temp_de_G711.org_") saynumber(temperature) sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/celsius") sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/irepeat_de_G711.org_") saynumber(temperature) sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/celsius") sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/methan") # Hinweis Klimaschutz sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/ende") except (ValueError, requests.RequestException, KeyError) as e: sys.stderr.write(f"Fehler: {e}\n") sys.stderr.flush() # Ungueltige Postleitzahl sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/error1_de_G711.org_") sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/methan") # Hinweis Klimaschutz sayit("/usr/share/asterisk/sounds/eigene/plztemps/de/ende")
Aufruf in der extensions.conf: Im Beispiel ist die 506 zu wählen.
exten => 506,1,Noop(Anruf erfolgt von: "${CALLERID(name)}" <${CALLERID(num)}>) same => n,Noop(Abfrage aktueller Temperaturen mit deutschen Postleitzahlen) same => n,Noop(SPRACHE: DEUTSCH) same => n,Set(CHANNEL(language)=de) ; Deutsche Prompts verwenden same => n,Answer() same => n,AGI(zipcode-dl-wx.py) same => n,Hangup()
Was zeigt die Asterisk-Konsole beim Ausführen des Skripts? Nachfolgend die Ausgabe in der Asterisk-Konsole, wenn eine Nummer (von einem anderen Server über IAX2) die 506 anwählt, um das AGI-Skript auszuführen. Damit man den vollen Umfang der Informationen erhält, ist in der Konsole
agi set debug on
zu setzen. Mit „agi set debug off“ schalten wir diesen Modus wieder ab.
Accepting AUTHENTICATED call from 192.168.1.111:4569: -- > requested format = alaw, -- > requested prefs = (alaw|g722|ulaw|gsm), -- > actual format = g722, -- > host prefs = (g722|alaw|ulaw|gsm), -- > priority = mine -- Executing [506@telefone:1] NoOp("IAX2/incoming-test77-11708", "Anruf erfolgt von: "Volker Lange-Janson" <1088>") in new stack -- Executing [506@telefone:2] Answer("IAX2/incoming-test77-11708", "") in new stack -- Executing [506@telefone:3] AGI("IAX2/incoming-test77-11708", "zipcode-dl-wx.py") in new stack -- Launched AGI Script /usr/share/asterisk/agi-bin/zipcode-dl-wx.py <IAX2/incoming-test77-11708>AGI Tx >> agi_request: zipcode-dl-wx.py <IAX2/incoming-test77-11708>AGI Tx >> agi_channel: IAX2/incoming-test77-11708 <IAX2/incoming-test77-11708>AGI Tx >> agi_language: en <IAX2/incoming-test77-11708>AGI Tx >> agi_type: IAX2 <IAX2/incoming-test77-11708>AGI Tx >> agi_uniqueid: 1735322486.72 <IAX2/incoming-test77-11708>AGI Tx >> agi_version: 18.10.0~dfsg+~cs6.10.40431411-2 <IAX2/incoming-test77-11708>AGI Tx >> agi_callerid: 1088 <IAX2/incoming-test77-11708>AGI Tx >> agi_calleridname: Volker Lange-Janson <IAX2/incoming-test77-11708>AGI Tx >> agi_callingpres: 0 <IAX2/incoming-test77-11708>AGI Tx >> agi_callingani2: 0 <IAX2/incoming-test77-11708>AGI Tx >> agi_callington: 0 <IAX2/incoming-test77-11708>AGI Tx >> agi_callingtns: 0 <IAX2/incoming-test77-11708>AGI Tx >> agi_dnid: unknown <IAX2/incoming-test77-11708>AGI Tx >> agi_rdnis: unknown <IAX2/incoming-test77-11708>AGI Tx >> agi_context: telefone <IAX2/incoming-test77-11708>AGI Tx >> agi_extension: 506 <IAX2/incoming-test77-11708>AGI Tx >> agi_priority: 3 <IAX2/incoming-test77-11708>AGI Tx >> agi_enhanced: 0.0 <IAX2/incoming-test77-11708>AGI Tx >> agi_accountcode: <IAX2/incoming-test77-11708>AGI Tx >> agi_threadid: 130098168591936 <IAX2/incoming-test77-11708>AGI Tx >> <IAX2/incoming-test77-11708>AGI Rx << GET DATA /usr/share/asterisk/sounds/eigene/plztemps/zipcode 20000 5 -- <IAX2/incoming-test77-11708> Playing '/usr/share/asterisk/sounds/eigene/plztemps/zipcode.slin' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=24534 <IAX2/incoming-test77-11708>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/eigene/plztemps/you-entered-zipcode "" -- <IAX2/incoming-test77-11708> Playing '/usr/share/asterisk/sounds/eigene/plztemps/you-entered-zipcode.slin' (escape_digits=) (sample_offset 0) (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 endpos=20925 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 2 "" -- <IAX2/incoming-test77-11708> Playing 'digits/2.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 4 "" -- <IAX2/incoming-test77-11708> Playing 'digits/4.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 5 "" -- <IAX2/incoming-test77-11708> Playing 'digits/5.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 3 "" -- <IAX2/incoming-test77-11708> Playing 'digits/3.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 4 "" -- <IAX2/incoming-test77-11708> Playing 'digits/4.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 <IAX2/incoming-test77-11708>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/eigene/plztemps/irepeat "" -- <IAX2/incoming-test77-11708> Playing '/usr/share/asterisk/sounds/eigene/plztemps/irepeat.slin' (escape_digits=) (sample_offset 0) (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 endpos=9021 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 2 "" -- <IAX2/incoming-test77-11708> Playing 'digits/2.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 4 "" -- <IAX2/incoming-test77-11708> Playing 'digits/4.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 5 "" -- <IAX2/incoming-test77-11708> Playing 'digits/5.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 3 "" -- <IAX2/incoming-test77-11708> Playing 'digits/3.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 4 "" -- <IAX2/incoming-test77-11708> Playing 'digits/4.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 <IAX2/incoming-test77-11708>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/eigene/plztemps/temp "" -- <IAX2/incoming-test77-11708> Playing '/usr/share/asterisk/sounds/eigene/plztemps/temp.slin' (escape_digits=) (sample_offset 0) (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 endpos=39165 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 5 "" -- <IAX2/incoming-test77-11708> Playing 'digits/5.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 <IAX2/incoming-test77-11708>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/eigene/plztemps/irepeat "" -- <IAX2/incoming-test77-11708> Playing '/usr/share/asterisk/sounds/eigene/plztemps/irepeat.slin' (escape_digits=) (sample_offset 0) (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 endpos=9021 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 5 "" -- <IAX2/incoming-test77-11708> Playing 'digits/5.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 <IAX2/incoming-test77-11708>AGI Rx << STREAM FILE /usr/share/asterisk/sounds/eigene/plztemps/irepeat "" -- <IAX2/incoming-test77-11708> Playing '/usr/share/asterisk/sounds/eigene/plztemps/irepeat.slin' (escape_digits=) (sample_offset 0) (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 endpos=9021 <IAX2/incoming-test77-11708>AGI Rx << SAY NUMBER 5 "" -- <IAX2/incoming-test77-11708> Playing 'digits/5.gsm' (language 'en') <IAX2/incoming-test77-11708>AGI Tx >> 200 result=0 -- <IAX2/incoming-test77-11708>AGI Script zipcode-dl-wx.py completed, returning 0 -- Executing [506@telefone:4] Hangup("IAX2/incoming-test77-11708", "") in new stack == Spawn extension (telefone, 506, 4) exited non-zero on 'IAX2/incoming-test77-11708' -- Hungup 'IAX2/incoming-test77-11708'
Erklärung der verwendeten Webdienste: Das Skript greift auf zwei zentrale Webdienste zu, um die Funktionalität zur Temperaturabfrage basierend auf deutschen Postleitzahlen bereitzustellen:
Nominatim API (OpenStreetMap): Die Nominatim API von OpenStreetMap wird genutzt, um die geografischen Koordinaten (Breitengrad und Längengrad) aus einer deutschen Postleitzahl zu ermitteln.
Anfrage: Die Postleitzahl wird zusammen mit dem Ländercode („Germany“) an die API übergeben.
Ergebnis: Die API liefert die Koordinaten des zugehörigen geografischen Ortes.
Met.no Wetter-API (Norwegian Meteorological Institute): Mit den ermittelten Koordinaten fragt das Skript die Wetter-API von met.no ab.
Anfrage: Die Koordinaten werden als Parameter übergeben.
Ergebnis:Die API liefert detaillierte Wetterdaten, einschließlich der aktuellen Lufttemperatur, die dann im Telefonsystem angesagt wird.
Hinweis: Beide APIs erfordern keine kostenpflichtige Registrierung, jedoch ist es notwendig, für jede Anfrage einen individuellen User-Agent-Header anzugeben. Dieser enthält beispielsweise Deinen Namen oder Projektinformationen und dient der Identifikation und dem verantwortungsvollen Umgang mit den Diensten.
Sounddateien: Sie liegen in US-Englisch vor und wurden mit https://ttsmp3.com/ (Johanna US-English) als MP3 erzeugt und anschließend mit der Voreinstellung von https://g711.org/ umgewandelt.
Sounddateien Englisch Temperaturabfrage mit deutschen Postleitzahlen.zip
Laut Skript gehören die Sounddateien in den Pfad /usr/share/asterisk/sounds/eigene/plztemps/.
************
Wie ist dieses Skript entstanden? Die ursprüngliche Idee stammt von ChatGPT, das dieses Skript auf meine Anregung hin vorstellte:
#!/usr/bin/python3 # -*- coding: utf-8 -*- # Ersetze Max Mustermann und max@mustermann.de durch deinen Namen # und deine eigen E-Mail-Adresse # für die API-Anmeldung import requests import time def get_coordinates_from_postcode(postcode): """ Wandelt eine deutsche Postleitzahl in Koordinaten um, basierend auf Nominatim (OpenStreetMap). """ url = "https://nominatim.openstreetmap.org/search" params = { "postalcode": postcode, "country": "Germany", "format": "json" } headers_osm = { "User-Agent": "Max Mustermann/1.0 (max@mustermann.de)" # Benutzerdefinierter User-Agent für Nominatim } response = requests.get(url, params=params, headers=headers_osm) response.raise_for_status() results = response.json() if results: lat = results[0]["lat"] lon = results[0]["lon"] return float(lat), float(lon) else: raise ValueError("Keine Ergebnisse für diese Postleitzahl gefunden!") def get_weather(lat, lon): """ Holt die Wetterdaten von der API von met.no """ url = f"https://api.met.no/weatherapi/locationforecast/2.0/compact?lat={lat}&lon={lon}" headers_metno = { "User-Agent": "AktuelleTemperaturDeutschePostleitzahl/1.0 (max@mustermann.de)" # User-Agent für met.no } response = requests.get(url, headers=headers_metno) response.raise_for_status() data = response.json() temperature = data["properties"]["timeseries"][0]["data"]["instant"]["details"]["air_temperature"] return round(temperature) try: # Nutzer gibt Postleitzahl ein postcode = input("Gib die deutsche Postleitzahl ein: ") # Koordinaten aus der Postleitzahl berechnen lat, lon = get_coordinates_from_postcode(postcode) # Temperatur von der API holen temperature = get_weather(lat, lon) # Ausgabe der Temperatur print(f"Die aktuelle Temperatur in {postcode} beträgt {temperature} °C.") except ValueError as e: print(f"Eingabefehler: {e}") except requests.RequestException as e: print(f"Fehler bei der API-Anfrage: {e}") except KeyError as e: print(f"Fehler beim Verarbeiten der API-Daten: {e}")
Es ist für die Eingabe und Ausgabe auf der Kommandozeilenebene ausgelegt und läuft z.B. auf Ubuntu mit Thonny.
Damit es als AGI für Asterisk läuft, habe ich die als Beispiel ausgelegte Anleitung auf
http://www.asteriskdocs.org/en/2nd_Edition/asterisk-book-html-chunk/asterisk-CHP-9-SECT-4.html
herangezogen. Mit diesem Beispiel wird erklärt, wie die Eingabe von Nummern über das Tastenfeld des Telefons und die Sprachausgabe von Nummern, Ziffern und Sounddateien in Python verarbeitet wird. Mit etwas Probieren gelang dann die Anpassung. Das habe ich selbst ausprobieren müssen. ChatGPT habe ich dann nochmals den Code untersuchen lassen und baute ein paar Sicherheitsmaßnahmen ein. Diese führten dazu, dass andere laufende Gespräche abgebrochen wurden. Deshalb enfernte ich diese Sicherheitsmaßnahmen wieder.
Hilfestellung durch ChatGPT: ChatGPT hat mir viel Arbeit abgenommen. Dennoch hat es einige Stunden gedauert, bis das Programm so lief, wie ich es mir vorstellte. Bei der Erstellung der Sounddateien hat mir ChatGPT mit den Übersetzungen geholfen. Der Text dieser Seite stammt zu 70% von ChatGPT. Und das witzige Bild hat mir ChatGPT ebenfalls erstellt. Zum Einsatz kam die kostenlose Version von ChatGPT. Vor zwei Jahren war diese KI bei weitem nicht so leistungsfähig und wir können gespannt auf die zukünftige Entwicklung sein, denn die Künstliche Intelligenz befindet sich immer noch in den Kinderschuhen.
Man muss auch bedenken, dass man mit solch ausgefallenen Themen kein Geld verdienen kann. Nur sehr wenige interessieren sich für Asterisk. Noch weniger interessieren sich für die AGI-Programmierung für Asterisk. Durch die zahlreichen Messengerdienste schwindet das Interesse an Telefonsoftware. Das ist bedauerlich. Moderne DECT-Telefone sind bequem in der Handhabung und bieten eine hervorragende Tonqualität selbst mit einer Freisprecheinrichtung.
Weiterführende Informationen zu Asterisk, AGI und Spracheinstellungen:
Deutsche Sprachdateien (german voice prompts) in Asterisk verwenden – 5. Januar 2025: Die Grundinstallation der kostenlosen Telefonsoftware Asterisk stellt leider nur englische Sprachdateien zur Verfügung. Die Erweiterung und Umstellung auf deutsche Sprachdateien wird hier erklärt. Dabei können wir wählen, ob der gesamte Asterisk-Server global auf Deutsch reagieren soll, oder ob er nur bei bestimmten Ereignissen auf Deutsch (oder einer anderen Sprache) reagiert. – weiter – |
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 – |