Моя задача — подключить мобильный телефон как GSM шлюз к Asterisk с помощью chan_mobile. В случае, если я буду недоступен по мобильному, люди смогут оставить мне сообщение на голосовую почту. SMS сообщения доставляются в мой почтовый ящик в виде писем, а мои ответы отсылаются в виде SMS.
Я использовал мой старый телефон Sony Ericsson k530i в связке с Asterisk подключившись через bluetooth адаптер ID 1131:1001 Integrated System Solution Corp. KY-BT100 Bluetooth Adapter.
Asterisk поддерживает подключения телефонов и гарнитур по bluetooth посредством модуля chan_mobile. Не все модели телефонов поддерживаются, я рекомендую проверить вашу модель на voip-info.org. В моём случае bluetooth адаптер KY-BT100 и телефоны Sony Ericsson k530i и Samsung Galaxy S4 работали прекрасно.
Как подключить мобильный телефон к Asterisk через chan_mobile читаем далее…
Подключаем мобильный телефон к Asterisk по bluetooth через chan_mobile
chan_mobile — это дополнение и его необходимо включить до компиляции Asterisk. Для Debian:
1 |
# apt-get install bluez-utils bluez-hcidump libbluetooth-dev |
после этого, перейдите в папку с исходниками Asterisk и выполните make menuselect . Включите дополнение в Add-ons -> chan_mobile:
1 2 |
# cd /usr/src/asterisk-1.8.11.0 # ./configure && make menuselect |
Несмотря на то что модуль успешно скомпилировался и установился, мне потребовалось внести небольшое изменение в исходный код chan_mobile, прежде чем он распознал мой телефон:
1 2 3 4 5 6 7 |
# vi /usr/src/asterisk-1.8.11.0/addons/chan_mobile.c Find this: addr.rc_channel = (uint8_t) 1; Replace with: addr.rc_channel = (uint8_t) 0; |
Теперь можно скомпилировать и установить chan_mobile и Asterisk:
1 |
# make && make install |
Чтобы использовать подлючённый по bluetooth телефон как GSM шлюз, необходимо создать bluetooth пару с сервером Asterisk. В Debian мы можем сделать это из командной строки. Сделайте телефон доступным для обнаружения и затем запустите его поиск:
1 2 3 |
# hcitool scan Scanning ... E0:1A:55:64:A2:52 k530i |
MAC понадобиться на следующих шагах. Для создания пары потребуется PIN код. Запустите следующую команду в фоновом режиме для начала процесса создания пары:
1 2 |
# bluetooth-agent 1111 & # rfcomm connect hci0 E0:1A:55:64:A2:52 |
После успешного завершения процесса создания пары убедитесь, что телефон настроен на автоматический приём запросов подключения. Проверить это можно следующей командой:
1 2 3 |
# hcitool con Connections: < ACL E0:1A:55:64:A2:52 handle 41 state 1 lm MASTER AUTH ENCRYPT |
Теперь необходимо настроить Asterisk на работу с подключенным телефоном. Необходимо знать какой rfcomm канал предоставляет голосовой канал. Самый простой способ — использовать chan_mobile:
1 2 |
# rasterisk *CLI> module load chan_mobile.so |
Не волнуйтесь по поводу возможных сообщений об ошибках. Выполните:
1 2 |
*CLI> mobile search E0:1A:55:64:A2:52 k530i Yes Phone 2 |
В нашем случае это rfcomm канал 2.кроме этого, нам нужно знать MAC адрес bluetooth адаптера, подключенного к серверу Asterisk. Выйдите из консоли Asterisk и используйте hcitool:
1 2 3 |
# hcitool dev Devices: hci0 00:81:C5:33:25:A4 |
Теперь у нас есть вся необходимая информация. В файле chan_mobile.conf (создайте его, если его нет):
1 2 3 4 5 6 7 8 9 10 11 |
# vi /etc/asterisk/chan_mobile.conf [Adapter] address = 00:81:C5:33:25:A4 id = pabx [k530i] address = E0:1A:55:64:A2:52 port = 2 context = from-k530i adapter = pabx |
Пример директив номерного плана для входящих/исходящих звонков:
1 2 3 4 5 6 7 |
# vi /etc/asterisk/extensions.conf [from-k530i] exten => s,1,Dial(SIP/100) [my-phones] exten => *12,1,Dial(MOBILE/k530i/5433) |
Когда на телефон поступит входящий звонок, он будет переадресован на SIP номер 100. Набор комбинации *12 запустит набор последовательности 5433 (абонентская поддержка lifecell). Я уверен, вы поняли идею.
Отсылаем SMS через Asterisk и chan_mobile
Если верить официальной the chan_mobile wiki page, только 3 модели поддерживают SMS: Nokia моделей E51, 6021 и 6230i.
Если телефон находитсяв связке с вервером, он будет доставлять SMS на сервер Asterisk через bluetooth соединение. Asterisk ищет ‘sms’ номер в контексте, указанном в chan_mobile.conf. Вариант номерного плана для обработки входящих SMS:
1 2 3 4 5 6 7 |
[from-k530i] exten => sms,1,Verbose(Incoming SMS from ${SMSSRC} ${SMSTXT}) exten => sms,n,System(echo "To: itgalaxyz@itgala.xyz" > /tmp/smsmail) exten => sms,n,System(echo "Subject: SMS from ${SMSSRC}" >> /tmp/smsmail) exten => sms,n,System(echo "${SMSTXT}" >> /tmp/smsmail) exten => sms,n,System(sendmail -t -f ${SMSSRC}@itgala.xyz < /tmp/smsmail) exten => sms,n,Hangup() |
В предыдущих версиях существовал баг, из-за которого переменная ${SMSSRC} была пуста. Необходим был патч и рекомпиляция:
1 2 3 4 |
# cd /usr/src/asterisk-1.8* # wget --no-check-certificate https://issues.asterisk.org/jira/secure/attachment/42026/sms-sender-fix.diff # patch -p0 < sms-sender-fix.diff # ./configure && make && make install |
В последней версии chan_mobile это уже исправлено!
Теперь входящие сообщения доставляются на мою почту от адресата +MOBILENUMBER@itgala.xyz. Конечно, на сервере Asterisk должен быть работающий МТА, например postfix.
Для исходящих SMS необходимо распарсить тело письма. Питон уже содержит необходимую библиотеку для этого.
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 |
#!/usr/bin/env python # (:? YOUR SCRIPT IS BAD AND YOU SHOULD FEEL BAD! (:? # I'M NOT A DEVELOPER AND THIS IS PROBABLY VERY, VERY BAD, but it does work. # email2sms.py James Stocks # based upon emailspeak.py by sysadminman - http://sysadminman.net # v0.0 2012-04-28 # Import libs we need import sys, time, email, email.Message, email.Errors, email.Utils, smtplib, os, socket, random, re from datetime import date from email.Iterators import typed_subpart_iterator from time import sleep # Asterisk Manager connection details HOST = '127.0.0.1' PORT = 5038 # Asterisk Manager username and password USER = 'your-ast-man-user' SECRET = 'dysmsdvsa' # Generate a random number as a string. We'll use this for file names later on callnum = str(random.randint(1, 100000000)) # Taken from here, with thanks - # http://ginstrom.com/scribbles/2007/11/19/parsing-multilingual- # email-with-python/ def get_charset(message, default="ascii"): """Get the message charset""" if message.get_content_charset(): return message.get_content_charset() if message.get_charset(): return message.get_charset() return default # Taken from here, with thanks - # http://ginstrom.com/scribbles/2007/11/19/parsing-multilingual- # email-with-python/ def get_body(message): """Get the body of the email message""" if message.is_multipart(): #get the plain text version only text_parts = [part for part in typed_subpart_iterator(message, 'text', 'plain')] body = [] for part in text_parts: charset = get_charset(part, get_charset(message)) body.append(unicode(part.get_payload(decode=True), charset, "replace")) return u"\n".join(body).strip() else: # if it is not multipart, the payload will be a string # representing the message body body = unicode(message.get_payload(decode=True), get_charset(message), "replace") return body.strip() # Read the e-mail message that has been piped to us by Postfix raw_msg = sys.stdin.read() emailmsg = email.message_from_string(raw_msg) # Extract database Fields from mail msgfrom = emailmsg['From'] msgto = emailmsg['To'] msgsubj = emailmsg['Subject'] msgbody = get_body(emailmsg) # Find the part of the 'To' field that is the phone number phonenum = re.match( r'\+?([0-9]+)', msgto, re.M) # Whose mobile is this? mobile = sys.argv[1] # Write a log file in /tmp with a record of the e-mails currtime = date.today().strftime("%B %d, %Y") logfile = open('/tmp/email2sms.log', 'a') logfile.write(currtime + "\n") logfile.write("Call Number: " + callnum + "\n") logfile.write("From: " + msgfrom + "\n") logfile.write("To: " + msgto + "\n") logfile.write("Subject: " + msgsubj + "\n") logfile.write("Body: " + msgbody + "\n\n") logfile.close() # Send the call details to the Asterisk manager interface s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) sleep(1) s.send('Action: login\r\n') s.send('Username: ' + USER + '\r\n') s.send('Secret: ' + SECRET + '\r\n\r\n') sleep(1) s.send('Action: originate\r\n') # Dummy channel - I don't actually want any phones to ring s.send('Channel: LOCAL/1@sms-dummy\r\n') s.send('Context: mobiles\r\n') s.send('Exten: ' + mobile + '\r\n') s.send('WaitTime: 30\r\n') # This is a bogus value, but the field is required s.send('CallerId: 5555\r\n') # Do not wait for response from dummy channel s.send('Async: true\r\n') s.send('Priority: 1\r\n') # The variables ${SMSTO} and ${SMSBODY} are used in the dialplan s.send('Variable: SMSTO=' + phonenum.group(1) + ',SMSBODY=\"' + msgbody + '\"\r\n\r\n') sleep(1) s.send('Action: Logoff\r\n\r\n') #Omitting this causes "ast_careful_fwrite: fwrite() returned error: Broken pipe" sleep(3) s.close() |
Сохраните код выше в файл /usr/sbin/email2sms.py и сделайте его выполняемым:
1 |
# chmod +x /usr/sbin/email2sms.py |
Скрипт использует Asterisk Manager Interface, поэтому необходимо добавить AMI пользователя. Добавьте в manager.conf
:
1 2 3 4 5 6 |
# vi /etc/asterisk/manager.conf [your-ast-man-user] secret=dysmsdvsa read=call,user,originate write=call,user,originate |
и проверьте, что AMI включен:
1 2 3 4 5 6 |
# vi /etc/asterisk/manager.conf [general] enabled = yes webenabled = yes port = 5038 |
В питон-скрипте используется контекст ‘mobiles’. Добавьте в extensions.conf:
1 2 3 |
# vi /etc/asterisk/extensions.conf [mobiles] exten => itg,1,MobileSendSMS(k530i,${SMSTO},${SMSBODY}) |
Также нам необходим контекст-«заглушка» для приложения originate:
1 2 3 4 5 6 |
# vi /etc/asterisk/extensions.conf [sms-dummy] exten => 1,1,Answer() exten => 1,n,Wait(10) exten => 1,n,Hangup() |
Перезапустите Asterisk для применения изменений.
Таким образом, вызов скрипта email2sms.py с аргументом ‘itg’ запустит использоваине мобильного телефона k530i.
Необходимо убедиться что почта для домена, в моём случае sms.itgala.xyz — направляется на сервер Asterisk. Для этого обычно нужно создать MX запись или транспорт на вашем почтовом сервере. Это выходит за рамки статьи, здесь я лишь покажу как направить сообщения в питон-скрипт.
Предположим, вы используете postfix:
1 2 3 4 |
# vi /etc/postfix/master.cf sms-itg unix - n n - - pipe flags=FR user=itg argv=/usr/sbin/email2sms.py itg |
указываем, что необходимо использовать эти транспорты для SMS домена:
1 2 3 |
# vi /etc/postfix/transport ; postmap /etc/postfix/transport sms.itgala.xyz sms-itg |
Если настройки transport_maps нет, создайте её:
1 |
# postconf -e transport_maps=hash:/etc/postfix/transport |
Перезвпустите postfix.
1 |
# /etc/init.d/postfix restart |
В случае, если что-то не работает отследить события можно через лог:
1 |
# tail -f /var/log/mail.log |
Также можно провести перехват пакетов на Asterisk Manager Interface:
1 |
# tcpdump -A -i lo port 5038 |
Попробуйте отправить пакет напрямую в AMI:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ nc localhost 5038 Action: login Username: your-ast-man-user Secret: dysmsdvsa Action: originate Channel: LOCAL/1@sms-dummy Context: mobiles Exten: itg WaitTime: 30 CallerId: 5555 Async: true Priority: 1 Variable: SMSTO=5555555555,SMSBODY="foo" Action: Logoff |
Будьте внимательны с пробелами, номер ‘itg’ != ‘itg ‘.
Удачи!