Pull to refresh

Макрос для балансировки исходящих звонков на GSM в Asterisk

Asterisk *Development of communication systems *
Tutorial
Привет, Хабр!

В прошлом топике(уже в черновиках) я обещал предоставить хабрасообществу действующий макрос для балансировки исходящих звонков через N-ное количество сим-карт. Сабж, собственно, найден, усовершенствован и протестирован. Плюс — он гарантирует, что симка с превышенным лимитом использоваться не будет.

Дано: FreeBSD 9, Asterisk 11.4, 2х Addpac GS1002 (используются все 4 сим-карты). Настроено 4 транка на симки: 9001, 9002, 9003, 9004 соответственно. На них полосатый тариф с «безлимитом» 300 минут в месяц на каждой.
Задача: Если на какой-либо симке исчерпан лимит, не использовать ее при наборе. Если же исчерпаны все — слать звонок через провайдера (там чуть дешевле, чем через GSM с тарификацией)

1. Настраиваем сохранение cdr в mysql

Не вижу смысла копипастить сюда мануал. Добавлю лишь, проверьте наличие модуля cdr_mysql.so в своей сборке.

2. Добавляем контекст с макросом в extensions.conf(для работы необходим модуль app_mysql.so — Simple Mysql Interface!)

Сам макрос подробно прокомментирован.

[macro-gsm]

exten => s,1(start),Set(ARG2=$[${ARG2} + 1]) ;инкремент, подробности чуть ниже
same => n,GotoIf($[${ARG2}>=9005]?sip:repeat) ;У нас 4 транка, предлагает 9005 - пускаем через провайдера
same => n(repeat),MYSQL(Connect connid localhost asterisk password asterisk) ; Подключаемся к базе
same => n,MYSQL(Query resultid ${connid} SELECT SUM(`billsec`) FROM `cdr` WHERE `dstchannel` LIKE '%${ARG2}%' AND `calldate` BETWEEN DATE_FORMAT(NOW(),'%Y-%m-01') AND LAST_DAY(NOW()) + INTERVAL 1 DAY) ; Собственно запрос. Результат - суммарное количество тарифицируемых секунд на текущем транке за текущий месяц
same => n,MYSQL(Fetch fetchid ${resultid} duration) ; Результат в переменную duration
same => n,MYSQL(Clear ${resultid}) ;Очистка и отключение от базы
same => n,MYSQL(Disconnect ${connid})
same => n,GotoIf($[${duration}<=18000]?call:start) ; Если через транк прошло менее 300 минут, посылаем звонок через него, нет - отправляемся в начало, в следующем круге используется транк с большим номером
same => n(call),Set(limit=$[18000 - ${duration}]) ; устанавливаем максимальную длительность разговора, чтобы не попасть на деньги
same => n,Dial(SIP/${ARG2}/${ARG1},,S(${limit})tTr) ;Звоним
same => n,GotoIf($[${DIALSTATUS}=ANSWER]?finish:start) ;Разговор состоялся - кладем трубку, транк занят - следующий круг
same => n(sip),Dial(SIP/ctm/${ARG1},,Ttr) ;Звонок через провайдера
same => n(finish),Hangup ;Кладем трубку

exten => h,1,MYSQL(Clear ${resultid}) ; Еще команды на отключение от базы, для перестраховки. 
same => n,MYSQL(Disconnect ${connid})

Пример вызова в диалплане: exten => _79XXXXXXXXX,1,Macro(gsm,${EXTEN},9000)
9000: номер транка — 1

Макрос протестирован и работает. Очевидные минусы — неоптимизированный запрос, названия транков только цифровые. Есть желание помочь — предлагайте в комментариях свои варианты. Плюс — он эффективен)

Спасибо pfactum, PyroRed и Malamut за вдохновение.

UPD: Макрос обновлен, спасибо WhiteD и ragus
Tags:
Hubs:
Total votes 9: ↑9 and ↓0 +9
Views 12K
Comments Comments 16