4 дек. 2012 г.

Проверка балланса GSM-модема, подключенного к Asterisk и формирование лога звонков за прошедшие сутки с отправкой по e-mail на Python 3

Недавно был описанный в заголовке таск.

Т. к. я очень люблю питончик, то скрипты пишу на нём. В скрипте выполняется команда астериска (USSD-запрос), далее вытягивается содержимое ответа на ussd, вытягивается лог звонков за сутки, формируется письмо в виде html и отсылается на заданные адреса по электронной почте.

1. Импорты необходимых библиотек:


#!/usr/bin/env python3
import os, smtplib, time, subprocess, shlex, sys, csv
from email.utils import formatdate
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

2. Формируем шапку письма - кому, куда, что и зачем :)


# me == my email address
# you == recipient's email address
# cc == copy's address
me = "asterisk@example.com"
сс = "recipient1@example.com"
you = "recipient2@example.com"
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "GSM modem balance ("+time.strftime("%m/%d/%Y",time.localtime())+")"
msg['From'] = me
msg['To'] = you+", "+cc
msg['Date'] = formatdate(localtime=True)

Отправка USSD-запроса сосстояния балланса и обработка результата. Для посылки запроса использую вызов bash команды через subprocess.call - может быть и слишком криво, но быстро и работает.

Затем идет пауза в 10 сек - необходима, чтобы пришел ответ от оператора.
Далее читаем файлик с ответом (что за файлик и где его брать - настраиватьеся в extensions.conf астериска и я писал уже об этом) и делаем некоторые украшательства для html-письма.


# call ussd command
subprocess.call(["asterisk","-r","-x","dongle ussd dongle0 *111#"],stdin=None, stdout=None, stderr=None)
time.sleep(10)
exit()
# open file
f = open ("/var/log/asterisk/ussd.txt","r")
#Read whole file into data
ussd_data = f.read()
f.close()
# Format ussd data as html
replace1='Na rahunku:<strong><font color="red">'
replace2='grn.</font></strong><br>'
ussd_data=ussd_data.replace('Na rahunku:',replace1)
ussd_data=ussd_data.replace('grn.',replace2)

Здесь идет формирование html-таблицы из стандартного лога звонков. User1, User2 - это пользователи, от которых могут идти исходящие звонки, т. е. - все ваши пользователи. Это нужно для определения, в какую таблицу кидать запись - входящие или исходящие звонки. Алгоритм не оптимален, но это первое рабочее решение, пришедшее мне в голову и подходящее под мои требования.

#########call log part
#input log file path
ipath = '/var/log/asterisk/cdr-csv/Master.csv'
ArrMessg = []
OutCalls = []
InCalls = []
LastArr = []
nextmsg = []
#open log
ifile  = open(ipath, "r")
#read file using csv module
reader = csv.reader(ifile)
for row in reader:
        ArrMessg.append(row)
        #if (row[9] == "0"): 
date = time.strftime("%Y-%m-%d",time.localtime())
for row in ArrMessg:
        nextmsg = row[9]
        if (nextmsg[0:10] == date):
                tmpmsg = []
                tmpmsg.append(row[1])
                tmpmsg.append(row[2])
                tmpmsg.append(row[9])
                tmpmsg.append(row[12])
                if (row[1] in ["User1","User2","User3"]):
                        OutCalls.append(tmpmsg)
                else:
                        InCalls.append(tmpmsg)
#########

Здесь идет формирование html-кода таблиц вх. и исх. звонков. Тут всё должно быть понятно - вставляем куда нужно теги.


# Attach letter into message container.
html = """\
<html>
  <head></head>
  <body>
    <p><br>
"""
html = html+ussd_data
html = html+"""\
        <br>
        <br>
        <strong><font color="blue">Incoming Calls:</font></strong><br>
        <br>
        <table width="60%" border="2" cellspacing="0" cellpadding="4">
                <tr align="center" bgcolor="#999999">
        <td>Source</td> <td>Extension</td> <td>Date</td> <td>Duration</td> <td>Note</td>
                </tr>
"""
for row in InCalls:
        tmp = str(row)
        rep1 = '<tr align=\"center\">'
        tmp=tmp.replace("[",rep1)
        tmp=tmp.replace("]","</tr>")
        tmp=tmp.replace("\',","</td>")
        tmp=tmp.replace("\'","<td>")
        html = html+tmp
html = html+"</table>"

html = html+"""\
        <br>
        <strong><font color="blue">Outgoing Calls:</font></strong><br>
        <br>
        <table width="60%" border="2" cellspacing="0" cellpadding="4">
                <tr align="center" bgcolor="#999999">
        <td>Source</td> <td>Destination</td> <td>Date</td> <td>Duration</td> <td>Note</td>
                </tr>
"""
for row in OutCalls:
        tmp = str(row)
        rep1 = '<tr align=\"center\">'
        tmp=tmp.replace("[",rep1)
        tmp=tmp.replace("]","</tr>")
        tmp=tmp.replace("\',","</td>")
        tmp=tmp.replace("\'","<td>")
        html = html+tmp
html = html+"</table>"

html = html+"""\
       <br>
        <br>
        <br>
        Best regards,<br>
        Developers Team<br>
    </p>
  </body>
</html>
"""
#print (html)
ifile.close()

Отправка письма через сервер mail.example.com и очиска файлика с ussd.


# Record the MIME type
letter = MIMEText(html, 'html')
# Attach letter into message container.
msg.attach(letter)
# sendmail function takes 3 arguments: sender's address, recipient's address
# and message to send - here it is sent as one string.
s = smtplib.SMTP('mail.example.com')
s.sendmail(me, you, msg.as_string())
s.quit()
subprocess.call(["rm","-f","/var/log/asterisk/ussd.txt"])

Выжимка из /etc/asterisk/extensions.conf для настройки USSD:

[dongle-incoming]

exten => ussd,1,System(/bin/echo "${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)} - ${USSD}" >> /var/log/asterisk/ussd.txt)
exten => ussd,n,Hangup()

Т. е. здесть говорится, что если пришел ответ от сервера на экстеншн ussd, то выполнить команду оболочки - записать в такой-то файлик текущее время и тело ответа от оператора.

Чтобы посылать письмо утром, надо либо разделить скрипт на 2 части - чтобы одна чекала в 23:50, а вторая отсылала уже утром. Либо что-то мудрить с датами (мне проще было сделать 1й вариант).