Имя: Пароль:
1C
1С v8
Отправка СМС через USB-модем или сотовый телефон
,
0 Cube
 
21.10.13
10:32
Хотел подредактировать статью в КЗ http://kb.mista.ru/article.php?id=77 , но, оказалось, что туда могут писать только избранные, поэтому излагаю здесь.

Заголовок абзаца:

Отправка СМС через USB-модем или сотовый телефон (подключенный по USB и определившийся как COM-порт).

Текст:

Ну а теперь вашему вниманию предлагается готовый код для отправки СМС, длиной более 70 символов (можете и менее, я не против) в PDU формате:

Функция ОтправитьСМС(НомерТелефона, ТекстСообщения)
    
    COMПорт = "\\.\Com4";
    
    НомерТелефонаДляКодирования = СтрЗаменить(НомерТелефона, "+", "");
    Если СтрДлина(НомерТелефонаДляКодирования) = 10 ИЛИ СтрДлина(НомерТелефонаДляКодирования) = 11 Тогда
        НомерТелефонаДляКодирования = "7" + Прав(НомерТелефонаДляКодирования, 10) + "F";
    Иначе
        Возврат "Не верная длина номера телефона";
    КонецЕсли;
    НомерТелефонаСтр = "";
    Для НомерСимвола = 2 По 12 Цикл
        Если НомерСимвола % 2 = 0 Тогда
            НомерТелефонаСтр = НомерТелефонаСтр + Сред(НомерТелефонаДляКодирования, НомерСимвола, 1) + Сред(НомерТелефонаДляКодирования, НомерСимвола - 1, 1);
        КонецЕсли;
    КонецЦикла;
    
    МассивСообщений        = Новый Массив;
    ТекстСообщенияСтр    = "";
    ДлинаСообщения        = СтрДлина(ТекстСообщения);
    Для НомерСимвола = 1 По ДлинаСообщения Цикл
        Если НомерСимвола > 67 И НомерСимвола % 67 = 1 Тогда
            МассивСообщений.Добавить(ТекстСообщенияСтр);
            ТекстСообщенияСтр = "";
        КонецЕсли;
        КодСимволаСтр    = "";
        КодСимвола        = КодСимвола(Сред(ТекстСообщения, НомерСимвола, 1));
        Пока КодСимвола <> 0 Цикл
            Остаток = КодСимвола % 16;
            КодСимволаСтр = "" + ?(Остаток <= 9, Остаток, ?(Остаток = 10, "A", ?(Остаток = 11, "B", ?(Остаток = 12, "C", ?(Остаток = 13, "D", ?(Остаток = 14, "E", "F")))))) + КодСимволаСтр;
            КодСимвола = (КодСимвола - Остаток) / 16;
        КонецЦикла;
        Пока СтрДлина(КодСимволаСтр) < 4 Цикл
            КодСимволаСтр = "0" + КодСимволаСтр;
        КонецЦикла;
        ТекстСообщенияСтр = ТекстСообщенияСтр + КодСимволаСтр;
    КонецЦикла;
    МассивСообщений.Добавить(ТекстСообщенияСтр);
    
    ЧислоСМС = МассивСообщений.Количество();
    ГСЧ = Новый ГенераторСлучайныхЧисел;
    СлучайноеЧисло        = ГСЧ.СлучайноеЧисло(1, 255);
    УникальныйНомерСМС    = "";
    Пока СлучайноеЧисло <> 0 Цикл
        Остаток = СлучайноеЧисло % 16;
        УникальныйНомерСМС = "" + ?(Остаток <= 9, Остаток, ?(Остаток = 10, "A", ?(Остаток = 11, "B", ?(Остаток = 12, "C", ?(Остаток = 13, "D", ?(Остаток = 14, "E", "F")))))) + УникальныйНомерСМС;
        СлучайноеЧисло = (СлучайноеЧисло - Остаток) / 16;
    КонецЦикла;
    Пока СтрДлина(УникальныйНомерСМС) < 2 Цикл
        УникальныйНомерСМС = "0" + УникальныйНомерСМС;
    КонецЦикла;
    Для НомерСМС = 1 По ЧислоСМС Цикл
        //Вставим задержку, чтобы модем не захлебнулся. Если задержку не делать или сделать маленькой, то модем ничего не отправит (причина, как мне кажется, в том, что модем не успевает отправить предыдущую часть, а ему уже суют следующую). Такой вывод сделан чисто интуитивно, поэтому, возможно, я где-то не прав.
        Если НомерСМС > 1 Тогда
            ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
            Пока ТекущаяУниверсальнаяДатаВМиллисекундах() - ВремяНачала < 5000 Цикл КонецЦикла;
        КонецЕсли;
        Текст = "00"; //Длина и номер SMS центра. 0 - означает, что будет использоваться дефолтный номер. 07919731899699F0 = номер SMS центра МТС.
        Текст = Текст + "51"; //Тип PDU. 11 = у сообщения нет заголовка, 51 = у сообщения есть заголовок.
        Текст = Текст + "00"; //Поле предназначено для хранения количества переданных SMS. Не понятно, нафиг оно нужно.
        Текст = Текст + "0B"; //Длина номера получателя.
        Текст = Текст + "91"; //Тип-адреса. (91 указывает международный формат телефонного номера, 81 - местный формат).
        Текст = Текст + НомерТелефонаСтр; //Телефонный номер получателя в международном формате (закодированный).
        Текст = Текст + "00"; //Идентификатор протокола.
        Текст = Текст + "08"; //Старший полубайт означает сохранять SMS у получателя или нет (Flash SMS),  Младший полубайт - кодировка(0-латиница 8-кирилица).
        Текст = Текст + "0B"; //Срок доставки сообщения. 0B = 1 час, 17 = 2 часа, С1 = 1 неделя.
        ЗаголовокСообщения = "05"; //Длина заголовка сообщения.
        ЗаголовокСообщения = ЗаголовокСообщения + "00"; //Длина поля "Уникальный номер длинного сообщения". 00 = 8-ми битная кодировка (1 октет, 255 значений поля), 08 = 16-битная кодировка (2 октета, 65535 значений поля).
        ЗаголовокСообщения = ЗаголовокСообщения + "03"; //Длина заголовка сообщения, исключая первые два поля.
        ЗаголовокСообщения = ЗаголовокСообщения + УникальныйНомерСМС; //Уникальный номер длинного сообщения.
        ЗаголовокСообщения = ЗаголовокСообщения + Формат(ЧислоСМС, "ЧЦ=2; ЧН=; ЧВН="); //Общее число сегментов составного СМС.
        ЗаголовокСообщения = ЗаголовокСообщения + Формат(НомерСМС, "ЧЦ=2; ЧН=; ЧВН="); //Номер текущего сегмента составного СМС.
        ДлинаСообщенияСтр = "";
        ДлинаСообщенияДляКодирования = (СтрДлина(МассивСообщений[НомерСМС - 1]) + СтрДлина(ЗаголовокСообщения)) / 2; //Делим на 4 (т.к. уже закодировано) и умножаем на 2.
        Пока ДлинаСообщенияДляКодирования <> 0 Цикл
            Остаток = ДлинаСообщенияДляКодирования % 16;
            ДлинаСообщенияСтр = "" + ?(Остаток <= 9, Остаток, ?(Остаток = 10, "A", ?(Остаток = 11, "B", ?(Остаток = 12, "C", ?(Остаток = 13, "D", ?(Остаток = 14, "E", "F")))))) + ДлинаСообщенияСтр;
            ДлинаСообщенияДляКодирования = (ДлинаСообщенияДляКодирования - Остаток) / 16;
        КонецЦикла;
        Пока СтрДлина(ДлинаСообщенияСтр) < 2 Цикл
            ДлинаСообщенияСтр = "0" + ДлинаСообщенияСтр;
        КонецЦикла;
        ТекстСМС = Текст + ДлинаСообщенияСтр + ЗаголовокСообщения + МассивСообщений[НомерСМС - 1];
        //Отправка на модем
        ЗаписьТекста = Новый ЗаписьТекста(COMПорт, КодировкаТекста.ANSI);
        ЗаписьТекста.ЗаписатьСтроку("AT+CMGF=0");
        ЗаписьТекста.ЗаписатьСтроку("AT+CMGS=" + Окр((СтрДлина(ТекстСМС) - 2) / 2)); //Длина байтов сообщения (по 2 цифры), без учета длины и номера SMS центра.
        ЗаписьТекста.ЗаписатьСтроку(ТекстСМС + Символ(26));
        ЗаписьТекста.Закрыть();
    КонецЦикла;
    
КонецФункции //ОтправитьСМС()

Код для 1Cv8, но портировать на 1Cv77 не сложно. Код тестировался на модеме Huawei E303.

Подводные камни:
- На некоторых модемах нужно устанавливать кодировку сообщения принудительно ("AT+CSCS=""UCS2""").
- Другая модель (точно не помню какая) модема Huawei вообще зависала при установке типа PDU в значение 51 или 41. Поэтому на ней отправлять можно было только одиночные СМС.
- На некоторых модемах не получалось писать все AT-команды в одной ЗаписьТекста. Приходилось каждую AT-команду писать в отдельной ЗаписьТекста и вместо метода ЗаписатьСтроку() пользоваться методом Записать().
- Если паузу между частями длинной СМС не делать или сделать маленькой, то на телефон вообще ничего не приходит.
1 Cube
 
21.10.13
10:38
Сам бился над СМС-ками около месяца (оказалось, модем корявый - купил другой и заработало), поэтому решил выложить код, чтобы другим было проще.

Используемая литература:
http://mobiletidings.com/2009/02/18/combining-sms-messages/
http://en.wikipedia.org/wiki/Concatenated_SMS
http://huh-muh.blogspot.ru/2010/07/sms_31.html
http://www.twit88.com/home/utility/sms-pdu-encode-decode
http://ganatol2000.narod.ru/otap.htm
http://www.sql.ru/forum/822234/pdu-i-dlinnye-sms
http://www.gsm-modem.de/sms-pdu-mode.html
http://www.sql.ru/forum/855618/biblioteka-gsm-library-shhob-snyat-voprosy-po-priemu-otpravke-sms-cherez-modemy-gsm
http://habrahabr.ru/post/133085/
http://www.sql.ru/forum/660795-2/otpravka-sms-cherez-grps-modem
http://kb.mista.ru/article.php?id=77

Так же был ещё мануал в PDF в инете. Найду ссылку - докину.
2 Cube
 
21.10.13
10:45
3 Cube
 
21.10.13
13:30
Ну так что, в статью кто-нить добавит или как?
4 Nexux
 
21.10.13
13:57
круто, обязательно заюзаю секнс
5 oleg_km
 
21.10.13
15:31
Читать ответы модема наверное тоже надо
6 Sereja
 
21.10.13
15:32
Гений 1с рассылку давно выкладывал. Нормуль было сделано
7 Sereja
 
21.10.13
15:33
+(6) У него все в готовенькой обработочке выложено
8 Cube
 
22.10.13
04:52
(5) Вообще - желательно, но тогда лучше внешнюю компоненту делать, а мне лень :)
Но не обязательно.
9 Cube
 
22.10.13
04:53
(6) Я много и упорно искал. Не нашел. На мисте нашел только в КЗ, остальное на мисте шлак... Если есть ссылка - буду благодарен.
10 Bumer
 
22.10.13
08:37
11 oleg_km
 
22.10.13
09:42
(8) Я имел ввиду, порт правильно на невычитку ответов реагирует? Может будет виснуть и неустойчиво работать?
12 Cube
 
24.10.13
05:38
(10) Спасибо за ссылку. Программы для отправки я как-то даже не рассматривал, поэтому, видимо, и не нашел этой ссылки.
13 Cube
 
24.10.13
05:42
(11) ХЗ, посмотрим. Этот код в бою недавно. Из косяков, пока, только замечено, что 5 сек на таймаут не всегда хватает. Мы у себя поставили 10 сек, пока что.
14 Cube
 
24.10.13
05:45
Всё-таки над чтением ответа надо подумать, ведь это позволит убрать таймауты и код сам будет определять, когда можно слать следующую часть СМС на модем...
15 IamAlexy
 
24.10.13
06:56
(0) а почему не через смс порталы ?
16 oleg_km
 
24.10.13
09:24
(15) Ну у нас например всего лишь прием СМС с банк-клиента и отправка при отключении питания, т.е. штук 100 в мес вход и 8 штук выход. И ради этого заключать договор с смс порталом?
17 Cube
 
25.10.13
04:37
(15) Нам так удобнее. К тому же, такой СМС-центр можно поднять прямо у себя дома (даже взяв свою старую нокию) и добавить функциональности своему "умному дому" :)
На мисту вывалил не с целью кого-то переубеждать делать только так, а с целью пополнения инфы о работе с модемами. В инете инфы не много, а миста на хорошем счету у поисковиков. Ну куда, если не на мисту? :)
18 monsterZE
 
08.11.13
14:17
спасибо тс за статью! =)
Оптимист верит, что мы живем в лучшем из миров. Пессимист боится, что так оно и есть.