Оперативное информирование клиентов, когда их достаточно много для ручного обзвона, но недостаточно много для подключения массового сервиса, вроде 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, но это уже другая история