Table of Contents
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
- 4 In 1 Raspberry Pi 3 Model B + V31 Acrylic Case + Pi Fan + Aluminum Heatsink Set
- Raspberry Pi 3 Model B (banggood.com)
- Raspberry Pi 3 Model B (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:
- How to setup a USB 3G Modem on Raspberry PI using usb_modeswitch and wvdial
- Everything About the 3g Modems… (in Bulgarian)
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
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:
Now to send a SMS we should send the following command, notice that at then end of the message we hit ctrl + z:
> here we type the message text<ctrl+z>
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.
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:
Where stat is any of the following: “REC UNREAD”, “REC READ”, “STO UNSENT”, “STO SENT”, “ALL” – unread, read, unsent, send and all messages. Example:
+CMGL: 12,”REC UNREAD”,”+359882505000″,,”15/06/14,23:27:17+12″
+CMGL: 13,”REC UNREAD”,”+359882505000″,,”15/06/15,11:15:15+12″
+CMGL: 14,”REC UNREAD”,”+359882505000″,,”15/06/15,11:15:57+12″
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:
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:
When executed it sends back the message content together with some header information:
+CMGR: “REC READ”,”+359882505000″,,”15/06/15,11:15:57+12″
If we receive too many messages the memory eventually will fill up, so how do we free space? Easy – with the +CMGD command:
By using the index we can delete the message we want and by using the <delflag> we can delete all read messages for example.
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.
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.