Моя задача – підключити мобільний телефон як 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 ‘.
Успіхів!