Как сделать будильник при помощи Asterisk, FreeBSD и наличии небольшого количества свободного времени

в 13:55, , рубрики: asterisk, freebsd, будильник, системное администрирование, метки: , ,

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

Сказано — сделано. Решил я написать будильник.

Как будем реализовывать?

Диалплан решил не трогать, ибо он и так уже не самый маленький, и усложнять его не хочется. Поэтому было решено написать shell скрипт, который запускается по крону и создает call-файлы с нужными данными.

Записывать кому и когда звонить в сам скрипт мне показалось неудобным, поэтому был создан текстовый файл alarmnumbers.txt вида:

89993332211 1000 1100 1200 1300 1400 1500 1600 /recs/macroform-robot_dity
89993332211 1005 1105 1205 1305 1405 XXXX XXXX /recs/macroform-robot_dity

Где первое это номер телефона, на который будет совершен звонок, дальше идут 7 блоков, разделенных пробелами, с указанием времени звонка: первый блок для понедельника, второй для вторника, и так далее. В самом конце путь к файлу, который будет воспроизведен, если поднимут трубку. Это должен быть любой звуковой файл, который астериск сможет скушать. Имя файла пишется без разрешения, астер сам выберет, какое ему нужно. Можно звуковой файл и вовсе не указывать, в таком случае при поднятии трубки звонок будет сразу же сброшен. Ну а XXXX вместо времени указывает не совершать побудку. К примеру, в выходные.

В файлике может быть сколько угодно строк, повторения номеров тоже допустимы. Решение, конечно, не самое оптимальное, но поскольку использование будильника предполагается только внутри IT отдела, то вполне подходящее. Разместил я его на шаре win сервера, подцепив её к FreeBSD при помощи mount_smbfs.

Сам скрипт запускается по крону раз в сутки. Т.е. обновление данных кому и куда звонить происходит каждый день в 00.02.

Разберем, что делает скрипт:

#!/bin/sh

echo 'START!'

filename=/recs/alarmnumbers.txt
CallFileName=AlarmFile
NewCallFilesPath=/var/spool/asterisk/outgoing_new/
AsteriskCallFilePath=/var/spool/asterisk/outgoing/

Указываем, где что лежит и как называть call-файлы для asterisk (ему, кстати, имя файла не важно, можете указать любое)
filename — наш файл со списком кому и когда
CallFileName — имя call-файла, только для нашего удобства
NewCallFilesPath — каталог для создаваемых call-файлов. Создавать их там, откуда их берет астер, нельзя — читает он их быстро и часто, может прочитать неполный. Этот каталог должен быть на том же разделе с каталогом, где астер ищет call-файлы для выполнения.
AsteriskCallFilePath – каталог, из которого астер читает call-файлы. Т.к. у меня FreeBSD, у вас они могут располагаться в другом месте.


currentdate=$(date +%Y%m%d)
weekday=$(date +%u)
var0=0

Запоминаем текущее время и день недели.


case "$weekday" in
        1)wd="13-16";;
        2)wd="18-21";;
        3)wd="23-26";;
        4)wd="28-31";;
        5)wd="33-36";;
        6)wd="38-41";;
        7)wd="43-46";;
esac

В зависимости от дня недели будем выбирать соответствующий блок в alarmnumbers.txt. Это параметры для cut.


cat $filename | while read line
do
 DialTime=$(echo $line | cut -c$wd)
 var0=`expr $var0 + 1`
 number=$(echo $line | cut -c1-11)
 dialwavfile=$(echo $line | cut -c48-200)

Читаем alarmnumbers.txt. построчно, выбирая нужные параметры из каждой строки.
DialTime — время звонка, тут используется параметр wd, который мы задали раньше.
number — номер, на который будет совершен звонок
dialwavfile — звуковой файл


 echo "Channel: SIP/providername/$number" > "$NewCallFilesPath$CallFileName$DialTime$var0.call"
 echo "CallerID: CompanyNumber" >> "$NewCallFilesPath$CallFileName$DialTime$var0.call"
 echo "MaxRetries: 2" >> "$NewCallFilesPath$CallFileName$DialTime$var0.call"
 echo "RetryTime: 450" >> "$NewCallFilesPath$CallFileName$DialTime$var0.call"
 echo "WaitTime: 20" >> "$NewCallFilesPath$CallFileName$DialTime$var0.call"
 echo "Application: Playback" >> "$NewCallFilesPath$CallFileName$DialTime$var0.call"
 echo "Data: $dialwavfile" >> "$NewCallFilesPath$CallFileName$DialTime$var0.call"
 echo "Archive: yes" >> "$NewCallFilesPath$CallFileName$DialTime$var0.call"

Создаем call-файл. Структура у него получится вот такая:


Channel: SIP/providername/89217884033
CallerID: CompanyNumber
MaxRetries: 2
RetryTime: 450
WaitTime: 20
Application: Playback
Data: /recs/macroform-robot_dity
Archive: yes

Channel — Через что звонить, указывается любой канал. У меня указан пир для внешних звонков. Если вы собираетесь звонить и на внутренние номера, то придется дописать условие, по которому будут подставляться различные каналы.
CallerID – Думаю, понятно. Не актуально, если это звонок на внешнюю линию и провайдер не позволяет менять CallerID
MaxRetries — Не поднял трубку? Не беда! Позвоним еще, вдруг не проснулся? Параметр сообщает сколько раз пытаться вызвать абонента
RetryTime — Через столько перезвонить, в секундах
WaitTime — Дозваниваться до абонента столько секунд.
Application — Это то приложение астериска которое будет использовано если абонент поднял трубку.
Data — Данные для приложения с предыдущей строки
Archive — Сохранять выполненные call-файлы, для анализа к примеру


 chmod 755 $NewCallFilesPath$CallFileName$DialTime$var0.call
 chown asterisk $NewCallFilesPath$CallFileName$DialTime$var0.call
 chgrp asterisk $NewCallFilesPath$CallFileName$DialTime$var0.call

Выдаем права на чтение, изменение и удаление пользователю, от которого запущен астериск.


 time=$(echo $line | cut -c$wd)
 case $time in
  XXXX) rm $NewCallFilesPath$CallFileName$DialTime$var0.call ;;
  "") rm $NewCallFilesPath$CallFileName$DialTime$var0.call ;;
  *) touch -t "$currentdate$time" "$NewCallFilesPath$CallFileName$DialTime$var0.call" ;;
 esac

Тут мы правим время изменения или удаляем call-файл в том случае если вместо времени указано XXXX.
Один из важных моментов в работе с call-файлами. Астериск будет читать только файлы с датой и временем изменения меньше или равной текущей. Таким образом, если мы укажем время модификации в будущем, астер будет ждать, пока не наступит нужное время.


 mv $NewCallFilesPath$CallFileName$varr$var0.call $AsteriskCallFilePath

Перемещаем наш созданный файл к астеру на съедение.

done

echo "HAPPY END!!!"

exit 0

Завершаем скрипт. С ним все.

Осталось только запихать его выполнение в крон. Не забудьте дать ему права на исполнение.


2       0          *       *       *       /usr/bin/my/alarm.sh

Ну, в общем-то, будильник готов. Заполняем alarmnumbers.txt и ждем звонка. У нас исправно работает уже 3 недели. Глюков пока не обнаружено.

Что в итоге?

Мы получили будильник с расписанием. Есть возможность исключать любые дни недели из расписания. Система будет создавать call-файлы, а астериск выполнять, когда наступит подходящее время. Ничего сложного.

Что плохо:

  • Запуск раз в сутки. Если захочется проснуться сегодня через 4 часа, астер ничего не сделает, звонок будет только через неделю.
  • Критично содержание alarmnumbers.txt. Если в нем будет косяк по неаккуратному заполнению, звонка не будет. Самому астеру ничего, конечно, не будет, но все равно неприятно.
  • Требуется заранее конвертировать звуковой файл в нужный формат. Автоконвертацию прикрутить поленился.
  • Коллега все равно не реагирует и на этот будильник.

Приветствуется критика, замечания, пожелания по улучшению.

Автор: EvilMause

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js