Sms с компутера

Nov 18, 2011 12:14

  Что-то в последнее время я совсем перестал пользоваться ЖЖ. Все как-то в Google+ сижу. Наверное, потому что пишу только мелкие сообщения, а ЖЖ как-то располагает к написанию больших обстоятельных постов. Да и мобильный клиент у Google+ мне нравится, в то время как у ЖЖ его почти нет.

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

  Есть (или уже все таки была) задача настроить sms-оповещения для одной конторы для системы мониторинга. Чтобы кроме электронных писем еще можно было получать sms на мобильный в случае возникновения проблем. Подумав понял, что в принципе есть 2 пути решения: использовать какой-нибудь сервис в интернете для рассылки sms, коих тьма (например, http://smsc.ru/tariffs/), или же завести свой девайс, который будет этим заниматься.
  Бесплатно sms через инет отсылать можно, с сайта конкретного оператора, но вот требуется для этого ввод капчи, поэтому автоматизация сильно затрудняется, а скорей становится не выгодной по трудо- и временным затратам. Да и не умею я этого и разбираться не хочется. Был еще вариант с мобильной почтой (хотя везде оно называется по-разному). Это когда оператор закрепляет за вашим номером почтовый ящик вида 7905xxxxxxx@beeline.ru и при поступлении на него письма шлет вам sms с содержимым этого письма. Но такой вариант плохо работает: для БиЛайн у меня все получилось, вот только sms я получал спустя 5-7 часов после поступления письма в ящик; МегаФон недавно прикрыл такую возможность, переделал и стал продавать за деньги; а о МТС вообще ничего не известно. В общем, оперативность никакая и не универсально.
  Возвращаясь к двум изначальным решениям: в случае с сервисом рассылки через интернет последний становится узким местом, т.к. если пропал инет, то sms мы не получим. Да и порывшись в интернете я не нашел чего-то мега дешевого. Везде выгодные ценники на sms начинаются в среднем при заказе, например, 2-4тыс sms или около того. А куда нам столько? Мы ж не спам sms'ить будем. В то время как у Tele2 есть тарифы по 20коп за sms. Второй вариант с собственным устройством хорош, вот только нужно найти это самое устройство. Сначала я думал прицепить к серверу какую-нибудь старую мобилу, Siemens или типа того. Но у себя таковых уже не застал. GSM модемы стоят не очень дешево, и ждать с ebay не мало. Так я и забросил на какое-то время этот вопрос, периодически спрашивая знакомых и сообщества о старых телефонах (правда тут есть еще одна проблема - data кабель. Старые телефоны продают, как правило, без оных, и, опять же, если покупать на ebay, то долго. А еще и не факт, что все получится и заработает).

Недавно меня осенило: есть же 3G модемы! Это же тоже самое, только функционал немного больше - можно по 3G в инет ходить =). Да и с unix'ами точно будет работать. Заглянув на avito.ru увидел, что средняя цена на такие устройства 400р. Круто! То, что надо. Моделей много всяких, в основном Huawei и ZTE. Еще немного порывшись нашел даже за 200р. МТСовский Huawei e1550.
  Его и купил. А еще Tele2'шную симку, и вставил ее в модем. Пришел домой. Первым делом разлочил, чтобы можно было пользоваться другими операторами, а не только МТС. Потом перевел в режим модем+cardreader (всего 3 режима, регулируется AT командами). До этого он был в режиме модем+cardreader+cdrom. Т.н. cdrom - это просто маленький чип flash-памяти в модеме, на который записан софт от МТС. Он мне больше не понадобится. А вот cardreader лишним не будет.
  Воткнул в комп с FreeBSD (ядро GENERIC), ввел
# cu -l /dev/cuaU0.0
AT
OK
И вздохнул с облегчением. Все вроде работает. Модем отвечает OK на мое AT. Кстати говоря, раньше не работал с модемами во фре, так что было сюрпризом, что кроме буквы A сначала ничего не можешь ввести. Была поначалу паника, что ничего не работает =)
  Затем поставил из портов comms/smstools3. Настроил (нашел маленький косяк, послал PR), и стал sms'ки слать себе из командной строки =). Круто, работает! Sms получаю =)
  Но на этом рано останавливаться. Захотел еще баланс проверять (USSD запрос). Вот тут стали открываться некоторые особенности устройства. Huawei e1550 имеет во FreeBSD несколько каналов: cuaU0.[0-2] и ttyU0.[0-2]. Как гласит интернет cua* - dial-out, tty* - dial-in. Ладно, посылаем модему через /dev/cuaU0.0 команду at+cusd=1,"*105#",15 . Ничего не выходит, говорит ERROR. Оказалось, что все Huawei понимают только PDU формат, так что вместо *105# нужно слать что-то другое. Порывшись в инете нашел конвертер. Хорошо, меняем команду на  at+cusd=1,"AA18AC3602",15 . Модем отвечает OK, но про баланс ничего не говорит. Хотя обычно, модемы не просто говорят OK, а еще и что-нибудь вроде +CUSD: 0," Ваш баланс: 7.03 RUB." OK . Ладно, опять порывшись в инете выясняется, что всю входящую информацию e1550'ый сыпет куда-то в другое место. Как оказалось после долгих поисков на /dev/ttyU0.2 (туда можно даже команды посылать вместо /dev/cuaU0.0) да еще и, опять же, в PDU формате. Например, CUSD: 0,"CF2135487D2E41B598EB5603C15D8A61B0294E16416E687DF96422C5C92268480D52B3437112D4023DA96E685028062D9FCD20929805A96234DC08C4020DA9CF7AF339A48A41B3A01BFA1C064133103C6F7301",1 . Эх, опять надо конвертить =(. Интернет подсказал мне скрипт на perl'е, предназначенный как раз для проверки баланса в huawei e1550, написанный изначально для linux, который сам все конвертирует. Истинный автор мне не известен, но растиражировали этот скрипт по разным местам уже хорошо. В комментах народ пишет, что во FreeBSD работать тоже будет, только comms/p5-Device-Gsm надо поставить. Ставим, проверяем, указывая для посыла команд cuaU0.0, а для приема ttyU0.2 - не работает. Смотрим truss ./balance.pl -v '*105#' - скрипт стопорится на открытии ttyU0.2:
...

open("/dev/cuaU0.0",O_RDWR,0666)                 = 3 (0x3)
ioctl(3,TIOCGETA,0xffffd5b0)                     = 0 (0x0)
lseek(3,0x0,SEEK_CUR)                            = 0 (0x0)
fstat(3,{ mode=crw-rw---- ,inode=121,size=0,blksize=4096 }) = 0 (0x0)
fcntl(3,F_SETFD,FD_CLOEXEC)                      = 0 (0x0)
write(3,"AT+CUSD=1,AA18AC3602,15\r\n",25)        = 25 (0x19)
close(3)                                         = 0 (0x0)
^Copen("/dev/ttyU0.2",O_RDONLY,0666)             ERR#4 'Interrupted system call'
SIGNAL 2 (SIGINT)
process exit, rval = 0
По нажатию Ctrl+C видим затык (3 строка снизу). Долго думать не стал, просто вбил строку в гугл, получил ответ: нужно изменить некоторые флаги для устройства терминала ttyU0.2. В моем случае правильно это нужно делать так: stty -f /dev/ttyU0.2.init raw clocal . Подробности в man 1 stty. Да, применить именно на ttyU0.2.init. После этого скрипт стал отрабатывать, но результат был пустым. Полез в сам скрипт, стал экспериментировать со строчкой, где делается перекодировка. В итоге так и не понял в чем дело. Полез в cpan'овский мануал по модулю Device::Gsm::Pdu. Нашел там другой вариант перекодировки. Но вот незадача, в портах этот модуль слишком старый, и нужного функционала там еще нет. Обновляю, отправляю PR(уже закоммитили). Завелось! 
Собственно слегка поправленный скрипт:

#!/usr/bin/perl
use Getopt::Std;
use Device::Gsm::Pdu;
# defaults
$opt_r = "/dev/ttyU0.2";
$opt_s = "/dev/cuaU0.0";
my $USAGE = <
Usage: $0 [-i input_port] [-o output_port] [-n] [-h] [-v] ussd_msg
Description:
  Send and receive 7-bit PDU-encoded USSD messages.
  Written and tested for Huawei E1550 GSM/UMTS USB modem.
Options:
  -r port   Port to receive data from. Default: $opt_r
  -s port   Port to send AT commands to. Default: $opt_s
  -n        Do not send any data to port. Useful with -v.
  -h        Print this help.
  -v        Be verbose.
__EOU
sub HELP_MESSAGE {print "$USAGE\n"; exit;}
sub VERSION_MESSAGE {};
getopts ('i:o:hnv');
HELP_MESSAGE() and exit if (! $ARGV[0]) or defined($opt_h);
#system("/bin/stty -f $opt_r.init raw clocal");
print "USSD MSG: $ARGV[0]\n" if $opt_v;
my $ussd_req = Device::Gsm::Pdu::encode_text7($ARGV[0]);
$ussd_req =~ s/^..//;
print "PDU ENCODED: $ussd_req\n" if $opt_v;

my $ussd_reply;
if (! $opt_n) {
    open (SENDPORT, '+<', $opt_s) or die "Can't open '$opt_s': $!\n";
    print SENDPORT 'AT+CUSD=1,',$ussd_req,",15\r\n";
    close SENDPORT;
    open (RCVPORT, $opt_r) or die "Can't open '$opt_r': $!\n";
    print "Waiting for USSD reply...\n" if $opt_v;
    while () {
        chomp;
        die "USSD ERROR\n" if $_ eq "+CUSD: 2";
        if (/^\+CUSD: 0,\"([A-F0-9]+)\"/) {
            $ussd_reply = $1;
            print "PDU USSD REPLY: $ussd_reply\n" if $opt_v;
            last;
        }
        print "Got unknown USSD message: $_\n" if /^\+CUSD:/ and $opt_v;
    }
}
if ($ussd_reply) {
    $decoded_ussd_reply = Device::Gsm::Pdu::pdu_to_latin1($ussd_reply);
    print STDOUT "USSD REPLY: $decoded_ussd_reply \n";
}
else {print "No USSD reply!\n";}

Закомментил строчку с system("/bin/stty... из-за того, что она мне не нравится, по идее это нужно делать из другого места, из cron'а, например.
  Теперь осталась еще проблема) Оператор возвращает в USSD не просто баланс, а еще и всякий спам, типа "Остаток 5р. Воруй, убивай!". Причем этот спам постоянно меняется. Да еще и в транслите. Так что с парсингом будет не просто =). А еще надо подумать над отправкой sms по сети с этого хоста. Можно, конечно, через ssh это делать, но, вероятно, есть и другие решения.
P.S. К вопросу о ttyU0.2. Всю самопроизвольно периодически сыпящуюся туда статистику можно выключить, и пользоваться только ttyU0.2 для отправки команд и получения ответов, т.е. пользоваться только ttyU0.2 вообще для всего. Подсказка найдена на очень хорошем сайте. Там же можно найти много чего интересного, в том числе и о проверке баланса на этом модеме. Но мне уже влом что-то менять, потому что надоело =).
UPD. Образовался глюк, точнее он никуда не девался, а просто был обнаружен: модем не был виден в системе после перезагрузки или выключения компа. Пришлось обновить ПО

e1550, freebsd, balance, huawei, smstools3, perl, оповещения, sms, notification, ussd

Previous post Next post
Up