Скрипт включения DND путём имитации вызова сервисного кода *78
В этой статье рассмотрим реализацию скрипта, который будет имитировать нажатие сервисного кода *78 на аппарате (тем самым выставляя его в режим DND). Также рассмотрим необходимый кастомный диалплан под данный функционал. Кроме того изменим хинты (добьёмся того, чтобы статус DND корректно отображался в очередях и BLF). Перейдём к реализации. Для начала необходимо подготовить кастомный диалплан, который […]
В этой статье рассмотрим реализацию скрипта, который будет имитировать нажатие сервисного кода *78 на аппарате (тем самым выставляя его в режим DND). Также рассмотрим необходимый кастомный диалплан под данный функционал. Кроме того изменим хинты (добьёмся того, чтобы статус DND корректно отображался в очередях и BLF).
Перейдём к реализации. Для начала необходимо подготовить кастомный диалплан, который будет отвечать за постановку определённого номера в режим DND.
Кастомный диалплан.
Кастомный диалплан будет располагаться в файле extensions_custom.conf. Откроем его в режиме редактирования.
В контекст [from-internal-custom] поместим следующий диалплан:
exten => _*78X.,1,NoOp(==== ${DEVICE_STATE(SIP/${EXTEN:3})} ====)
same => n,GotoIf($["${DEVICE_STATE(SIP/${EXTEN:3})}" != "INVALID"]?app-dnd-on-put,${EXTEN:3},1)
exten => _*79X.,1,NoOp(==== ${DEVICE_STATE(SIP/${EXTEN:3})} ====)
same => n,GotoIf($["${DEVICE_STATE(SIP/${EXTEN:3})}" != "INVALID"]?app-dnd-off-put,${EXTEN:3},1)
Тем самым при наборе сервисного кода *78Внутренний_Номер_Абонента будет вызываться контекст app-dnd-on-put (опишем его ниже). В нём будет описан диалплан включения DND на экстеншене.
С app-dnd-off-put всё аналогично, только диалплан вызывается для снятия DND.
Данным диалпланом достигнем возможности ставить не только свой внутренний номер в DND, но также внутренний номер другого абонента.
Кроме того, если необходимо считать какую-либо статистику нахождения абонентов в DND, то данный скрипт можно добавить к выполнению текущего диалплана.
Приведём диалплан контекста app-dnd-on-put:
[app-dnd-on-put]
exten => _X.,1,Answer
exten => _X.,n,Wait(1)
exten => _X.,n,Macro(user-callerid,)
exten => _X.,n,Set(DB(DND/${EXTEN})=YES)
exten => _X.,n,Set(STATE=BUSY)
exten => _X.,n,Gosub(app-dnd-on-put,sstate,1())
exten => _X.,n(hook_1),Macro(hangupcall,)
exten => sstate,1,Set(DEVICE_STATE(Custom:DND${EXTEN})=${STATE})
exten => sstate,n,Set(DEVICES=${DB(AMPUSER/${EXTEN}/device)})
exten => sstate,n,GotoIf($["${DEVICES}" = "" ]?return)
exten => sstate,n,Set(LOOPCNT=${FIELDQTY(DEVICES,&)})
exten => sstate,n,Set(ITER=1)
exten => sstate,n(begin),Set(DEVICE_STATE(Custom:DEVDND${CUT(DEVICES,&,${ITER})})=${STATE})
exten => sstate,n,Set(ITER=$[${ITER} + 1])
exten => sstate,n,GotoIf($[${ITER} <= ${LOOPCNT}]?begin)
exten => sstate,n(return),Return()
Теперь рассмотрим контекст app-dnd-off-put:
[app-dnd-off-put]
exten => _X.,1,Answer
exten => _X.,n,Wait(1)
exten => _X.,n,Macro(user-callerid,)
exten => _X.,n,Noop(Deleting: DND/${EXTEN} ${DB_DELETE(DND/${EXTEN})})
exten => _X.,n,Set(STATE=NOT_INUSE)
exten => _X.,n,Gosub(app-dnd-off-put,sstate,1())
exten => _X.,n(hook_1),Macro(hangupcall,)
exten => sstate,1,Set(DEVICE_STATE(Custom:DND${EXTEN})=${STATE})
exten => sstate,n,Set(DEVICES=${DB(AMPUSER/${EXTEN}/device)})
exten => sstate,n,GotoIf($["${DEVICES}" = "" ]?return)
exten => sstate,n,Set(LOOPCNT=${FIELDQTY(DEVICES,&)})
exten => sstate,n,Set(ITER=1)
exten => sstate,n(begin),Set(DEVICE_STATE(Custom:DEVDND${CUT(DEVICES,&,${ITER})})=${STATE})
exten => sstate,n,Set(ITER=$[${ITER} + 1])
exten => sstate,n,GotoIf($[${ITER} <= ${LOOPCNT}]?begin)
exten => sstate,n(return),Return()
В итоге должен получиться диалплан, как на скриншоте ниже:
Сохраняем файл.
Теперь необходимо проверить текущие промежуточные настройки и убедиться, что наш диалплан работает верно. Для этого выполним следующее.
Первым делом зайдём в консоль Asterisk и выполним команду:
dialplan reload
Теперь с любого телефона или софтфона, подключённого к Asterisk’у необходимо набрать сервисный код *78X, где X — внутренний номер абонента, которого хотим поставить в DND.
К примеру, для того, чтобы поставить в режим DND телефон, с внутренним номером 0008, необходимо позвонить на сервисный код *780008.
Проверим, что сервисный код отработал и DND успешно установлен. Для этого есть несколько способов (к примеру можно позвонить на данный внутренний номер, если звонок не прошёл — значит DND успешно установлен). Но мы рассмотрим несколько иной способ — проверку через внутреннюю базу Asterisk — AstDB.
Выполним следующую команду в консоли Asterisk:
database get DND 0008
Если результат будет таким же, как показано на скриншоте ниже, значит диалплан отработал верно.
Этой же командой можно проверить, что сервисный код снятия DND (то есть *79Х) также отработает. Выведем телефон из режима DND и перейдём к написанию скрипта вызова данных сервисных кодов.
Скрипт вызова сервисных кодов
Основной принцип работы данного скрипта заключается в следующем: В качестве GET-запроса на вход скрипта подаются два параметра: внутренний номер телефона (на нём и будет включаться DND) и команда на включение/отключение DND. В процессе выполнения скрипт будет вызывать подготовленные коды снятия/постановки DND (описанные в предыдущем пункте).
Первым делом необходимо считать значение, которое передаётся GET-запросом. Ипользуем для этого тернарный оператор. В случае, если переменная account не задана в запросе, то $ext остаётся пустым.
$ext = (isset($_GET['account'])) ? trim($_GET['account']) : "";
Производить какие-либо действия с DND имеет смысл, только если переменная $ext не пуста, поэтому добавляем условие:
if ($ext != "") {
В данный блок помещаем следующий код:
writelog("extensions $ext found!");
if ($_GET['dnd'] == "on") {
writelog("Enable DND on $ext");
Call("*78".$ext);
$ret = `/usr/sbin/asterisk -rx 'devstate change Custom:DEVDND{$ext} BUSY'`;
writelog(trim($ret));
}
elseif ($_GET['dnd'] == "off") {
writelog("Disable DND on $ext");
Call("*79".$ext);
$ret = `/usr/sbin/asterisk -rx 'devstate change Custom:DEVDND{$ext} NOT_INUSE'`;
writelog(trim($ret));
}
else {
writelog("ERROR: DND value is incorrect. Nothing to do.");
exit();
}
Рассмотрим приведённый выше код. Сперва производится запись в лог соответствующей функцией writelog (будет рассмотрена немного позже). Затем проверяем, был ли передан GET-запросом параметр DND. В зависимости от его результата либо вызываем функцию Call с параметром *78 и номер абонента, либо *79 и номер абонента. В случае, если в качестве параметра DND ничего не передалось, либо передалось неверное значение, то пишем в лог ошибку и выходим из программы.
На этом закрывается условие $ext != “”, т.е. в код дописываем:
}
else {
writelog("ERROR: Not found extensions. Nothing to do");
}
Тем самым в скрипт добавили обработчик ситуации, если внутренний номер не был передан.
Теперь рассмотрим функцию, предназначенную для вызова сервисного кода. Производиться вызов будет с помощью AMI функции Originate.
В данной функции обязательно указать 3 переменные:
$port — порт подключения к AMI;
$username — имя пользователя AMI;
$password — пароль подключения к AMI для данного пользователя.
Все эти данные можно найти в файле manager.conf
На скриншоте ниже показан пример такого файла. При этом значения переменных распределятся следующим образом: $port = 5038; $username = admin; $password = nasdnioh1123nasd8h12jbqd8y21e1bdq2.
Функция Call в данном случае имеет весьма стандартную структуру, так что описывать подробно её не будем, лишь приведём код:
function Call($numb) {
$port = 5038;
$username = "admin";
$password = "nasdnioh1123nasd8h12jbqd8y21e1bdq2";
$context = "from-internal";
$socket = stream_socket_client("tcp://127.0.0.1:$port");
if($socket) {
writelog("Connected to socket, sending authentication request.");
// Prepare authentication request
$authenticationRequest = "Action: Login\r\n";
$authenticationRequest .= "Username: $username\r\n";
$authenticationRequest .= "Secret: $password\r\n";
$authenticationRequest .= "Events: off\r\n\r\n";
// Send authentication request
$authenticate = stream_socket_sendto($socket, $authenticationRequest);
if($authenticate > 0) {
// Wait for server response
usleep(200000);
// Read server response
$authenticateResponse = fread($socket, 4096);
// Check if authentication was successful
if(strpos($authenticateResponse, 'Success') !== false) {
writelog("Authenticated to Asterisk Manager Inteface. Initiating call.");
// Prepare originate request
$originateRequest = "Action: Originate\r\n";
$originateRequest .= "Channel: Local/$numb@$context/n\r\n";
$originateRequest .= "Async: yes\r\n\r\n";
// Send originate request
$originate = stream_socket_sendto($socket, $originateRequest);
if($originate > 0) {
// Wait for server response
usleep(200000);
// Read server response
$originateResponse = fread($socket, 4096);
// Check if originate was successful
if(strpos($originateResponse, 'Success') !== false) {
writelog("Call initiated, dialing.");
} else {
writelog("Could not initiate call.");
}
} else {
writelog("Could not write call initiation request to socket.");
}
} else {
writelog("Could not authenticate to Asterisk Manager Interface.");
}
} else {
writelog("Could not write authentication request to socket.");
}
} else {
writelog("ERROR: Unable to connect to socket.");
}
}
Одно из существенных изменений, которое было внесено в данный скрипт — это внедрение своей функции логирования (writelog). Таким образом, весь лог скрипта собирается и записывается в отдельный файл.
Остаётся рассмотреть последнюю и самую короткую функцию — writelog. На вход она принимает строку, которая будет выведена в файле лога (dndlog)
function writelog($str) {
$fl = fopen("/var/log/asterisk/dndlog", "a");
fwrite($fl, date('Y-m-d H:i:s')." ".$str."\n");
fclose($fl);
}
На этом описание файла скрипта закончено. Можно сохранять его и проверять работу.
Остались вопросы?
Я - Кондрашин Игорь, менеджер компании Voxlink. Хотите уточнить детали или готовы оставить заявку? Укажите номер телефона, я перезвоню в течение 3-х секунд.
категории
- DECT
- Linux
- Вспомогательный софт при работе с Asterisk
- Интеграция с CRM и другими системами
- Интеграция с другими АТС
- Использование Elastix
- Использование FreePBX
- Книга
- Мониторинг и траблшутинг
- Настройка Asterisk
- Настройка IP-телефонов
- Настройка VoIP-оборудования
- Новости и Статьи
- Подключение операторов связи
- Разработка под Asterisk
- Установка Asterisk
VoIP оборудование
ближайшие курсы
Новые статьи
10 доводов в пользу Asterisk
Распространяется бесплатно.
Asterisk – программное обеспечение с открытым исходным кодом, распространяется по лицензии GPL. Следовательно, установив один раз Asterisk вам не придется дополнительно платить за новых абонентов, подключение новых транков, расширение функционала и прочие лицензии. Это приближает стоимость владения станцией к нулю.
Безопасен в использовании.
Любое программное обеспечение может стать объектом интереса злоумышленников, в том числе телефонная станция. Однако, сам Asterisk, а также операционная система, на которой он работает, дают множество инструментов защиты от любых атак. При грамотной настройке безопасности у злоумышленников нет никаких шансов попасть на станцию.
Надежен в эксплуатации.
Время работы серверов некоторых наших клиентов исчисляется годами. Это значит, что Asterisk работает несколько лет, ему не требуются никакие перезагрузки или принудительные отключения. А еще это говорит о том, что в районе отличная ситуация с электроэнергией, но это уже не заслуга Asterisk.
Гибкий в настройке.
Зачастую возможности Asterisk ограничивает только фантазия пользователя. Ни один конструктор шаблонов не сравнится с Asterisk по гибкости настройки. Это позволяет решать с помощью Asterisk любые бизнес задачи, даже те, в которых выбор в его пользу не кажется изначально очевидным.
Имеет огромный функционал.
Во многом именно Asterisk показал какой должна быть современная телефонная станция. За многие годы развития функциональность Asterisk расширилась, а все основные возможности по-прежнему доступны бесплатно сразу после установки.
Интегрируется с любыми системами.
То, что Asterisk не умеет сам, он позволяет реализовать за счет интеграции. Это могут быть интеграции с коммерческими телефонными станциями, CRM, ERP системами, биллингом, сервисами колл-трекинга, колл-бэка и модулями статистики и аналитики.
Позволяет телефонизировать офис за считанные часы.
В нашей практике были проекты, реализованные за один рабочий день. Это значит, что утром к нам обращался клиент, а уже через несколько часов он пользовался новой IP-АТС. Безусловно, такая скорость редкость, ведь АТС – инструмент зарабатывания денег для многих компаний и спешка во внедрении не уместна. Но в случае острой необходимости Asterisk готов к быстрому старту.
Отличная масштабируемость.
Очень утомительно постоянно возвращаться к одному и тому же вопросу. Такое часто бывает в случае некачественного исполнения работ или выбора заведомо неподходящего бизнес-решения. С Asterisk точно не будет такой проблемы! Телефонная станция, построенная на Asterisk может быть масштабируема до немыслимых размеров. Главное – правильно подобрать оборудование.
Повышает управляемость бизнеса.
Asterisk дает не просто набор полезных функций, он повышает управляемость организации, качества и комфортности управления, а также увеличивает прозрачность бизнеса для руководства. Достичь этого можно, например, за счет автоматизации отчетов, подключения бота в Telegram, санкционированного доступа к станции из любой точки мира.
Снижает расходы на связь.
Связь между внутренними абонентами IP-АТС бесплатна всегда, независимо от их географического расположения. Также к Asterisk можно подключить любых операторов телефонии, в том числе GSM сим-карты и настроить маршрутизацию вызовов по наиболее выгодному тарифу. Всё это позволяет экономить с первых минут пользования станцией.