Вариация на тему: прогноз погоды по телефону

в 14:03, , рубрики: asterisk, bash, прогноз погоды, метки: , ,

Решил поделиться ещё одним способом организации сервиса прогноза погоды по телефону. Здесь, по сравнению с этим постом, больше интеллекта перенесено в Asterisk.
Weather

XML с погодой

XML с текущей погодой и прогнозом на два следующих дня беру с BBC.

Так как от Cron'а нам не избавиться, то добавляем:
0 2 * * * /home/alexandr/xml/weather/almaty/bbcweather.sh
0 14 * * * /home/alexandr/xml/weather/almaty/bbcweather.sh
30 16 * * * /home/alexandr/xml/weather/almaty/bbcweather.sh

Опытным путем было установлено, что XML обновляется три раза в сутки (по крайней мере для города Алматы).

Скрипт не только скачивает, но также обрабатывает XML-ку и раскладывает необходимые значения по файликам. Правда мой скрипт очень примитивный и скорее всего многих введёт в уныние своей неэффективностью, поэтому не буду заострять на нём внимание.

Текстовые файлы

Имена файлов для одного и того же параметра (например, минимальная температура) для разных дней будут отличаться цифрой-префиксом: 1 – сегодня, 2 и 3 – завтра и послезавтра соответственно. Например, минимальная температура для сегодняшнего дня (первый блок данных в XML) будет храниться в файле с именем «1Tmin», для завтрашнего (второй блок данных) – «2Tmin».

Теперь по содержимому файлов (которые, кстати, не должны содержать символа конца строки):

  • День недели (Wday) содержит «day-0» для воскресенья,… «day-6» для субботы;
  • Направление ветра (Wdir) содержит «N» для «северный»,… «NW» для «северо-западный»;
  • Числовые значения (влажность, температура, скорость ветра) записываются числом;
  • Текстовые – текстом :-) (облачность, видимость).

Для тестирования (а также для написания скрипта) пользовался параметром "-n" команды «echo» для того, чтобы не записывать в файл символ конца строки:
echo -n "day-5" > 1Wday

Итак, имеем список файликов с погодными данными. Теперь переходим к конфигурации extensions.conf.

extensions.conf

[weather]  exten => 071,1,Set(wpath="/home/your-directory/")  exten => 071,n,Goto(say-weather,s,1)    [say-weather]  exten => s,1,Answer()  exten => s,n,Set(E=1)  exten => s,n(play),Playback(digits/${SHELL(cat ${wpath}${E}Wday)})  exten => s,n,Playback(custom/temperatura)  exten => s,n,SayNumber(${SHELL(cat ${wpath}${E}Tmin)})  exten => s,n,SayNumber(${SHELL(cat ${wpath}${E}Tmax)})  exten => s,n,Playback(custom/wind)  exten => s,n,Playback(custom/wind/${SHELL(cat ${wpath}${E}Wdir)})  exten => s,n,SayNumber(${SHELL(cat ${wpath}${E}Wspd)})  exten => s,n,Playback(custom/metrov-v-sekundu)  exten => s,n,Playback(custom/vlazhnost)  exten => s,n,SayNumber(${SHELL(cat ${wpath}${E}Humd)})  exten => s,n,Playback(custom/procentov)    exten => s,n,WaitExten()  exten => s,n,Hangup()  exten => _[1-3],1,Set(E=${EXTEN})  exten => _[1-3],n,Goto(say-weather,s,play)  
Разбор полётов

Публикуем extension, по которому будем дозваниваться до погоды и, заодно, выставляем переменную «wpath», где указываем каталог ранее созданных файликов:

exten => 071,1,Set(wpath="/home/your-directory/")

Переходим в контекст say-weather:

exten => 071,n,Goto(say-weather,s,1)  

После инициализации значения «E» (по умолчанию выставляем сегодняшний день), воспроизводим название дня недели:

exten => s,n,Set(E=1)  exten => s,n(play),Playback(digits/${SHELL(cat ${wpath}${E}Wday)})  

Команду Playback можно и не представлять, а вот дальше на всякий случай расскажу. Если указывается относительный путь, то по умолчанию (во всяком случаем на моём debian) подставляется "/usr/share/asterisk/sounds/en/" (или «ru/», если в sip.conf указан параметр «language=ru»). Значения «wpath» и «E» мы уже определили, поэтому получается следующее:

Playback(/usr/share/asterisk/sounds/ru/digits/${SHELL(cat /home/your-directory/1Wday)})

Результатом выполнения «cat /home/your-directory/1Wday» пусть будет, например, строка «day-0» (допустим, что сегодня – воскресенье), тогда:

Playback(/usr/share/asterisk/sounds/ru/digits/day-0)

Т.е. воспроизводится файл, содержащий название нужного нам дня недели, т.к. файл digits/day-0 как раз и содержит звуковую запись «Воскресенье».

По такому же принципу отрабатывает и эта строчка:

SayNumber(${SHELL(cat ${wpath}${E}Tmin)})  

Проговаривается минимальная температура сегодняшнего дня, значение которой берётся из файла "/home/your-directory/1Tmin".

Увы, пришлось записывать часть сообщений самостоятельно, их я поместил в каталог «custom».

exten => s,n,Playback(custom/temperatura)

После окончания всех Playback и SayNumber, ждем ввода дополнительных цифр:

exten => s,n,WaitExten()  

Дополнительные цифры включают в себя 1, 2 и 3, что видно по паттерну _[1-3]:

exten => _[1-3],1,Set(E=${EXTEN})  exten => _[1-3],n,Goto(say-weather,s,play)  

При нажатии на любую из них, первая строчка присваивает введённое значение переменной «E», а вторая строчка осуществляет переход к метке «play» (третья строка этого контекста). Таким образом Asterisk снова сообщит звонящему погоду, но уже на завтра (если была введена цифра 2) или послезавтра (3).

Ничто не мешает нам написать ещё один extension рядом с 071 и воспользоваться тем же самым контекстом say-weather для воспроизведения погоды для другого города:

[weather]  exten => 071,1,Set(wpath="/home/user/weather/city1/files")  exten => 071,n,Goto(say-weather,s,1)  exten => 072,1,Set(wpath="/home/user/weather/city2/files")  exten => 072,n,Goto(say-weather,s,1)  

Откуда качал архив с русскими сообщениями уже не вспомню, но он должен легко нагуглиться.
Подробные описания функций Asterisk на www.voip-info.org/.

Бонус

В качестве бонуса выкладываю часть extensions.conf, с помощью которой я записывал свои звуковые сообщения:

[test-context]  exten => 051,1,Goto(rec-file,s,1)  [rec-file]  exten => s,1,Verbose(1,Recording application)  exten => s,n,Answer()  exten => s,n,Playback(record-enter-num)  exten => s,n(filename),Read(filename)  exten => s,n(rec-mes),Record(/tmp/recs/${filename}:gsm)  exten => s,n,Playback(beep)  exten => s,n,Wait(1)  exten => s,n(rec-play),Playback(/tmp/recs/${filename})  exten => s,n(rec-review),Background(vm-review)  exten => s,n,WaitExten(10)  exten => s,n(rec-del),System(rm /tmp/recs/${filename}.gsm)  exten => s,n,Playback(vm-deleted)  exten => s,n(read-hang),Read(rep,,1,,,2);Wait for 1 digit for 2 seconds to receive 1 which means that another file is to be recorded  exten => s,n,Gotoif($["${rep}" = "1"]?filename)  exten => s,n,Hangup()    exten => 1,1,Playback(vm-msgsaved)  exten => 1,n,SayDigits(${filename})  exten => 1,n,Goto(rec-file,s,read-hang)    exten => 2,1,Goto(rec-file,s,rec-play)    exten => 3,1,Wait(1)  exten => 3,n,Goto(rec-file,s,rec-mes)    exten => i,1,Goto(rec-file,s,rec-review)  exten => t,1,Goto(rec-file,s,rec-del)  exten => 0,1,Goto(rec-file,s,rec-del)  

Готовим табличку со списком имен файлов (в виде цифр) и текстом, который нужно будет проговорить, звоним с более-менее хорошего телефона/гарнитуры на 051, «прогоняем» каждую строчку своей таблички и в конце забираем готовые файлики из /tmp/recs/ (не забывая менять их названия на что-то более понятное).

И подсказка для того, чтобы легче было пользоваться:

Recording Menu

UPD: Ссылка на bbcweather.sh: pastebin.com/DJYy6XRM и sed.bbc pastebin.com/Xm4EeDst. Если кто будет делать с помощью нормального XML-парсера – не забудьте поделиться кодом :-).

Автор: aleksashka

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


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