Pull to refresh

Реализация отправки sms-уведомлений

System administration *
В виду достаточно большого парка серверов/свитчей/модемов и иного активного оборудования в конторе, была установленная система мониторинга zabbix и успешно использовалась продолжительное время. Zabbix имеет замечательную возможность отправки уведомлений о возникших проблемах.
Для этого был написан скрипт отправки sms сообщений через шлюз email-to-sms оператора связи, ограничение по количеству смс с одного адреса в сутки было обойдено путем ротации исходящих адресов, работало более или мение сносно, но в последнее время смс сообщения через данный шлюз начали доходить с задержкой порядка 10-15 минут, что уже не очень нравилось.
Итак, было решено организовать отправку уведомлений через собственный GSM-терминал, порывшись в прайсах поставщиков и не обнаружив там подходящих по цене и характеристикам GSM модемов весьма огорчился.
И тут вспомнилось что дома валяется старый Siemens CX65 да еще и data-кабель к нему, после подключения телефона и курения доков по отправке sms сообщений пришел к не очень радостному выводу, оказывается siemens не поддерживает отправку sms в текстовом режиме, команда AT+CMGF=1 возвращает error.
Отправка сообщений в данных аппаратах возможна только в режиме PDU, ради спортивного интереса и для размятия мозгов было решено реализовать эту систему, был написан скрипт для перекодировки в PDU формат сообщений и отправки через телефон.

Мануал по системе отправки сообщений можно найти здесь: dreamfabric.com/sms
Сам получившийся скрипт:
#!/usr/bin/python

import os
import sys
import time

def dectobin(i):
	b = ''
	while i > 0:
		j = i & 1
		b = str(j) + b
		i >>= 1
	return b

def SendSMS(dev,number,text):
	pdu_data = '00'
	pdu_data += '11' #SMS-SUBMIT
	pdu_data += '00' #TP-Message-Reference
	pdu_data += '0B' #Address-Length
	pdu_data += '91' #Address-Length
	'''Convert telephone number'''
	number += 'F'
	pdu_number = ''
	for i in range(0,len(number)):
		if i%2==0:
			continue
		pdu_number += number[i] + number[i-1]
	pdu_data += pdu_number
	pdu_data += '00' #TP-Protocol identifier
	pdu_data += '00' #TP-Data coding scheme
	pdu_data += 'AA' #TP-Validity-Period
	
	'''Convert text to binary format'''
	pdu_text_bin = []
	for i in text:
		dec_s=ord(i)
		if dec_s == 95:
			dec_s = 17
		if dec_s == 94:
			dec_s = 1
		if dec_s == 64:
			dec_s = 0
		if dec_s == 36:
			dec_s = 2
		if dec_s == 123:
			dec_s = 40
		if dec_s == 125:
			dec_s = 41
		if dec_s == 124:
			dec_s = 64
		if dec_s == 126:
			dec_s = 61
		if dec_s == 92:
			dec_s = 47
		if dec_s == 91:
			dec_s = 60
		if dec_s == 93:
			dec_s = 62
		bin = dectobin(dec_s)
		le = len(bin)
		while le<7:
			bin='0'+bin
			le = len(bin)		
		pdu_text_bin.append(bin)
	
	'''Encode binary to PDU format'''
	pdu_text_bin_cp = []
	n=0
	for i in range(0,len(text)):
		if (i>0) & ((i+1)%8==0):
			continue
		n+=1
		if n==8:
			n=1
		if i==len(text)-1:
			cp = pdu_text_bin[i][0:8-n]
		else:
			cp = str(pdu_text_bin[i+1][7-n:7] + pdu_text_bin[i])[0:8]
		pdu_text_bin_cp.append(cp)
			
	'''Convert PDU to hex'''
	pdu_text=''
	for i in pdu_text_bin_cp:
		hexi = str(hex(int(i,2)))[2:4].upper()
		if len(hexi) == 1:
			hexi = '0' + str(hexi)
		pdu_text += hexi
	
	'''Calculate text length'''
	len_hex = hex(len(text))[2:4].upper()
	if len(len_hex) == 1:
		len_hex = '0' + str(len_hex)
		
	'''Calculate PDU length'''
	pdu_data+=len_hex+pdu_text
	pdu_len = str(len(pdu_data)/2-1)
	
	if True:
		fd = os.open(dev, os.O_RDWR)
		os.write(fd, "AT+CMGF=0 \015")
		time.sleep(1)
		os.write(fd, "AT+CMGS=" + pdu_len + "\015")
		time.sleep(1)
		os.write(fd, pdu_data + "\032")
		os.close(fd)
	
def main(argv):
	SendSMS("/dev/ttyUSB0",argv[1],argv[2] + '\r\n' + argv[3])
	return 0

if __name__ == '__main__': main(sys.argv)

Не претендую на правильность кода, программированием на python занимаюсь не часто, поэтому любые оптимизации скрипта готов принять.

Телефон подключается при помощи data-кабеля, который представляет собой usb-serial переходник, основанный на чипе Prolific pl2303, данный чип стабильно работает в linux, никаких нареканий на работу связки телефон-комп нет.
Для корректной работы скрипта необходимо перед началом работы выставить нужные параметры ком-порта.
Для этого в /etc/udev/rules.d/50-udev.rules была добавлена следующая строчка:
KERNEL=="ttyUSB[0-9]", RUN+="/bin/stty -F /dev/%k speed 9600 -brkint -icrnl ixoff -imaxbel -opost -onlcr -isig -icanon -echo -echoe"
Теперь при каждом подключении кабеля параметры com-порта выставляются автоматически, нет необходимости запускать приложения вручную.
Далее в zabbix не сложная настройка и система отправки уведомлений готова, бюджетный вариант с GSM-терминалом работает гораздо лучше чем сервисы email-to-sms, плюс может отправлять уведомления о том что упал канал в инет, ранее после падения инета отправка соответственно не могла быть осуществлена.

Возможно данный материал будет кому либо полезен, старая мобилка наверняка валяется у каждого дома, а покупать gsm-модем стоймостью более 8000 рублей не очень хочется.
Tags:
Hubs:
Total votes 46: ↑42 and ↓4 +38
Views 15K
Comments Comments 44