Оперативное информирование клиентов, когда их достаточно много для ручного обзвона, но недостаточно много для подключения массового сервиса, вроде sms.ru (на самом деле сервис хорош, но недавняя политика некоторых мобильных операторов создала определённые финансовые сложности ввиду заградительных тарифов на использование услуг sms-рассылок с/без использования имён) родило потребность в применении независимого инструмента.

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

Была предпринята попытка адаптировать изложенную логику на основе полученных знаний, но уперся в кириллическую кодировку, т.к. готового кодера в UCS-2 python не имеет, а варианты на основе utf-16 приводили к какому-то такому результату "PÉQ@P>Q£Q$P>P9".

Но, кто ищет - то находит. Попалась мне готовая реализация на python2 от huh-muh (Ссылка на пост). Адаптировать под python3 труда не составило:

import serial
import time
import random
# процедура для отправки строки в модем и получения ответа
def str_send (ser, textline):
    print("<<" + textline)
    ser.write(bytes(textline, "utf-8"))
    out = ''
    N = 10
    while N > 0:
        time.sleep(1)
        while ser.inWaiting() > 0:
            out += str(ser.read(1))
        if ('OK' in out) or ('ERROR' in out) or ('>' in out):
            print(">>" + out)
            N = 1
        N -= 1

# функция преобразования телефонного номера в формат, пригодный для SMS
def PhoneNumberToSMS(number):
    number += 'F'
    result = '0B' + '91'
    i = 0
    while i < len(number):
        result += number[i+1] + number[i]
        i += 2
    return result

# функция, кодирующая юникодную строку в формат SMS
def TextToSMS(text):
    b = text
    result = ''
    i = 0
    while i < len(b):
        o = ord(b[i])
        result += ("%0.2X" % (o//256)) + ("%0.2X" % (o%256))
        i += 1
    return result

# вводим с консоли сообщение и переводим его в юникод

message = input('Текст сообщения:\n')
# message = message.decode('utf-8')

# если сообщение большое - режем его на кусочки для механизма конкатенации SMS
chunks = []

if len(message) > 70:
    while len(message) > 66:
        chunks.append(message[:66])
        message = message[66:]
if len(message) > 0:
    chunks.append(message)

# готовим номер группы сообщений и устанавливаем 6-й бит SMS_SUBMIT_PDU
SMS_SUBMIT_PDU = "11"
CSMS_reference_number = ""
if len(chunks) > 1:
    SMS_SUBMIT_PDU = "51"
    CSMS_reference_number = "%0.4X" % random.randrange(1,65536)

# связываемся с модемом
ser = serial.Serial("COM4", 9600, timeout=1)

# устанавливаем нужный формат передачи данных
str_send(ser, 'AT+CMGF=0\r')

# передаем кусочки сообщения
i = 1
for chunk in chunks:
    emessage = TextToSMS(chunk)
    if CSMS_reference_number != "":
        emessage = "06" + "08" + "04" + CSMS_reference_number + \
        ("%0.2X" % len(chunks)) + ("%0.2X" % i) + emessage
    sms = "00" #Накидываем тело сообщения в формате PDU
    sms += SMS_SUBMIT_PDU
    sms += "00"
    sms += PhoneNumberToSMS("7ХХХХХХХХХХ")
    sms += "00"
    sms += "08"
    sms += "AA"
    sms += "%0.2X" % (len(emessage)//2)
    sms += emessage
    str_send(ser, 'AT+CMGS=' + str(len(sms)//2-1) + '\r')
    str_send(ser, sms + '\x1A')
    i += 1

# отвязываемся от модема
ser.close()

В целом, код готов. Теперь можно реализовать массовую рассылку, скармливая скрипту файл с телом сообщения и списком адресатов в формате 79876543210, но это уже другая история

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


  1. saipr
    21.04.2022 17:16

    Лиха беда начало. Так что в другой истории?


  1. Jury_78
    21.04.2022 19:25

    Вот спасибо! Что то UCS-2 мимо меня прошло, а я не понимал что такое с СМС.


  1. jackkum
    22.04.2022 04:41

    Когда-то давно писал для этого либу

    https://github.com/jackkum/node-pdu

    Есть PHP версия
    https://github.com/jackkum/PHPPDU


  1. BDI
    22.04.2022 08:45

    Если кому-то потребуется отправка кириллических СМС из VBA/VBScript, то тут есть небольшой класс. Реализовано формирование PDU для отправки длинных СМС в кириллице(работа с модемом своими руками, там ничего экстраординарного).

    Т.к. ничего сверхъестественного там нет, код можно перевести на любой удобный язык :).

    P.S. В теме есть ссылки на описание формата PDU, правда требует авторизации на киберформуме, плюс в описании было пара досадных ошибок(хотя возможно сейчас они уже исправлены).


    1. Chupakabra303
      22.04.2022 11:18

      Когда-то для SCADA использовал этот VBScript класс.


      1. BDI
        22.04.2022 11:25

        Приятно что он кому-то пригодился — писался чисто из интереса :).