Inviare sms con Python e Raspberry

Una delle mie recenti esperienze lavorative mi ha portato a realizzare un sms gateway per l’inoltro di alcune centinaia di messaggi al giorno. Ho scelto di utilizzare l’ormai noto Raspberry Pi come piattaforma hardware e ho scritto uno script in python per gestire l’invio degli sms.

 

Perchè il Raspberry

Ci sono davvero tanti motivi per scegliere un prodotto di questo tipo:

  • nessun alimentatore classico da pc, quindi nessun problema dipendente da esso
  • nessun supporto magnetico, il sistema operativo è su una SD da 4GB, quindi si riduce drasticamente il rischio di perdita di dati o rottura dell’hard disk
  • il processore è un ARM e il costo dell’intero dispositivo completo di SD e alimentatore esterno non arriva a 40 euro
  • la dimensione del dispositivo è di poco più grande di un pacchetto di sigarette, quindi posizionabile ovunque

 

Ma come funziona

La distribuzione linux che ho utilizzato è Debian Wheezy, ho creato una cartella condivisa con samba per depositare da un pc in rete gli elenchi dei contatti a cui il dispositivo deve inviare giornalmente gli avvisi e ho creato una regola per cron (gestore delle operazioni pianificate su linux) in modo da far richiamare lo script python, addetto alla verifica dei file dei contatti e all’inoltro dei messaggi, ogni ora.

Per il collegamento alla rete GSM ho utilizzato una pennina HUAWEI di quelle che si utilizzano per navigare, ma è possibile utilizzare anche un semplice telefonino.

 

Il codice

Di seguito ho postato il codice sorgente della classe Sms della mia soluzione che si occupa proprio di inoltrare il messaggio predefinito inserendo al posto giusto il nome del destinatario.

# -*- coding: utf-8 -*-
 
import time
import datetime
import serial
 
 
class Sms:
     
    # template message to use to send sms
    __message = "Avviso per l'utente  <user> ..."
     
    # timing    
    __waitrw         = 0.3                  # seconds between sends    
    __readtout       = 3                    # read timeout in seconds
     
    __eachstep       = 20                   # number of sends to wait more time
    __bigwait        = 8000                 # seconds between  sends
    __comport        = "/dev/ttyACM0"       # com port to exchange data with phone
    __baudrate       = 9600                 # serial speed    
    __readBuff       = 1024                 # read buffer size
    __smscenter      = "+393916263900"      # FASTWEB SMS Center
     
     
    # object to manage phone/sim card communication
    __phone = None
     
     
     
    # function to read data from buffer using timeout
    def ReadData(self, readTimeOut):
         
         
        endtime = datetime.datetime.now() + datetime.timedelta(0, readTimeOut)
        actual = datetime.datetime.now()
        tmpmsg = ""        
         
        # loop until timeout
        while (actual < endtime):
             
            toRead = self.__phone.inWaiting()
             
            # try to read on serial port
            if toRead > 0:
                tmpmsg = self.__phone.read(toRead)
                break
 
            # update actual time
            actual = datetime.datetime.now()
 
             
        # if buffer is empty, exit
        if len(tmpmsg) == 0:
            return ""
         
        # append to output message
        outmsg = tmpmsg
         
        # if there are bytes to read, read it
        while self.__phone.inWaiting() > 0:
             
            # try to read on serial port
            tmpmsg = self.__phone.read(self.__readBuff)
            outmsg += tmpmsg
         
        # return readed bytes
        return outmsg
         
     
     
     
    # init phone/modem communication
    def Init(self):
         
        # open communication
        self.__phone = serial.Serial(self.__comport, self.__baudrate, timeout=self.__readtout)
         
        try:
            time.sleep(self.__waitrw)
             
            # send ack
            self.__phone.write(b'AT\r')            
            datain = self.ReadData(self.__readtout)
            if datain[-4:] != "OK\r\n":
                return "init error: " + datain
             
            # send sms center
            self.__phone.write(b'AT+CSCA="' + self.__smscenter + '"\r')
            datain = self.ReadData(self.__readtout)
            if datain[-4:] != "OK\r\n":
                return "init error: sms center error: " + datain
             
             
             
        except Exception as e:
            # error detected
            return "init error: [exception] " + e.message
 
        # return empty 
        return ""
 
 
 
 
 
    # send message
    def Send(self, user, number):
 
        # update message to send
        smsmsg = self.__message.replace('<user>', user).encode() + b"\r"
         
        try:
           
            # check for message len
            if len(smsmsg) > 120:
                return "send error: message is too long"
             
            # send ack
            self.__phone.write(b'AT\r')
            datain = self.ReadData(self.__readtout)
            if datain[-4:] != "OK\r\n":
                return "send error: [1] " + datain
           
            # set communication for text messages
            self.__phone.write(b'AT+CMGF=1\r')
            datain = self.ReadData(self.__readtout)
            if datain[-4:] != "OK\r\n":
                return "send error: [2] " + datain
 
            # set phone number
            self.__phone.write(b'AT+CMGS="' + number.encode() + b'"\r')            
            datain = self.ReadData(self.__readtout)
            if datain[-2:] != "> ":
                return "send error: [3] " + datain
             
            # set text messages
            self.__phone.write(smsmsg)            
            datain = self.ReadData(self.__waitrw)
            self.__phone.write(chr(26))            
            time.sleep(3)
            datain += self.ReadData(self.__readtout)
             
            if datain[-4:] != "OK\r\n":
                return "send error: [4] " + datain + " [" + datain.encode("hex") + "]"
             
             
        except Exception as e:
            # error detected
            return "send error: [exception] " + e.message
 
 
        # return empty if all ok
        return ""

 

Lascia il primo commento

Lascia un commento