Данная статья посвящена организации СМС оповещения в очень бюджетном исполнении.
Такой метод подходит для домашнего использования или использования в SOHO. На что-то большее данная схема не способна, имейте это ввиду.
Ранее на Хабре уже были статьи на тему СМС информирования, но все сводилось к локальным USB-модемам или сервисам email2sms.
В этой статье будет рассмотрена иная схема взаимодействия. А именно: оборудование Mikrotik выступит в роли GSM шлюза, а Zabbix будет отправлять СМС через терминал.

Что понадобится:
1) Mikrotik 951 серии (активный USB-хаб крайне рекомендуется)
2) USB-модем с сим-картой
3) и развернутый Zabbix-сервер.

А работает это все согласно RFC2217.

Вся конфигурация разбита на 3 этапа:
A) Настройка Mikrotik
B) Работа со скриптом отправки
C) Настройка Zabbix

Наcтройка Mikrotik


К Mikrotik'у подключен USB-модем, произведены базовая настройка и проверка работоспособности модема.
Сразу выясните каналы для отправки СМС. В моем случае это было сделано экспериментально, каналы 1 и 2 отвечают за эту функцию.

В документации к ROS была найдена функция проброса COM-порта по TCP (RFC2217). Она позволяет обращаться к оборудованию за роутером через обычный терминал.
Настройка в Winbox
System -> Ports -> Remote Access


Все параметры интуитивно понятны. Каналы данных SMS Settings и Remote Port совпадать не должны!
Со стороны сетевого оборудования на этом настройка окончена.

Скрипт отправки СМС


В качестве гостевой системы ВМ в моем случае выступает Ubuntu 14.04.2. Так исторически сложилось, с этим приходится жить.
Вы же можете использовать как «железный» Zabbix, так и виртуальный.

Путем чтения тонны инструкций был написан скрипт отправки СМС на Bash сначала в текстовом формате, а следом и в формате PDU. PDU-формат позволяет отправлять СМС в Юникоде, т.е. латинские и кириллические символы (в данном случае только они нас интересуют).
Окончательный вариант скрипта, прилагаемый здесь, позволяет отправлять «многостраничные» СМС любого содержания, т.е. более 70 символов.
Для тех, кто хочет проникнуться, я оставлю несколько ссылок: тык и тык
Скрипт на Bash'е
Для работы скрипта требуется утилита Recode.
В случае, если вы хотите проверить работу скрипта из терминала, уберите "-e" у «echo».

#!/bin/bash
#Переменные
tel=$1
header=$2
mes=$3
ip=XXX.XXX.XXX.XXX                                          #IP шлюза
port=Y                                                 #Порт шлюза

#Служебные переменные !!! НЕ ТРОГАТЬ !!!
TP_MR0=0                                                #Начальный параметр TP-MR
IED31=1                                                 #Начальный параметр IED3 для блока UDH

#Начинается...
###########################################################################################################################################
#Переменные для обоих блоков

#Вычисление длины сообщения для определения использовать ли UDH
UDH=`echo $mes | recode ..U2/x2`                        #Преобразование тела сообщения в UCS2
UDH=`echo $UDH | sed 's/0x\|,\| //g' | sed 's/000A$//g'`
TP_UD=$UDH                                              #TP-UD - кодированное сообщение
UDH=`echo -n $UDH | wc -c | gawk '{print $1}'`
UDH=$(($UDH/4))                                         #Подсчет символов в сообщении - определяет какой типа отправки использовать

#Кодировка номера в нужный формат
tel="$tel"F""
i=`echo -n $tel | wc -c | gawk '{print $1}'`
i=$(($i/2))

while [ "$i" != "0" ]
do
R=`echo $tel | cut --complement -b '3-12' | rev`
TPTEL="$TPTEL$R"
tel=`echo $tel | cut --complement -b '1-2'`
i=$(($i-1))
done

###########################################################################################################################################
#Если символов 70 и менее!
if [ "$UDH" -le "70" ]; then

#Кодировка сообщения и длины сообщения в UCS2
TP_UDL=`echo -n $TP_UD | wc -c | gawk '{print $1}'`     #Вычисление длины сообщения в шестнадцатеричный формат вида XX
TP_UDL=$((($TP_UDL+1)/2))
TP_UDL=`printf '%02x' $TP_UDL | sed 's/[[:lower:]]/\u&/g'`      #Тут еще в верхний регистр загоняем для красоты


#Собираем строку для >
TPDU=""0011000B91"$TPTEL"0008AA"$TP_UDL$TP_UD"          #Собираем всю строку для >

#Подсчет байтов для AT+CMGS=
Byte=`echo -n $TPDU | cut --complement -b '1-2'`        #Убираем первые 2 символов, они не участвуют в подсчете
Byte=`echo -n $Byte | wc -c | gawk '{print $1}'`
Byte=$((($Byte)/2))

#Сама процедура отправки на шлюз. Вроде как поддерживается и RFC2217, и RAW
(
sleep 2
echo  "AT+CMGF=0"                                       #1 - Текстовый режим, 0 - PDU режим чтоб он сгорел!!!
sleep 1
echo "AT+CSCS=\"UCS2\""                                 #Кодировка
sleep 1
echo "AT+CMGS=$Byte"                                    #Передача байта в десятичном виде
sleep 1
echo -e "$TPDU\\032"                                       #Передача закодированной строки + Ctrl+Z
sleep 3                                                 #Спим долго, отчет идет долго
echo -e "\\033"                                            #ESC на всякий случай, чтоб модем не завис в случае ошибки
sleep 3
) | telnet $ip $port                                    #Telnet на шлюз, параметры в самом верху
exit 0

##################################################################################################################################
#Если символов более 70!
else

#Тут временные переменные, нужны для цилка
UDH=$((($UDH/67)+1))                                    #Превращаем UDH в количество циклов (на 1 больше, чем полных СМС по 67 символов)
IED2=$UDH                                               #Посчитаем количество частей СМСок - параметр для UDH
IED2=`printf '%02x' $IED2 | sed 's/[[:lower:]]/\u&/g'`

#Сама процедура отправки на шлюз. Вроде как поддерживается и RFC2217, и RAW
(
sleep 2
echo  "AT+CMGF=0"                                       #1 - Текстовый режим, 0 - PDU режим чтоб он сгорел!!!
sleep 1
echo "AT+CSCS=\"UCS2\""                                 #Кодировка
sleep 1

#Цикл отправки сообщений AT+CMGS=
while [ $UDH -ne 0 ];
do

#Кодировка сообщения и длины сообщения в UCS2
TPUD=`echo -n $TP_UD | cut --complement -b '269-100000000'`     #Отрезаем первые 67 символов для кодирования одного СМС
TP_UD=`echo -n $TP_UD | cut --complement -b '1-268'`    #Оставшееся сообщение без 67 символов, будет отрезано в следующем цикле

TP_MR=`printf '%02x' $TP_MR0 | sed 's/[[:lower:]]/\u&/g'`       #Преобразуем TP-MR (00, 01 и т.д.)
IED3=`printf '%02x' $IED31 | sed 's/[[:lower:]]/\u&/g'` #Текущая часть СМС - параметр для UDH

UDH_TP_UD=""050003FF"$IED2$IED3$TPUD"                   #Собираем строку для подсчета длины TP-UDL

TP_UDL=`echo -n $UDH_TP_UD | wc -c | gawk '{print $1}'` #Вычисление длины в шестнадцатеричный формат вида XX
TP_UDL=$(($TP_UDL/2))
TP_UDL=`printf '%02x' $TP_UDL | sed 's/[[:lower:]]/\u&/g'`      #Тут еще в верхний регистр загоняем для красоты

TPDU=""0041"$TP_MR"0B91"$TPTEL"0008"$TP_UDL$UDH_TP_UD"  #Собираем всю строку для >
TP_MR0=$(($TP_MR0+1))                                   #Увеличивает $TP-MR0 на 1 для следующего СМС
IED31=$(($IED31+1))                                     #Увеличиваем номер следующего СМС для UDH
UDH=$(($UDH-1))                                         #Уменьшаем номер для следующего цикл на один

#Подсчет байтов для AT+CMGS=
Byte=`echo -n $TPDU | cut --complement -b '1-2'`        #Убираем первые 2 символов, они не участвуют в подсчете
Byte=`echo -n $Byte | wc -c | gawk '{print $1}'`
Byte=$((($Byte)/2))

#Сама отправке нескольких сообщений на шлюз
echo "AT+CMGS=$Byte"                                    #Передача байта в десятичном виде
sleep 1
echo -e "$TPDU\\032"                                       #Передача закодированной строки + Ctrl+Z
sleep 3                                                 #Спим долго, отчет идет долго
echo -e "\\033"                                            #ESC на всякий случай, чтоб модем не завис в случае ошибки
sleep 3
done
) | telnet $ip $port                                    #Telnet на шлюз, параметры в самом верху

fi
exit 0
#В случае, если вы хотите проверить работу скрипта из терминала, уберите "-e" у "echo"


Вам в скрипте необходимо изменить две переменные на ваши — IP и Port.
В скрипт передаются 3 переменные по порядку: номер телефона, заголовок (не используется, просто Zabbix именно в такой последовательности передает данные в скрипт) и само сообщение. Дополнительно переменные экранировать не нужно, Zabbix это делает сам.
По умолчанию скрипт должен лежать в:
для версии 2.2 — /usr/local/share/zabbix/alertscripts
для версии 2.4 — /usr/lib/zabbix/alertscripts.
Не забывайте дать соответствующие права на файл скрипта!

Настройка Zabbix


На стороне Zabbix'а процедура настройки тривиальна, но я опишу ее еще раз для закрепления.
1) Указываете Способ оповещения
2) Указываете необходимый телефон в профиль пользователя
Телефон вводится в формате 11-значном формате, т.е. 7**********
3) Настраиваете действия на сработавший триггер
Картинки для закрепления






Не забывайте, что поле действия «Тема по умолчанию» не учитывается в скрипте, поэтому все необходимое выносите в «Сообщение по умолчанию». Я использую для этого следующую конструкцию: {TRIGGER.NAME} {TRIGGER.DESCRIPTION} {ITEM.NAME} — {ITEM.LASTVALUE}. Она более чем информативна.

Послесловие


Как я и предупреждал в начале статьи, все очень примитивно и для «продакшена» не годится. Но метод позволяет за совсем скромные деньги получать чуть больше оперативной информации от вашей системы мониторинга. За сим разрешите откланяться.

Комментарии (38)


  1. Lelik13a
    19.08.2015 06:26

    Только слабое место в такой конфигурации — если microtick умрёт, или канал до него отвалится, то zabbix никому и ничего не расскажет.
    Потому, надёжнее всё-таки слать непосредственно с сервера.
    Но и этот вариант интересен для общего развития, спасибо.


    1. AcidVenom
      19.08.2015 08:23

      Слабых мест у такой конфигурации куча: от проблем с локальной сетью до занятости модема самим микротиком (мне симулировать пока не удалось).
      Но, как я писал в самом начале, этот метод подходит мелким предприятиям особенно в наше время. Мелкий бизнес и так пытается любыми средствами сэкономить, не забывая конечно о хоть каком-то мониторинге и какой-то автоматизации.


  1. tjomamokrenko
    20.08.2015 00:11
    +1

    Что автор думает о gammu? А о Kannel?


    1. AcidVenom
      20.08.2015 08:32

      Думает, что это отличные инструменты. Насколько мне известно, они не умеют работать по RFC2217, но все решается использованием ttyd.
      Такую связку я не тестировал.


      1. AcidVenom
        20.08.2015 10:15

        А нет ttyd для 14.04!
        Если кто-нибудь знает утилиту аналогичную ttyd, буду очень признателен.


  1. Roy
    20.08.2015 00:12
    -1

    А чего бы просто sms сервис не использовать? Тот же sms.ru. И проще и дешевле.


    1. kotomyava
      20.08.2015 01:58
      +1

      Вероятность недоступности внешнего сервиса всё же куда выше, чем даже такой конфигурации.
      Но ещё лучше подключить модем к серверу с заббиксом…


    1. AcidVenom
      20.08.2015 07:43

      Я не использовал этот сервис, как у него с оперативностью? В моем случае СМС доходит в несколько секунд после отправки.
      Ну и конечно же момент с отвалом канала связи. В случае со свистком, сам свисток можно научить поднимать свое подключение.


      1. Obramko
        20.08.2015 08:43
        +1

        Можно действительно поднять через свисток отдельный канал только для отправки SMS.
        Приходят обычно за те же несколько секунд.


        1. AcidVenom
          20.08.2015 08:54

          Можно, но это уже какое-то… нагромождение что ли.


          1. Obramko
            20.08.2015 14:37

            По-моему, лучше, чем AT-команды из bash-скрипта. ;)


    1. mihmig
      20.08.2015 11:34

      Угу, пользовались. но:
      1. Внезапно сообщения перестали приходить на часть операторов (хотя деньги исправно списывались )
      2. Техподдержка стала не адекватной — на сайте не отвечают, а звонить на московский номер с 10 до 17 МСК как-то не очень удобно
      3. ОПСОСЫ спохватились и ну давай повышать тарифы на такую отправку (по ценам 2000-х)

      Пока перешли на другого «провайдера», но вообще перейдём на отправку через модем/android-смартфон.


    1. DarkByte
      20.08.2015 12:06

      Причём на столько дешевле, что аж бесплатно. Если конечно отправлять уведомления только себе. Хотя можно хранить табличку сопоставления номера телефона получателя и его api-key с сайта.

      Но почему не воткнуть модем в сам сервере и не подключить модем локально? Если сервер находится удалённо, то при потери канала связи он и до модема по сети не достучится. В таком случае для мониторинга доступности сервера мониторинга можно воспользоваться услугами стороннего сервиса мониторинга доступности.


      1. AcidVenom
        20.08.2015 12:23

        Если вопрос адресован мне, то метод статьи рассчитан на совместное использование модема или Заббикс, размещенной в ВМ.


  1. Xeenon
    20.08.2015 07:10

    Микротик же сам умеет смс отсылать, а кроме того у него есть API.
    Может попробовать через API микротика рассылать?


    1. AcidVenom
      20.08.2015 07:38

      Проблем у микротика 2: только текстовый режим отправки СМС, а значит о кириллице можно забыть, и ограничение в 1 СМС (160 латинских символов). У скрипта таких ограничений нет.


    1. mihmig
      20.08.2015 11:34

      Не подскажете, какой именно модуль для этого нужен?


  1. mihmig
    20.08.2015 11:37

    Хм, а пробросить можно вообще любой USB-COM конвертер? было бы неплохо «подцепить» что-то типа такого:
    (4 реле 5/220 плюс входные/выходные линии TTL)
    image
    kernelchip.ru/Ke-USB24R.php
    и перезагружать оборудование в серверной.
    (Сам-то микротик вряд-ли создаст модель с одним-двумя 220В реле)


    1. AcidVenom
      20.08.2015 11:46

      По идее, если микротик увидит оборудование, то и его можно пробросить.
      И так же по идее с этим оборудованием можно будет работать через скрипты самого микротика (в вашем случае перезагрузка по СМС и т.д.)
      Нужно пробовать, только такой ответ я могу дать.


      1. mihmig
        20.08.2015 11:59

        Я понимаю, надо пробовать втыкать оборудование. Жаль, что если какой-то чип-конвертер не заработает, то с этим ничего не сделать — свои модули к закрытой RouterOS ведь не написать?

        А как принять СМС-на микротике? Вычитывать из порта входящие СМС? Но ведь ка каждого Huawei/Zte и проч. свой формат?


        1. AcidVenom
          20.08.2015 12:03

          Так глубоко я в дебри ROS не лез, скорее всего там ловить нечего.

          А по поводу приему СМС — вот информация на их wiki. Прием придется включать после каждой перезагрузки микротика, но это легко решается скриптом на старте.


  1. ihormanchik
    25.08.2015 07:32

    или учим Zabbix новым трюкам

    вы серьезно? такой подход на моей памяти уже используется не меньше 10 лет, не новый он совсем
    но за реализацию на баше, конечно, спасибо
    по скрипту
    это
    UDH=`echo $UDH | sed 's/0x//g' | sed 's/,//g' | sed 's/ //g' | sed 's/000A$//g'`
    

    можно заменить на
    UDH=`echo $UDH | sed 's/0x\|,\| //g' `
    


    1. AcidVenom
      25.08.2015 09:04

      Да, заголовок не ахти, признаю.
      В сети я встречал только схему с GSM-шлюзом, работало это все так же через терминал. Но реализовано было на PHP и быстро под мои нужды заточить не удалось. Только вот не помню, был ли там PDU с UDH или нет.

      Сейчас проверить не могу, но вполне возможно, что там хватит

      sed 's/, 0x//g'

      Перепроверю и отпишусь ниже.


      1. ihormanchik
        25.08.2015 19:21

        в любом случае спасибо за интересную статью )


        1. AcidVenom
          25.08.2015 22:19

          Внес в скрипт вашу поправку, большое спасибо за комментарий!


  1. denser
    26.08.2015 15:01

    Спасибо за скрипт — моя реализация через API работает, но кирилица — это неплохо!
    Но не подскажете, почему скрипт не отрабатывает?

    root@zabbix:~/alertscripts# ./sms_all 7********** "" "123"
    ./sms_all: line 18: recode: command not found
    Trying 192.168.*.*...
    Connected to 192.168.*.*.
    Escape character is '^]'.
    AT+CMGF=0
    OK
    AT+CSCS="UCS2"
    OK
    AT+CMGS=14
    > 0011000B919732155403F30008AA00
    +CMGS: 103
    
    OK
    onnection closed by foreign host.
    

    Настройки поправлены на свой адрес и порт, что видно из лога, но обрывается. На микротике тихо, или нет?
    echo: sertcp,info connection to serial remote-access 0.0.0.0:24 from 192.168.*.*:38899
    echo: sertcp,debug end of file reading TCP port 24
    


    НОВОЕ: может от того что тестирую в терминале, не убрав -е?


    1. AcidVenom
      26.08.2015 15:10

      У вас все отрабатывается на ура, +CMGS показывает номер текущего удачно отправленного сообщения.
      А вот Recode вы не поставили. Ну и "-e" нужно убрать, иначе это "-е" полезет в строку >.


      1. denser
        26.08.2015 19:17

        Хм, может я не достаточно внимательно прочел статью, но о каком Recode речь?
        И может оно и отрабатывает на ура :) но смс мне не пришли, хотя через API прекрасно ходят, ровно как и через winbox если отправить.

        НОВОЕ: и ведь невнимательно! Спасибо, что тыкнули носом — незаметная строка оказалась, Ctrl+F рулит )


        1. AcidVenom
          26.08.2015 19:35

          Выделил жирным для «внимательных» :)


          1. denser
            27.08.2015 07:01

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


            1. AcidVenom
              27.08.2015 08:29

              Поясните. Пытаетесь из винды сделать?


              1. denser
                27.08.2015 11:39

                Нет, в терминале убунты, тестирую с русскими символами — всё ОК, интересно как перенести строку в сообщении

                ./sms_all 7******** "" "пошли<?>домой"
                

                Каой символ вводить, чтобы сработал перенос каретки?


                1. tjomamokrenko
                  27.08.2015 11:51

                  Попробуйте

                  echo -e "пошли\r\nдомой" | xargs ./sms_all 7******** ""


                  1. denser
                    27.08.2015 12:34

                    Пришло только слово «пошли». Я читал, что для смс есть спец-символ для переноса, здесь.
                    Это веб-символ, аналог, по-моему, 0x0A, прочитано тут.
                    Может это как-то в скрипте обрабатывать?


                    1. AcidVenom
                      27.08.2015 13:44

                      Это делается так:

                      "bla-bla"\\n"bla-bla"
                      


                      Из Заббикса отправку сейчас проверю.


                      1. denser
                        27.08.2015 13:48

                        Не подходит. Через командную строку приходит

                        ./sms_all 7********** "" "пошли\\nдомой"
                        
                        пошли\nдомой
                        


                        echo -e "пошли"\\n"домой" | xargs ./sms_all 7******** ""
                        
                        пошли
                        


                        1. AcidVenom
                          27.08.2015 14:03

                          Ладно, напишу полностью

                          ./sms_all 7********** "" "пошли"\\n"домой"
                          

                          Из Заббикса такая конструкция не работает. Но оно там и не надо :)


                          1. denser
                            27.08.2015 16:27

                            Обратно не работает

                            пошли\nдомой