PySMS
PySMS is a package, written in Python, which communicates with a mobile phone, allowing SMS messages to be sent and received. It includes an XML- RPC server, allowing the resource to be shared across a network. There is also a message - response mechanism, which allows an automatic response to messages to be specified, based on the content of the message. This allows you to, for example, run commands on your server and return a summary of the results to your phone, via SMS.
PySMS is released under the GPL license.
Download the latest version here
Required packages
* Python 2.2 or higher
* PySerial
* xmlrpc
This software has been tested on Windows 98SE and Gentoo Linux 2.4.20, but it should run on any platform that the above packages run on.
Background
It all started when I woke up one morning to find my phone lying in a pool of water next to an upturned glass by the bed. The phone was soaking wet and seemed dead. Being a phone addict, I went straight out and bought another phone. Trying the phone again a few days later I found that it was working perfectly. Not liking things to go to waste I decided to put the old phone to work, so embarked on this project. The phone is now permanently connected to my Mini-ITX Linux box.
The software should work with any phone that implements the common SMS AT command extensions. You will need a serial cable to connect the phone to the RS232 port of your computer, or you can use IrDA. I've not tried Bluetooth yet.
I would like to thank Beacon Dodsworth Ltd. for their support and encouragement with the development of this software.
Documentation
The software consists of:
nokia.py - Interfaces to the phone using pyserial. Does all the AT stuff.
server.py - Runs an XML-RPC server allowing other processes to use the SMS resource. The server also polls the phone for messages. A configuration file allows a set of actions to be associated with certain message types. For example, a message can be defined that will provoke a response in the server.
The following commands are supported over XML-RPC
* sms.at()
* sms.reset()
* sms.send_message(number, text)
* sms.read_messages()
* sms.read_message(index)
* sms.delete_message(index)
* sms.get_power()
* sms.get_signal_dbm()
* sms.set_memory(code)
* sms.get_manufacturer()
* sms.get_model()
* sms.log_read()
Examples
Running the server
The server can be run on the command line by running the script server.py with the following parameters:
* comm port index (e.g. COM1 or /dev/ttyS0 is '1')
* required host / port (e.g. '
http://server:8181')
* path to the INI file
I run the following script. I also call this from a script in /etc/init.d so that the service starts when the machine is booted. The port number 8181 was chosen by me arbitrarily.
#!/bin/bash cd path/to/sms/stuff ./server.py 1
http://server:8181 nokia.ini >>/var/log/pysms/nokia.log 2>>/var/log/pysms/nokia_error.log &
Client code
The following code fragment shows how simple it is to communicate with PySMS, thanks mainly to xmlrpclib. This code connects to the server, reads a list of all messages on the phone, prints out their contents and deletes them from the phone.
import xmlrpclib server = xmlrpclib.ServerProxy('
http://server:8181') for msg in server.sms.read_messages(): print 'reading message' index = msg['index'] print msg['number'] print msg['text'] print 'deleting message' server.sms.delete_message(index)
This following script will send a text message to a number specified on the command line. The message is truncated because of the limited size of SMS messages.
import sys import xmlrpclib server = xmlrpclib.ServerProxy('
http://server:8181') number = sys.argv[1] text = sys.stdin.read() server.sms.send_message(number, text[:150])
External programs
An external program can be configured to be called on receipt of an SMS message. An example is included with the source code which emails the contents of any message, providing a SMS-to-email service (see sms_to_email.py). The script send_sms.py will send an SMS to a provided number. This allows a command to be executed on the server, and results returned via a text message.
The configuration file has the following .ini file format:
[section] regex = "regex" exec = "executable" mode = "repeat|delete|once|more"
There is a special section called 'system', which contains configuration items. This is followed by command sections. The system section can be used to specify an optional log file used to archive all sent and deleted messages. e.g.
[system] sendlog = "/var/log/pysms/nokia_send.log"
The remaining sections are then sorted in alphabetic order. The order can be controlled by giving the section names a numeric prefix, e.g. 00-first-section ... 99-last-section.
Each message is compared to each section until a regex match is found, or the section list is exhausted. Any regex that matches the message will result in the executable being called. Note: the regex must include at least one group (i.e. something in brackets) in order to match. The content of the message is written to the stdin of the called program. The match's group is passed as additional command line parameters to the executable.
The regex system allows for flexible control of responses to SMS messages. It is a simple matter to design a system which will, for example, control processes on the server, or return data by responding with an SMS message, so that the server can be remotely monitored. You could, for example, remotely enable a web server.
[01-webserver] regex = "WWW (start|stop)" exec = "/etc/init.d/apache" mode = "once"
All you need to do is text the message WWW start to start up apache. Does that look dangerous?
The mode parameter determines how the message is dealt with after the command has been executed. The polling rate for messages is currently fixed at 1 minute. There are 4 possible modes:
* once: the message is processed once and subsequently ignored
* delete: the message is deleted after processing
* repeat: the message gets executed at each polling cycle
* more: process this command and then look for the next command
The originating phone number of the SMS is included in the data passed to the script, and can additionally be passed as a command line parameter. This allows rudimentary security - by ensuring that only certain phone numbers are responded to (although SMS phone numbers can be spoofed). This is achieved using the facility for extracting fields from the message (e.g. 'index', 'number', 'text') and placing these on the command line using the syntax #(number)s, where 'number' is one of the fields in the message object returned by read_messages(). There is also an args substitution, #(args)s, which will be replaced by the regex group(s). For example:
[02-ping] regex = "Ping (.*)" exec = "ping -c 1 #(args)s | ./send_sms.py
http://server:8181 #(number)s" mode = "once"
This will match any text starting with Ping , execute ping -c 1 with the args in the rest of the text (matching the (.*) part of the regex), then send the result as an SMS to the originating phone number (by substituting for #(number)s). This is a handy way of checking if a machine can be seen from the server connected to the phone.
[03-nmap] regex = "Nmap (.*)" exec = "nmap #(args)s | awk '/open/ { print $1 " " $3 }' | ./send_sms.py
http://server:8181 #(number)s" mode = "more"
This nmap command is really useful. It is great when on clients' sites to check if their firewalls are working correctly. All you need to do is type in the IP address or domain name (i.e. text Nmap my.server.com), and your server will scan the ports and send an SMS listing all the open ones. The awk command removes the redundant information, to cut down the message size, simply listing the open port numbers and protocols. The summary is then sent back to the caller via SMS.
I have a handy catch-all command that simply emails me the received SMS. The mode is set to once, so that the message is ignored on subsequent polls.
[99-email] regex = "(.{1,30})" exec = "./sms_to_email.py smtp.server to@email.address from@email.address #(number)s #(date)s" mode = "once"
The (.{1,30}) group is there simply to put some meaningful info into the log, without dumping the whole message. It could just as easily be (.*).
Warning: the executable will be run with the same privileges as the user that invokes the server script. This could result in the programs being called with root privileges.
Hardware considerations
When the phone is connected to an RS232 port the batteries will discharge faster than normal. I presume this is either because of the current drain from the physical interface, or more likely because the CPU must stay awake to respond to serial data. I found that the phone went flat in 24 hours. Manufacturers warn against leaving the charger switched on all the time, and my phone will not operate without the battery pack.
I solved this problem by using a mains timer. The current battery status can be determined via the sms.get_power() call. I wrote a simple cron script that logs the battery status each hour. By studying the battery status over time I determined that a one hour charge twice a day was enough to keep the phone working correctly. In fact, it seems that the battery reports being fully charged when it is not, and after running several cycles of slight overcharging the battery seems to hold more charge than it used to, as it now discharges less during the day.
Problems talking to Nokia phones
I discovered two bugs in the Nokia firmware while writing PySMS. Both relate to the Tx of serial data.
The first manifests itself as corruption of the currently transmitting character when a CR is Rxd. This causes bad characters to be transmitted and may result in framing errors, possibly corrupting subsequent characters too. This is presumably because the Tx routines are software driven, but the bit-rate gets disrupted because the latency of the CR processing is too high. This bug can be largely avoided by turning off echo, so that Tx is not occurring during Rx on the phone.
The second bug is more difficult to avoid. There seems to be a bug in the Tx buffer, which appears to wrap around when sending large amounts of data. For example, if you list > 40 messages, the data stream will have holes in it, resulting in lost data and a breaking of the comms protocol. If messages are processed and deleted as they come in, the number of messages on the phone will never be large enough to cause this problem. But there is no good fix for this bug.
Both of these bugs were found by using my ancient copy of ViewComm which only runs under DOS. This serial protocol analyser package has saved me in projects in the past, and enabled me to find these problems with the Nokia very quickly. I should have tried this before I got the scope out.
The software uses text mode to send / recieve messages from the phone. The command AT+CSCS= should allow the character encoding to be set, but the command does not work on my phone; the encoding stays set to "PCCP437" (PC code page 437) or "ibm437". I therefore use the ibm437 codec to convert from the nokia serial data to unicode. This may not match the default settings on your phone.
I still get occasional bad serial characters from the phone.
Related Links
* TuxMobil - Linux on laptops, PDAs and mobile phones . See also SMS
* PyMobile on Sourceforge
* Hacking the T616 in Python
* Gnokii - THE linux phone tools
* Siemens M35 as a modem
* CUTS - Remote execution of linux commands
Please help
I would like to get this software working with other phones. If anyone would like to help out with this, please get in touch. If it works on your phone, please let me know.