10 июля 2015 г.

Астериск (FreePBX): Делаем селекторную связь.

Поступила однажды задача сделать селекторную связь на одном гос. предприятии при помощи астериска.
Причем сделать так, как они все привыкли: пришел директор, нажал одну кнопочку и все его слышат без дополнительных телодвижений.

Первый пришедший в голову вариант использования встроенного функционала Conference сотрудников данного предприятия не устроил по причине того, что для присоединения к конференции необходимо ж таки набрать ее номер, а это для них тяжело\бла-бла\все такое ...
Так же, директор хотел лично контролировать, кто и когда присоединился к конференции.

В результате был решено использовать слегка допиленный встроенный вариант.

В первую очередь был поставлен модуль FreePBX - Custom Context. С его помощью был сделан кастомный контекст: открываем
Custom Context, жмем Add Custom Context. В верхнее поле Context вписываем название контекста, в данном случае Selector. Опции ниже заполняем по своему усмотрению. Опции, выделенные красным, желательно оставить в Deny. Сохраняем все это дело. Так как данный контекст сделан из веб-морды FreePBX , то напрямую его редактировать в файле нельзя, так как конфигурационные файлы FreePBX генерируются из базы и все изменения потеряются. Что бы такого не произошло, открываем специальный файл extensions_custom.conf, как раз предназначенный для ручного изменения диалплана.
В нем создаем следующий контекст:

--------------------------------------------------------------------------
[Selector-custom]
exten => _999,1,Answer()
exten => _999,n,System(/var/lib/asterisk/bin/selector.sh < /var/spool/asterisk/director.list)
exten => _999,n,MeetMe(998,,Ir)

--------------------------------------------------------------------------


Обратите внимание на слово
Selector в начала данного контекста. Это должно быть то же самое название, что и в созданном ранее Custom Context.
Что происходит в данном контексте ?  При наборе номера 999 вызывается шелл скрипт, после чего создается конференция с номером 998.

Для того, что бы этот самый номер 999 был рабочим, необходимо сделать следующее:
Создаем Misc Application с именем Selector. В поле Feature Code вписываем номер селектора 999. В качестве Destination выбираем "Custom Context"- "Selector".

Создаем Conference с номером 998.
Из  опций ставим User join/leave: и Record Conference: если необходимо.

Далее заходим по ссш на сервер телефонии и создаем два файла: 

/var/lib/asterisk/bin/selector.sh

--------------------------------------------------------------------------
 #!/bin/sh

while read number; do

cat <<EOF  >  /var/spool/asterisk/tmp/$number
Channel: Local/$number@from-internal
Callerid: "SELECTOR" <998>
MaxRetries: 1
RetryTime: 20
WaitTime: 30
Context: Selector
Extension: 998
Priority: 1
Set: CDR(userfield)=\${REASON}
EOF

    chown asterisk:asterisk /var/spool/asterisk/tmp/$number
    mv /var/spool/asterisk/tmp/$number /var/spool/asterisk/outgoing

    echo "$number"
    number=`expr $number + 1`

done

exit 0

--------------------------------------------------------------------------

/var/spool/asterisk/director.list
 в нем просто перечисляем все номера, которые будут автоматически прозваниваться для подключению к селектору.
--------------------------------------------------------------------------
100
130
212
220

-------------------------------------------------------------------------- 

Итак, как это все работает:
Директор приходит на свое рабочее место, набирает 999 и включает громкую связь на своем телефоне. В этот момент скрипт создает call-файлы для всех номеров, перечисленных в файле  director.list и перемещает их в исходящую очередь астериска. Астериск добросовестно начинает звонить по всем номерам. САМ. Как того и требовали сотрудники вышеупомянутого предприятия. Сотрудник, к кому пришел звонок, просто поднимает трубку, называет свою фамилию и присоединяется к конференции. Все уже подключившиеся и директор в том числе, слышат, кто вошел в конферецию.



9 июля 2015 г.

Астериск (FreePBX): прозваниваем не отвеченные вызовы через тот же транк, через который они и приходили.


Ситуация:
На АТС заведено несколько транков, каждый из которых принадлежит отдельной  виртуальной компании. На эти номера звонят клиенты и , бывает, не дозваниваются. Необходимо, что бы звонки менеджера,  обзванивающего не отвеченные вызовы, уходили через тот же транк, через который клиент совершал вызов ранее.


Как сделано:

1. Для "подписи" звонков кто откуда пришел используется стандартный инструмент SetCallerID. Старое значение CallerID Name "${CALLERID(name)}" заменяем на "ARTWEB - ${CALLERID(name)}". "ARTWEB" - название виртуальной компании, куда попадает звонок.
ЭТО ЖЕ название будет позже использоваться для получения информации, откуда пришел звонок.
Итак, делаем новый  SetCallerID, заворачиваем в него входящий маршрут. Точкой выхода из него служит остальная часть вашего диалплана.
Дополнительно получаем профит в виде: а) на экране телефона менеджер сразу видит в какую компанию приходит звонок б) в сдр логе ТАК ЖЕ будет эта запись.

2. Настраиваем исходящие маршруты. Для каждой компании может быть несколько маршрутов. Обязательное условие - наличие уникального префикса для каждой компании. В данном случае 998 для Артвеб, 997 для Мегабит

3. Настраиваем кастомную часть диалплана, ответственного за ручную маршрутизацию исходящих звонков как нам надо. Открываем extensions_custom.conf и вставляем:

------------------------------------------------------
[from-internal-custom]
exten => _X.,1,NoOp(AMPUSER = $["${AMPUSER}"])
exten => _X.,n,NoOp(UNIQUEID = $["${UNIQUEID}"])
exten => _X.,n,NoOp(CALLERID NAME = ${CALLERID(name)})
exten => _X.,n,NoOp(CALLERID NUMBER = ${CALLERID(number)})

# Mb its a internal number - goto exit
exten => _X.,n,GotoIf($[LEN(${EXTEN}) < 7]?990)

exten => _X.,n,MYSQL(Connect connid localhost freepbxuser superpassword asteriskcdrdb)
exten => _X.,n,MYSQL(Query resultid ${connid} select clid from cdr where src like '%${EXTEN}%' and calldate > NOW() - INTERVAL 7 DAY  order by calldate desc limit 1)
exten => _X.,n,MYSQL(Fetch fetchid ${resultid} TEMPNAME)
exten => _X.,n,MYSQL(Clear ${resultid})
exten => _X.,n,MYSQL(Disconnect ${connid})

# External number not found in DB - goto default
exten => _X.,n,GotoIf($[${fetchid} = 0]?980)

exten => _X.,n,Set(TEMPNAME=${TEMPNAME:1:5})
exten => _X.,n,NoOp(TEMPNAME = $[${TEMPNAME}])

exten => _X.,n,GotoIf($[${TEMPNAME} = MEGAB]?951:960)
exten => _X.,951,NoOp(EXTEN ${EXTEN} go to 997 MEGABIT)
exten => _X.,952,Goto(from-internal-additional,997${EXTEN},1)

exten => _X.,960,GotoIf($[${TEMPNAME} = ARTWE]?961:970)
exten => _X.,961,NoOp(EXTEN ${EXTEN} go to 998 ARTWEB)
exten => _X.,962,Goto(from-internal-additional,998${EXTEN},1)

exten => _X.,970,GotoIf($[${TEMPNAME} = UNDER]?971:980)
exten => _X.,971,NoOp(EXTEN ${EXTEN} go to 999 UNDERNET)
exten => _X.,972,Goto(from-internal-additional,999${EXTEN},1)

# Default for external numbers
exten => _X.,980,NoOp(Number ${EXTEN} not found in DB)
exten => _X.,n,Goto(from-internal-additional,998${EXTEN},1)

# Default for internal numbers
exten => _X.,990,Goto(from-internal-additional,,1)

exten => h,1,Hangup

------------------------------------------------------
По диалплану:
Исходящие звонки совершаются из контекста from-internal. Экстеншн длиной меньше семи цифр считается внутренним номером и следуат дальнейшему диалплану (from-internal-additional) без изменений. Номер более семи цифр считается исходящим (менеджер совершает звонок). Этот номер ищется в БД MySQL (которая же, конечно, должна быть настроена на хранение логов звонков) за последние семь дней. Если номер найден, то выбирается его clid вида "ARTWEB - 380679999999 "<380679999999>. Далее к исходящему номеру добавляется ПРЕФИКС соответствующей компании, как было ранее описано при настройке исходящих маршрутов и звонок отправляется по своему законному маршруту в контекст from-internal-additional.
В случае, если номер не найден в БД, звонок идет в марштут "по умолчанию". В данном случае с префиксом 998.

 Собственно, вот и вся магия.


6 сентября 2012 г.

Поставил голый Дебиан - сделай так ;-)


Так как на текущий момент с Дебианом я на "вы", то данная заметка тут для "что бы не забыть".

aptitude update && aptitude full-upgrade
aptitude install ntpdate sockstat smartmontool sysv-rc-conf screen mc

В файле /etc/default/ntpdate поправить:
NTPDATE_USE_NTP_CONF=no
Будет использоваться сервер времени по умолчанию, прописанный в этом же файле.

В файле /etc/snmp/snmpd.conf поправить:
а)  agentAddress udp:ИП_НУЖНОГО_ИФЕЙСА:161
б) закомментировать #defaultMonitors (в логе много ошибок именно на эту строку)
в) rocommunity ИМЯ_COMMUNITY default
г) закомментировать #rocommunity public default

Настраиваем сервисы на автозагрузку:
sysv-rc-conf ntpdate on
sysv-rc-conf snmpd on

Устанавливаен нашу временнУю зону
dpkg-reconfigure tzdata, выбираем Europa\Kiev

Изменяем редактор по умолчанию:
update-alternatives --config editor

Прописываем в крон автокоррекцию времени - в 03 минуты каждого часа.
echo "3 * * * * root /usr/sbin/ntpdate -bu 10.0.221.1" >> /etc/crontab

БложеГ: The beginning

Давно хотел сделать себе блог, в который бы записывал нужные на данный момент заметки \ решения вопросов...
Решился, наконец-то =)