
IP ATC Asterisk to potężne narzędzie w dziedzinie telefonii IP. Interfejs webowy FreePBX, stworzony dla Asterisk, znacznie upraszcza konfigurację i obniża próg wejścia do systemu.
Jeśli potrafisz wymyślić jakiekolwiek zadanie związane z telefonii IP, to prawie na pewno można je zrealizować w Asterisk. Ale upewnij się, że wymaga to od ciebie determinacji i cierpliwości.
Staliśmy przed zadaniem skonfigurowania powiadomień e-mail o nieodebranych połączeniach. Mówiąc dokładniej, chodziło o informowanie przez e-mail o sytuacjach, gdy przychodzące połączenie trafiło do kolejki, ale nikt (z agentów) nie odpowiedział na to przychodzące połączenie.
Ku zdziwieniu, nie znaleźliśmy standardowych środków do rozwiązania tego zadania w FreePBX. O tym, jak poradziliśmy sobie z tym zadaniem, opowiem poniżej.
Wstęp
Zanim podeszliśmy do problemu z pełnym zaangażowaniem, oczywiście poszukaliśmy informacji w internecie, ale nie znaleźliśmy gotowego rozwiązania (może źle szukaliśmy, ale co zrobić...).
Umiejętności pracy bezpośrednio w Asterisk nie są tak duże, jak byśmy chcieli, dlatego proponowane rozwiązanie , nie było do końca przemyślane i zostało odrzucone.
Podobało mi się rozwiązanie zaproponowane przez , chociaż nie zadziałało. Podkreślono tutaj, że praca w Asterisk powinna odbywać się w kontekście kolejek [ext-queues]. A ponieważ pracujemy w FreePBX, więc praca powinna odbywać się w pliku konfiguracyjnym „extensions_override_freepbx.conf”. Zwrócono uwagę na to, że „łapanie nieodebranych połączeń” jest wygodne przed zdarzeniem hangupcall (zakończenie połączenia).
Przeczytawszy dyskusję , pojawił się pomysł, by filtrować w CDR zmienną „Disposition” dla wszystkich agentów w kolejce. A po przeczytaniu informacji sformułowały się całkiem konkretne kroki do rozwiązania postawionego zadania.
Co mamy:
Mamy FreePBX 13.0.197, który używa Asterisk 13.12.1. Wersja systemu operacyjnego SHMZ release 6.6 (Final). Dystrybucja oparta na CentOS.
W Asterisk skonfigurowano IVR (menu głosowe), które kieruje przychodzące połączenia do różnych kolejek. Każdej kolejce przypisano agentów, tzn. operatorów.
Teoria
Co dzieje się w Asterisk
Kiedy do Asterisk dociera przychodzące połączenie, trafia ono do IVR. Osoba dzwoniąca dokonuje wyboru, naciskając określoną cyfrę na telefonie, i trafia do odpowiedniej kolejki. Po tym wszyscy dostępni agenci kolejki otrzymują równocześnie telefon.
Aby lepiej zrozumieć, co się dzieje w tym momencie i co się dzieje dalej, zwróćmy się do Raportu CDR (Rys.1).

Rys.1
Gdy przychodzące połączenie trafiło do kolejki, wszyscy agenci mieli wartość zmiennej „Disposition” równą „NO ANSWER”, jeśli w danym momencie nie byli zajęci. Zmienna „Disposition” mogła przyjąć również inne wartości (patrz. ), z wyjątkiem wartości „ANSWERED”. W momencie, gdy jeden z agentów odbiera przychodzące połączenie, wartość zmiennej „Disposition” tego agenta staje się równa „ANSWERED”.
Z raportu CDR można zauważyć, że kiedy połączenie przeszło do kolejki (w kolumnie App wartość staje się równa „Queue”), wszystkie zdarzenia mają ten sam „uniqueid” (kolumna System).
Krótko o CDR
Ważne jest, aby zrozumieć, czym jest CDR i w którym momencie dane, które obserwujemy w raporcie CDR, są rejestrowane. CDR, w odniesieniu do systemu operacyjnego, to baza danych, w której Asterisk zapisuje szczegółowy raport połączeń (patrz. ). W naszym przypadku jest to baza o nazwie asteriskcdrdb, która znajduje się w mysql. Doświadczenie pokazuje, że dane o połączeniach z danym „uniqueid” nie są zapisywane w asteriskcdrdb od razu po zaistnieniu jakiegoś zdarzenia, lecz po zdarzeniu hangupcall (zakończenie połączenia).
Zasada działania stworzonego rozwiązania
Ponieważ mamy większą wiedzę na temat basha niż na temat Asteriska, główna idea była następująca. Przed zdarzeniem hangupcall wywołać skrypt bash. Do tego skryptu przekazać 3 parametry. Pierwszy parametr „uniqueid”, do filtrowania danych uzyskiwanych z CDR. Drugi parametr „CALLERID(num)” (numer dzwoniącego), aby wiedzieć, komu oddzwonić. Trzeci parametr „NODEST” (numer kolejki), do której trafiło połączenie, aby wiedzieć, w jakiej sprawie to połączenie dotyczyło i komu wysłać powiadomienie e-mail o nieodebranym połączeniu.
Skrypt bash musi połączyć się z bazą asteriskcdrdb w mysql i pobrać wszystkie wartości zmiennej „Disposition” z określonym „uniqueid”. Z uzyskanych danych należy wykluczyć wartości: „NO ANSWER”, „BUSY”, „FAILED”, „UNKNOWN”. W wyniku tego pozostaną albo „ANSWERED” — połączenie zostało odebrane, albo w ogóle nic — połączenie nieodebrane.
Następnie, jeśli połączenie okazało się nieodebrane, skrypt powinien wysłać powiadomienie e-mail.
Na wstępie warto zaznaczyć istotny punkt. Asterisk wykonuje polecenia sekwencyjnie, czekając na ich zakończenie (co jest całkiem logiczne). Wywołamy skrypt bash przed tym, jak zostanie wykonane polecenie hangupcall. W związku z tym w momencie wykonywania skryptu, w CDR nie będą jeszcze dostępne informacje o pożądanym „uniqueid”. Aby rozwiązać ten problem, wywołamy skrypt bash z parametrem „&”, aby Asterisk od razu przeszedł do następnego kroku, czyli hangupcall. Na początku skryptu bash wprowadzimy małe opóźnienie, aby dać Asterisk czas na wprowadzenie danych z interesującym nas „uniqueid” do CDR.
Praktyka
Zanim przejdziemy do konfiguracji Asterisk i stworzenia skryptu bash, musimy skonfigurować wysyłanie powiadomień e-mail. W tym celu będziemy korzystać z narzędzia postfix.
Konfiguracja postfix
Mamy domenę pocztową „lucky.ru”, znajdującą się w Yandexie. Skonfigurujemy postfix w trybie smtp-klienta i będziemy wysyłać wiadomości z konta asterisk@lucky.ru.
Wzięto za podstawę rozwiązanie stąd: .
Najpierw zainstalujemy/aktualizujemy/sprawdzimy dostępność pakietów:
yum install postfix
yum install mailx
yum install cyrus-sasl cyrus-sasl-lib cyrus-sasl-plainNie będziemy nadpisywać głównego pliku konfiguracyjnego postfix „/etc/postfix/main.cf”, a zamiast tego stworzymy jego kopię zapasową:
cp /etc/postfix/main.cf /etc/postfix/main.cf.savEdytujemy plik „/etc/postfix/main.cf” i przekształcamy go w następujący sposób:
nano /etc/postfix/main.cf
#####################
relayhost =
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/private/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_type = cyrus
smtp_sasl_mechanism_filter = login
smtp_sender_dependent_authentication = yes
sender_dependent_relayhost_maps = hash:/etc/postfix/private/sender_relay
smtp_generic_maps = hash:/etc/postfix/generic
smtp_tls_CAfile = /etc/postfix/ca.pem
smtp_use_tls = yes
smtputf8_autodetect_classes = all
#####################Nie każdą linię w „/etc/postfix/main.cf” można komentować. Komentarze w niektórych liniach nie są rozpoznawane przez parsera i są przekazywane do przetwarzania, co prowadzi do błędów. Lepiej zrezygnować z komentarzy w tym pliku. Możesz to sprawdzić uruchamiając w sąsiednim oknie „tail -f /var/log/messages”.
Zaznaczam linię „smtputf8_autodetect_classes = all”. Ta zapis włącza domyślnie utf-8, co pozwala na użycie cyrylicy zarówno w treści wiadomości, jak i w temacie wiadomości bez dodatkowych manipulacji (Zob. ).
Stwórzmy katalog na pliki konfiguracyjne:
mkdir /etc/postfix/privateEdytujemy plik „/etc/postfix/private/sender_relay”. Musimy wskazać, którego serwera smtp należy używać przy korzystaniu z naszej domeny e-mail.
nano /etc/postfix/private/sender_relay
#####################
@lucky.ru smtp.yandex.ru
#####################Edytujemy plik „/etc/postfix/private/sasl_passwd”. Tutaj podamy adres e-mail, który będziemy używać do wysyłania wiadomości, a także login i hasło do tego konta (login i hasło podajemy przez dwukropek):
nano /etc/postfix/private/sasl_passwd
#####################
asterisk@lucky.ru asterisk@lucky.ru:password_asterisk
#####################Edytujemy plik „/etc/postfix/generic”. W nim ustanowimy zasady zmiany adresu nadawcy (zob. ):
nano /etc/postfix/generic
#####################
root asterisk@lucky.ru
root@localhost asterisk@lucky.ru
root@localhost.localdomain asterisk@lucky.ru
root@freepbx asterisk@lucky.ru
root@freepbx.localdomain asterisk@lucky.ru
root@asterisk asterisk@lucky.ru
root@asterisk.localdomain asterisk@lucky.ru
asterisk asterisk@lucky.ru
asterisk@localhost asterisk@lucky.ru
asterisk@localhost.localdomain asterisk@lucky.ru
asterisk@freepbx asterisk@lucky.ru
asterisk@freepbx.localdomain asterisk@lucky.ru
asterisk@asterisk asterisk@lucky.ru
asterisk@asterisk.localdomain asterisk@lucky.ru
root@localdomain.localdomain asterisk@lucky.ru
#####################Początkowy adres nadawcy zależy od zawartości „/etc/hosts” oraz „/etc/hostname”, jak również od nazwy użytkownika, który będzie wysyłał wiadomość. To znaczy, mimo że używamy klienta smtp i wysyłamy e-maile z asterisk@lucky.ru, postfix początkowo podstawia „coś innego” jako adres nadawcy i należy to poprawić zasadami z tego pliku konfiguracyjnego.
Przedstawię zawartość mojego pliku „/etc/hosts”:
cat /etc/hosts
#####################
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 asterisk.localdomain
127.0.0.1 localhost.localdomain localhost
::1 asterisk localhost localhost6
#####################Ważne jest, aby serwer miał jakąś domenę (wartość po kropce), ponieważ narzędzie mail „szuka” nazwy domeny w „/etc/hosts”, a jeśli nie „znajdzie” jej od razu, to będzie kontynuować to przez kilka minut, a dopiero potem wyśle wiadomość. To znaczy, jeśli domena nie jest zdefiniowana, wiadomość z opóźnieniem będzie wysyłana przez kilka minut.
Przedstawię zawartość mojego pliku „/etc/hostname”:
cat /etc/hostname
#####################
asterisk
#####################Następnie należy przekształcić utworzone pliki konfiguracyjne w zindeksowane bazy danych, w tym celu wykonamy następujące polecenie:
postmap /etc/postfix/generic && postmap /etc/postfix/private/{sasl_passwd,sender_relay}Następnie musimy pobrać i umieścić na serwerze certyfikat smtp.yandex.ru, w tym celu wykonamy następujące polecenie:
openssl s_client -starttls smtp -crlf -connect smtp.yandex.ru:25 > /etc/postfix/ca.pemJednak po tym, jak na ekranie pojawią się informacje techniczne, zespół będzie „dalej wisiał”. Naciśnij Ctrl+C, aby przerwać.
Teraz ręcznie usuniemy wszystkie zbędne elementy z powstałego pliku i pozostawimy tylko certyfikat. Powinno wyglądać to mniej więcej tak:
nano /etc/postfix/ca.pem
#####################
-----BEGIN CERTIFICATE-----
MIIGazCCBVOgAwIBAgIQcUU9mJXW4OUs5Gf0JfLtsjANBgkqhkiG9w0BAQsFADBf
...
nRG0DfdqYIuPGApFORYe
-----END CERTIFICATE-----
#####################I w końcu uruchomimy ponownie postfix:
service postfix restartWysyłamy testowy e-mail:
echo "To jest treść wiadomości" | mail -s "To jest temat" admin@lucky.ruadmin@lucky.ru — adres docelowy
Na tym konfiguracja postfixa się kończy.
Piszemy skrypt bash
Tworzymy katalog do przechowywania skryptu bash (gdzie komu wygodniej):
mkdir /home/asterisk/scriptsTworzymy plik skryptu bash:
touch /home/asterisk/scripts/noanswer.shNadajemy plikowi skryptu uprawnienia do wykonywania:
chmod +x /home/asterisk/scripts/noanswer.shJeśli masz wątpliwości co do uprawnień do pliku, na czas debugowania można nadać pełny dostęp do pliku. Ale to „niebezpieczne”.
chmod 777 /home/asterisk/scripts/noanswer.shTreść skryptu bash:
nano /home/asterisk/scripts/noanswer.sh
#####################
#! /bin/bash
sleep 7
res_sql="SELECT disposition FROM cdr WHERE uniqueid = '$1'"
answer=`mysql -u freepbxuser -pPassword_freepbxuser -D asteriskcdrdb -B -N -e "$res_sql" | grep -E -v "NO ANSWER|BUSY|FAILED|UNKNOWN" | head -n 1`
error_kod=0
if [ "$answer" != "ANSWERED" ]
then
case $3 in
68800)
address="big_boss@lucky.ru"
subject="w ważnej sprawie"
;;
63100)
address="debian@lucky.ru"
subject="w sprawach linux debian"
;;
63200)
address="windows@lucky.ru"
subject="w sprawach windows"
;;
63300)
address="freebsd@lucky.ru"
subject="w sprawach freebsd"
;;
63400)
address="ubuntu@lucky.ru"
subject="w sprawach linux ubuntu"
;;
63500)
address="centos@lucky.ru"
subject="w sprawach linux centos"
;;
*)
address="admin@lucky.ru"
error_kod=1
;;
esac
case $error_kod in
0)
echo "Nieodebrane połączenie od abonenta $2, dzwoniącego o $subject." | mail -s "Nieodebrane połączenie od $2" $address
echo "Nieodebrane połączenie dla $address od abonenta $2, dzwoniącego o $subject. uid=$1" | mail -s "Nieodebrane połączenie od $2" admin@lucky.ru
;;
1)
echo "Nieodebrane połączenie od $2. Kolejka nieznana. uid=$1" | mail -s "Nieodebrane połączenie od $2" admin@lucky.ru
;;
esac
fi
#####################Krótka analiza skryptu:
„sleep 7”:
To jest wspomniane wcześniej opóźnienie czasowe. Ustaliliśmy opóźnienie na 7 sekund. Mimo to myślę, że jedna sekunda w zupełności wystarczy.
„res_sql="SELECT disposition FROM cdr WHERE uniqueid = '$1'"”:Zapytałem w mysql, a wynik przechowaliśmy w osobnej zmiennej dla wygody.
Następnie wykonujemy zapytanie do MySQL i filtrujemy uzyskany wynik. Usuwamy wszystkie opcje poza „ANSWERED”, jeśli taka w ogóle istnieje. Jeśli wartości „ANSWERED” jest kilka, należy pozostawić tylko jedną. Na końcu w zmiennej „answer” otrzymamy albo „ANSWERED”, albo „”.
Jeśli wartość zmiennej „answer” nie jest równa „ANSWERED”, to oznacza, że to była nieodebrana rozmowa. W zależności od numeru kolejki, za pomocą operatora case ustalimy adres, na który należy wysłać powiadomienie e-mail, oraz co dokładnie napisać w tym komunikacie (zmienna część wiadomości).
Następnie rozważany jest przypadek, gdy kolejka została określona w Asterisk, ale nie została opisana w skrypcie. W takim przypadku admin@lucky.ru otrzyma wiadomość e-mail, informującą, że kolejka jest nieznana dla skryptu.
Jeśli kolejka jest opisana, zostanie wysłany e-mail na odpowiedni adres oraz duplikat wiadomości na admin@lucky.ru z adnotacją „uniqueid”, aby móc śledzić wydarzenia związane z tym połączeniem w razie potrzeby.
Na tym skrypt się kończy.
Zauważę, że do połączenia z MySQL użyliśmy loginu i hasła, które wcześniej uzyskaliśmy. W FreePBX, aby poznać login użytkownika Asterisk w MySQL, wykonaj następujące polecenie:
cat /etc/amportal.conf | grep AMPDBUSERAby poznać hasło użytkownika Asterisk w MySQL, wykonaj następujące polecenie:
cat /etc/amportal.conf | grep AMPDBPASSKonfiguracja Asteriska
Używamy FreePBX. W FreePBX istnieją różne typy plików konfiguracyjnych (patrz: ), z których niektóre FreePBX nadpisuje podczas restartu, a niektóre nie (nazywa się je custom), ponieważ są specjalnie przeznaczone dla użytkownika.
Będziemy pracować z plikiem konfiguracyjnym „extensions_override_freepbx.conf”, ponieważ należy on do typu custom.
Na początek upewnijmy się, że w pliku „/etc/asterisk/extensions.conf” dołączono plik „extensions_override_freepbx.conf”. Aby to sprawdzić, wykonaj następujące polecenie:
cat /etc/asterisk/extensions.conf | grep extensions_override_freepbx.conf
#####################
#include extensions_override_freepbx.conf
#####################Edytujemy plik „/etc/asterisk/extensions_override_freepbx.conf” i doprowadzamy go do następującej postaci:
nano /etc/asterisk/extensions_override_freepbx.conf
#####################
[ext-queues]
exten => h,1,System(/home/asterisk/scripts/noanswer.sh ${CDR(uniqueid)} ${CALLERID(num)} ${NODEST} &)
exten => h,2,Macro(hangupcall,)
#####################Jak już wcześniej wspomniałem, symbol „&” na końcu jest obowiązkowy. Ponieważ będziemy pracować w skrypcie bash z danymi CDR bezpośrednio z bazy mysql, a te dane są zapisywane w mysql dopiero po wykonaniu „exten => h,2,Macro(hangupcall,)”, nie należy czekać na zakończenie działania skryptu bash, ale przejść do wykonania następnego kroku w Asterisk. Sam skrypt bash powinien zawierać opóźnienie czasowe przed wykonaniem swojej głównej części.
Aby zmiany w pliku konfiguracyjnym „/etc/asterisk/extensions_override_freepbx.conf” zaczęły obowiązywać, należy ponownie uruchomić jądro Asterisk za pomocą następującej komendy:
/usr/sbin/asterisk -rx "core restart now"To trzeba zrobić po utworzeniu skryptu bash.
Podsumowanie
Prawdopodobnie to 1001 sposób na „łapanie utraconych połączeń” w Asterisk. Podziel się w komentarzach, jak rozwiązujesz ten problem. I co, według Ciebie, można poprawić/przerobić/optymalizować. Będziemy wdzięczni za konstruktywne pomysły.
Źródło: habr.com
