Saturday 30 April 2011

Send and Receive SMS with Python

I was thinking about writing a text-based game similar to the classic Fighting Fantasy books, but using SMS as the delivery mechanism. To do that I would need a way to send and receive SMS text messages to and from a server. As a challenge to see how that would work I wanted to write a prototype that would look like this:

CPU>>User: "Hello! What is your name?"
User>>CPU: "Fred"
CPU>>User: "Nice to meet you Fred"

The program itself is obviously easy. The problem is how to do the input and output over SMS. On to Google to see if I could find anything. Second link down on my first search I found the Active State code recipe 'Send and receive SMS messages using TextMagic'. It had a nice looking python package available. Reading the TextMagic website it seems that the only way to get started is to buy 200 SMS credits for £20. Hmm a little pricey as a barrier to entry.
I remember using Clickatell for this sort of thing ages ago. I took a look back at their site. The reality-check came in pretty quickly as Clickatell was going to cost minimum of €100 to set up and then €25 per month to run. So, back to TextMagic. And then I found out how to sign up for a free trial account!
With the free trial set up the next job was to set up the python environment. I use virtualenv to keep my python installation clean. To get started therefore created a new virtualenv.

$ virtualenv sms
$ source sms/bin/activate

I then installed the PyTextMagicSMS package.
$ sms/bin/easy_install PyTextMagicSMS
The first job was to try the sample sending program:

import textmagic.client
client = textmagic.client.TextMagicClient('your_username', 'your_api_password')
result = client.send("Hello, World!", "1234567890")

...which worked a treat. Obviously change the method parameters to match your settings.
So onwards to reading the Text Magic documentation to find out how to receive a reply. There are two ways of receiving a reply. Either you can poll your in-box to see what messages you have received, or you can set a callback URL to be notified of the response. The callback URL is clearly the way to go for anything of any complexity, but just to get started we will poll the in-box.

import textmagic.client
client = textmagic.client.TextMagicClient('name', 'pw')

received_messages = client.receive(0)
messages_info = received_messages['messages']
print('%d messages in in-box' % len(messages_info))
if len(messages_info) > 0:
first_message = messages_info[0]
print("Message from: %s" % first_message['from'])
print(first_message['text'])
client.delete_reply(first_message['message_id'])


Okay, so we're getting close to a solution. I'll have one program that sends the hello part of the conversation, a second program that checks the in-box for replies and then sends the final message. Here's the sending one...

import sys
import textmagic.client


client = textmagic.client.TextMagicClient('username', 'password')
no = sys.argv[1]

result = client.send("Hello! What is your name?", no)


...and here's the receiving one...

import textmagic.client
client = textmagic.client.TextMagicClient('username', 'password')

received_messages = client.receive(0)
messages_info = received_messages['messages']
print('%d messages in in-box' % len(messages_info))
if len(messages_info) > 0:
first_message = messages_info[0]
from_no = first_message['from']
name = first_message['text']
print("Message from: %s" % from_no)
print(name)

client.send("Nice to meet you %s!" % name, from_no)
print("I have sent a reply")
client.delete_reply(first_message['message_id'])


All this needs is a main loop round it to keep polling for input and we're done.

Friday 22 April 2011

Pennington Flash to Wigan Pier Bike Ride

Had a great bike ride with the whole family today. We went from Pennington Flash to Wigan Pier. We stopped at the Dover Lock Inn on both the way out and the way back. It even had a bouncy castle in the grounds.
The only down side was that the museum at the Wigan Pier end of the ride had closed down. That did rather mean that we got to the end of the ride and there was no where to get a nice ice cream.
Still, according to the Gmaps Pedometer we made a rather impressive 13.3 miles.