Send and Receive SMS Messages Using Raspberry Pi and Python

Introduction

As I described already in another article – Running the Raspberry Pi on Solar Power it is pretty easy to run the Raspberry Pi on solar energy. This fact combined with the small form factor of the Pi makes it extremely portable platform. In one of my projects I will leave the Raspberry Pi working in a distant rural area with no wired or wifi connection. The only possibility to connect to it is through the cell phone network.

So I came up with the idea to control the Pi with short messages or SMSs.

Get a Raspberry Pi and Accessories

You can obtain many Raspberry Pi accessories including 3g modem from banggood.com or aliexpress.com

Connecting the 3g Modem

In order to connect the Pi with the cell network we would first need a 3g modem. Fortunately nowadays they are very cheap and easy to get hold of. The carriers even give them for free. So I had the ZTE MF190 from a Bulgarian carrier and attached it to the Raspberry Pi. Then came the first challenge – 3g modems usually have two modes of operation – a usb storage device and a 3g modem with the storage mode being the default one. This is very convenient for Windows users because when you plug the modem it opens as a usb stick where all the necessary drivers are, you install them and then it is automatically switched to a modem mode. Of course it is not that easy under Linux. What you have to do is to switch it manually to a modem mode and then use the likes of wvdial or pppd to establish a connection. The good news is that there are plenty of articles how to do it and it is not that hard, so I will not talk about it here :). A good reference are these pages:

Sending SMS

Once you have the 3g dongle connected as a modem three new devices will appear under /dev. In my case these are /dev/ttyUSB0, ttyUSB1 and ttyUSB2, with additional symbolic link /dev/gsmmodem pointing to ttyUSB2. What this means is that while you establish connection using the /dev/gsmmodem the others are free and can be opened and used to send AT commands to the modem.

But what are AT commands? The AT (meaning ‘attention’) commands are simple instructions send to the modem over a serial link telling it what to do – dial a number, hang up, send message, etc. For more information: Wikipedia. In reality it is not so straightforward to get a list of those commands since for 3g dongles there is no official documentation (at least for those I have). Fortunately there are internal leaked documents on the internet so I was able to find the ZTE command set by with Google.

So let’s try to send some commands. For testing purposes I use the cu program –  cu – Call up another system. To open the modem type the following: “cu -l /dev/ttyUSB1”. After that you should see an empty screen. Now what you type is directly send to the modem. Type AT and hit ENTER. You should see OK in response:

pi@raspberrypi ~ $ cu -l /dev/ttyUSB1
Connected.
AT
OK

Now we are ready to send a short message. There are two ways to do it – either in text mode either in PDU mode. For now we will stick to text mode because it is easier to work with. So let’s go in it:

AT+CMGF=1
OK

Now to send a SMS we should send the following command, notice that at then end of the message we hit ctrl + z:

AT+CMGS=”<phone number>”r
> here we type the message text<ctrl+z>

+CMGS: 152
OK

The phone number can be the full one with the country code or the short one starting with zero. Also r means the ENTER key. If everything is going fine you will see an “OK” in response.
How do we do it in python? Let’s see an example:

#!/usr/bin/python
import serial
<span class="pl-k">from</span> curses <span class="pl-k">import</span> <span class="pl-c1">ascii
</span>import time
 
modem <span class="pl-k">=</span> serial.Serial(<span class="pl-s"><span class="pl-pds">'</span>/dev/ttyUSB1<span class="pl-pds">'</span></span>, <span class="pl-c1">460800</span>, <span class="pl-smi">timeout</span><span class="pl-k">=</span><span class="pl-c1">1</span>)
 
modem.write("AT+CMGF=1")
print modem.readline()
print modem.readline()
 
modem.write('AT+CMGS="%s"r' % "012345679")
modem.write("message text")
modem.write(<span class="pl-c1">ascii</span>.ctrl(<span class="pl-s"><span class="pl-pds">'</span>z<span class="pl-pds">'</span></span>))
time.sleep(2)
 
print modem.readlines()

If everything is alright you will see several lines in response with an OK at the end.

Receiving SMS

Now when we are able to send messages let’s see how to read incoming ones. Looking at the AT command list for the ZTE MF190 we see the +CMGL – List Messages. In text mode the command syntax is the following:

AT+CMGL=”<stat>r”

Where stat is any of the following: “REC UNREAD”, “REC READ”, “STO UNSENT”, “STO SENT”, “ALL” – unread, read, unsent, send and all messages. Example:

AT+CMGL=”ALL”r

+CMGL: 12,”REC UNREAD”,”+359882505000″,,”15/06/14,23:27:17+12″
CMD:connect
+CMGL: 13,”REC UNREAD”,”+359882505000″,,”15/06/15,11:15:15+12″
CMD:status
+CMGL: 14,”REC UNREAD”,”+359882505000″,,”15/06/15,11:15:57+12″
CMD:status

OK

Using the +CMGL command its easy to get incoming SMS messages but there is one drawback – we have to query the modem every once in a while in order to get updates. It would be much better if the modem notifies us (pushes) directly once there is a message. Again looking at the command specification we can see: +CMTI which stands for “New Message Indications”. If there is an incoming SMS the modem pushes a line with the following form:

<CR><LF>+CMTI: <mem>,<index><CR><LF>

where <mem> can be “ME” – message storage, “SM” – SIM storage or “SR” status report storage and then the <index> is the message index in that storage. Having this information we can send +CMGR “Read Message” command. it has the following form:

+CMGR=<index>r

When executed it sends back the message content together with some header information:

AT+CMGR=14
+CMGR: “REC READ”,”+359882505000″,,”15/06/15,11:15:57+12″
CMD:status

OK

If we receive too many messages the memory eventually will fill up, so how do we free space? Easy – with the +CMGD command:

+CMGD=<index>[,<delf lag>]

By using the index we can delete the message we want and by using the <delflag> we can delete all read messages for example.

AT+CMGD=1,2
OK

Here I used the delflag = 2 which means: “Delete all read messages from preferred message storage and sent mobile originated messages, leaving unread messages and unsent mobile originated messages untouched”.

For more information regarding the ZTE at commands look for the fucking manual on the internet :).

Putting It All Together

Now that we can send and receive messages let’s make a server program in python which will receive commands via SMS, decode them and then execute actions on the Pi. For now I have defined actions such as “connect” – to establish internet connection on the Pi, “disconnect”, “reboot” – to reboot the Raspberry Pi, “status” – which returns connection status, free space on the memory card and in the future will return local temperature. This list can easily be extended. It would probably have been much easier to use a simple web server to control the Pi but unfortunately you don’t get a real ip address on the 3g network. So we should stick to SMS.

To see the full program, checkout my github repository – smscenter.

Conclusion

It is easy to turn the Raspberry Pi into a remotely managed “probe” even without internet connection. Possible applications are garden automation, weather stations, surveillance camera etc.

Links

12 thoughts on “Send and Receive SMS Messages Using Raspberry Pi and Python

  1. My sim900A gsm module is not responding to AT commands.It should print OK but not printing anything.

    I have been facing this problem since long time.

    Please help me ASAP.

    Thanks.

  2. Can we use a number which is stored in a variable in AT+CMGS command ?
    Please help.

  3. Hi, Can we connect many USB 3G with SIM cards into the raspberry pi? We can use a hub usb to divide an USB port to 4 sub USB and plug in 4 USB 3G with SIM cards. Can we use in this way? Did you try? Tks

  4. Please, I have bought and installed an ZTE MF190, as yours.

    lsusb gives me:

    Bus 001 Device 005: ID 19d2:0117 ZTE WCDMA Technologies MSM
    Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
    Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
    Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

    pi@raspberrypi ~ $ cu -l /dev/ttyUSB1
    Connected.
    AT
    OK

    exactly as you describe.

    But,

    AT+CMGF=1
    ERROR

    The red light is on the dongle.

    Am I missing a step?

  5. Hi, can you correct the sending sms code example? There are extra HTML formatting characters and its a bit confusing. If you open this blog post there you can see the sample code as follows:

    #!/usr/bin/python
    import serial
    from curses import ascii
    import time

    modem = serial.Serial(‘/dev/ttyUSB1’, 460800, timeout=1)

    modem.write(“AT+CMGF=1”)
    print modem.readline()
    print modem.readline()

    modem.write(‘AT+CMGS=”%s”r’ % “012345679”)
    modem.write(“message text”)
    modem.write(ascii.ctrl(‘z’))
    time.sleep(2)

    print modem.readlines()

    Thanks in advance.

    BR,

    //Cs

  6. Aahhhhh, posted the comment and transformed to the correct one 🙂 But the sample code window is still not fine…should be the same I pasted above.

Leave a Reply