Сижу я на работе утром. Коллега опаздывает, делать особо нечего. Скучно. Наконец приходит опоздавший и жалуется, что не проснулся по своему будильнику. То ли не завел, то ли не услышал, этого я уже не помню. Почему бы не устроить ему звонок с работы, с утра пораньше?
Сказано — сделано. Решил я написать будильник.
Как будем реализовывать?
Диалплан решил не трогать, ибо он и так уже не самый маленький, и усложнять его не хочется. Поэтому было решено написать 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