Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Python

SMS Implementation with the Telit Cellular Module using Python

4.75/5 (7 votes)
9 Oct 2010CPOL5 min read 42.1K  
SMS implementation with the Telit Cellular Module using Python

Introduction

This is a continuation of the series of articles on how to use the embedded Python interrupter to control a Telit GC864-PY or other Python enabled cellular modules produced by Telit. In this article, we will be covering how to send and receive SMS messages with Python and AT commands.

Setup

To setup SMS messages, there are a few things your script needs to include in the initial stages.

#AT+CMGF mode 1 = text mode 0 = PDU mode (Default)
#Set Text Mode
a = MDM.send('AT+CMGF=1\r', 2)
#clear Receive buffer
res = MDM.receive(5)
#ATE0 sets the modem to echo commands
a = MDM.send('ate0\r', 2)
#clear Receive buffer
res = MDM.receive(5)
#CNMI sets up the new SMS message indicator
#AT+CNMI=mode,Message_Format,Broadcast_Reporting,SMS-Status-Report,Buffer-Handling
#Settings used
#Mode = Buffer and Forward to terminal
#Message_Format = '+CMTI: <memr>,<index>'
#Broadcast_Reporting = No messages
#SMS-Status-Report = No Reporting
#Buffer Handling = Buffer Flushed to terminal
a = MDM.send('AT+CNMI=2,1,0,0,0\r', 2)
#clear Receive buffer
res = MDM.receive(5)

The default mode for the Telit device is to use the PDU format. This is not a good mode to use unless you understand what PDU is and want to use it. The second mode is Text. This is a verbose setup that allows you to read the messages without having to decode them. Your first step is to set this mode.

#AT+CMGF mode 1 = text mode 0 = PDU mode (Default)
#Set Text Mode
a = MDM.send('AT+CMGF=1\r', 2)
#clear Receive buffer
res = MDM.receive(5)

Please refer to the previous article for the explanation of the custom Python library that is included with the Telit modules. MDM.send() and MDM.receive() are explained there.

The next command is the ATE command. This disables the input echo so that the receive buffer only has responses from the module and there is no need to see the commands you send the device.

The CNMI command is really important and decides what the module displays when a message is received.

#CNMI sets up the new SMS message indicator
#AT+CNMI=mode,Message_Format,Broadcast_Reporting,SMS-Status-Report,Buffer-Handling
#Settings used
#Mode = Buffer and Forward to terminal
#Message_Format = '+CMTI: <memr>,<index>'
#Broadcast_Reporting = No messages
#SMS-Status-Report = No Reporting
#Buffer Handling = Buffer Flushed to terminal
a = MDM.send('AT+CNMI=2,1,0,0,0\r', 2)
#clear Receive buffer
res = MDM.receive(5)

We will cover how to read the message later but when you receive a message, you will see something like this:

+CMTI: "SE",2

The format and the mode are the most important at this stage. The AT command reference guide for the module goes deeper into the other options if your situation requires different settings.

Receiving SMS

With the above settings, it is easy to identify and extract the body of any SMS messages received and the number that it came from. First, you have to wait for an SMS message to arrive and this can be handled by different methods. An infinite loop was used here to keep checking for new messages from the Terminal.

while 1:
        #Read buffer for new messages
        res = MDM.receive(5)
        #Identify if a SMS was received
        a = res.find('+CMTI: "SM",')
        #Process Received SMS Message
        if (a != -1):
                #Identify the position of memory location
                firstdigit_pos = a + 12
                #Extract Memory location as string
                pos = res[firstdigit_pos:-2]
                #Retrieve Sending Number
                SMSnumber = getSMSnumber(pos)
                #Retrieve Message
                SMSmessage = getSMSmessage(pos)

The Variable a is set to the first position of the string if it contains '+CMTI: "SM". This allows us to identify if a message was received and eliminate any other messages that may have been trapped in the buffer. Now we need to isolate the exact index number of the message.

firstdigit_pos = a + 12

Now we know where the first index number starts and we take the rest of the string -2 places from the right to eliminate some trailing white space. And we obtain the pos value to use in the next two functions.

pos = res[firstdigit_pos:-2]

getSMSnumber extracts the number from the resulting string when a read command is issued. We have not covered this yet, but I will explain it as we go.

def getSMSnumber(SMSpos):
    #setup command for reading message
    SMS_read_command = 'AT+CMGR='+str(SMSpos)+'\r'
    #clear receive buffer
    MDM.receive(10)
    MDM.send(SMS_read_command,5)      #send the read message command
    SMScontent = MDM.receive(15)        #collect the contents of the message
    b = SMScontent.find('+1')           #Identify the start of the number
    c = b+12
    SMSnumber = SMScontent[b:c]         #Extract the number
    return(SMSnumber)

This function is rather simple. It just identifies the number in the string that is generated by the +CMGR command. CMGR just requires the <index> location in memory and it will retrieve the message in a format similar to the following:

+CMGR: "REC READ","+15291234567",,"07/02/18,00:12:05+32"
Insert SMS message here

This function only works with US numbers because I search for the “+1”. A different approach would be needed for international messages. Once the start of the number is identified, it's easy to parse out the number and return that to the main function.

The same procedure is used to retrieve the body of the message.

def getSMSmessage(SMSpos):
        #setup command for reading message
        newSMSread_command = 'AT+CMGR='+str(SMSpos)+'\r'
        #clear receive buffer
        MDM.receive(10)
        MDM.send(newSMSread_command,5)      #read the new SMS arrived
        SMScontent = MDM.receive(15)        #collect the full message with header
        a = SMScontent.find('\n',4) + 1     #Find the end of the first line
        b = len(SMScontent)
        SMSmessage = SMScontent[a:b]        #extract message from response
        return(SMSmessage)

Similar to the above, you just need to remove the header for the message and take just the body of the message. The biggest hurdle is setting up the modem correctly and the rest is string manipulation.

Sending SMS

Sending SMS messages is even easier than receiving them.

def sendSMS( number, smstext):
        #Send command for sending message
        a = MDM.send('AT+CMGS="' + number + '"\r', 2)
        #clear receive buffer
        res = MDM.receive(10)           
        a = MDM.send(smstext, 2)        #Send body of message
        #this terminates the message and sends it
        a = MDM.sendbyte(0x1A, 2)       #terminating the message require ctrl-z
        return()

The CMGS command is what you need here. It simply requires the destination number. The module displays a prompt and then accepts anything sent to it as the body of the message. Finally sending a Ctrl-Z to the module indicates the message is finished and sends it.

Deleting SMS

In order to delete an SMS, all you need to know is the position in memory. You can also delete all messages instead of just one.

AT+CMGD=<index>[,<delflag>]

<delflag> is optional and allows for several different options when deleting all messages. If omitted or 0, then only the message at <index> is deleted.

<delflag> options are:

  1. Delete all messages leaving unread and sent/unsent messages
  2. Delete all read and sent messages leaving unread and unsent
  3. Delete all messages except unread (even unsent messages are deleted)
  4. Delete all messages

This function deletes all messages from memory.

def del_all_SMS(SMSpos = 1):
        delSMS_command = 'AT+CMGD='+str(SMSpos)+',4\r'
        MDM.send(delSMS_command,5)     #delete all messages
        return()

Making Voice Calls

Answering and making voice calls is not a very big topic, so I decided to cover it here instead of dedicating it to another article. Answering calls requires checking for the stringRING’ on the MDM interface. This will allow you to send the following command.

ATA

ATA answers the call and uses the mic and speaker inputs on the device. This can be used to monitor a location or audio source remotely or to create a remote call box. Making a call is just as simple.

ATD<number>

Just insert the number to call and it will automatically connect the other phone to the mic and speaker connections. Call control is rather simple and easy to implement with the MDM.send() and MDM.receive() commands in Python. Here is an example of a script to answer a phone call.

#Check for Phone CAll
p = res.find('RING')
if (p != -1):
       q = MDM.send('ATA\r',5)

Conclusions

SMS messages are a great way to send information back and forth from a project and allow control from almost any way. In future articles, we will be covering other topics such as data calls and GPIO usage.

History

  • 8th October, 2010: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)