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:
- Delete all messages leaving unread and sent/unsent messages
- Delete all read and sent messages leaving unread and unsent
- Delete all messages except unread (even unsent messages are deleted)
- 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 string
‘RING
’ 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