Retrieving SMS via Bluetooth from a K700i Phone
January 3rd, 2006
Documentation is sparse on the web on actually talking to your phone, so here’s a little guide to extract your SMS from a bluetooth phone, decode them, and send them out via email.
Components (ie. required):
- a Sony Ericsson K700i (other Sony Ericsson’s should work - but I have none at hand to test them)
- Python
- A linux system with a running bluez stack (and an appropriate bluetooth dongle) (I used debian)
- AT Command reference for the K700i - available from http://developer.sonyericsson.com/
- Bluetooth (bluez) support for python
Â
From small to even more bloody detailed…
AT commands were used back in the day to talk to modems (way before broadband ever was)… modern day cell phones still speak them, and they’re the easiest way to talk to your phone.
Bluetooth requires devices to be coupled. You’ll also need to know your phone’s bluetooth address. So turn on bluetooth on your phone and execute ‘hcitool scan’ in your shell.
You should see a line like 00:12:EE:55:10:F2Â Â Â Â Â Â Name of your phone
00:12:EE:55:10:F2Â would be your address. Note that for later.
Now, we’ll talk to your phone via bluetooth.
Fire up python, type the following.
from bluetooth import *;
s = BluetoothSocket (RFCOMM)
strAddr = “00:12:EE:55:10:F2″
x = s.connect ( ( strAddr , 2) ) # 2 is the channel. This might change from phone to phone.
s.send(”AT\r\n”)
print s.recv(1000)
you should get an ‘AT\r\nOK’ back.
If your phone wants you to pair, and you don’t know the pin, you might need to dig through your bluez settings.
On a shell only (no X) debian system, the standard pin tool bluez-pin won’t work (it requires GTK). I wrote a quick “echo PIN:1234″ shell script and (after chmod +x) set that in /etc/bluetooth/hcid.conf as my pin_helper
Now to getting your messages
Step 1
Choose the appropriate phone memory (SIM or built in).
The command in question is AT+CPMS=”ME” (don’t forget the newlines when sending!).
Step 2
Ask for all SMS - AT+CMGL=4.
Step 3
Get mad because your recv() returns without the phone having send all data.
Step 4Â
Learn about select(). Then define your own wrapper
def readFromSock (s):
   i = [s]
   w = []
   e = [s]
   out = ”
   while True:
       ir, wr, er = select.select(i,w,e,3)
       if len(ir) == 0:
          break
       if len(er) > 0:
           break
       out += i[0].recv(1000)
       if (out.find(”OK\r\n”) != -1):
           return out
   return out
Step 5
Wonder at what gibberish you’re getting back.
No worries - the phone is dutifully returning all your SMS. Unfortunatly, they’re encoded in a format called PDU, defined in GSM 03.40 and GSM 03.38. Now there are some examples for pdu decoding out there. But still, it’s a headache ;-).
Koders.com, an open source code search engine, to the rescue:
I found a basic gpl’ed SMS decoder class written by a guy called Dominik Pytlewski.
It worked for some SMS., but it failed on some others, particulary outgoing SMS.
Attached you’ll find an improved version that seems to handle all my SMS ok. (out of sheer paranoia, I still store the PDU with every message, just in case of a decoding error).
Step 6
Explode output on “CMGL: “, strip, seperate body and header (message id - you’ll need this later to delete a particular message), turn into SMS decoder objects. Save the message id along with the decoded SMS.
Step 7
I split my messages into incoming and outgoing messages - but that’s just because the phone doesn’t provide a date for outgoing message, and I use a seperate deletion scheme for them.
Step 8
Do some clever ‘have I seen this message before’ caching (basically: Store last 1000 messages in PDU and use them as they keys for a dictionary. If has_key(), don’t bother mailing this message again)
Step 9
Assemble messages into a mail text, use smtplib to mail them wherever you like. Look up numbers from the cell’s phone book (retrieve (lazy evaluation) via AT+CPBS=”ME” (memory) and AT+CPBR=1,255 (get phonebook). Then split and store in a dictionary. Finally, look the phone numbers up (beware - they might be stored with a 0, but you get the international (+xy) number . Or the other way around. Think up some heuristic. Personally, I try both variants, then I remove the first three characters and search for a string match ).
Step 10
Decide which SMS you want to remove from the phone (I delete incoming SMS after seven days and keep only 10 sent SMS. But that’s a configuration option in the other attached file - blueMailSuck.py. Yeah, that’s what it does. It sucks SMS from your phone ;-).
Step 11
For each SMS to remove, send a AT+CMGD=message_id.
Step 12
Play a neat sound on the phone (AT+CRMP=5,0,1 for the alarm sound). I’d have displayed an image during the procedure, but apperantly the AT*EAPP command is broken and interprets only 4 letters of the text to pass in. Stupid if you *need* to specify a folder like images/whatever. (If you were playing the sound before another command, make sure to use socket.recv() instead of the select() version - otherwise your select will timeout and you’ll send the next command before the phone is ready).
I believe that’s pretty much it…
Feedback of course is always welcome.
So long,
Flo
Attached files:
ey thats pretty neat =) i got the same mobile phone…but i need this for windoze!
*starts digging*
You’ll need to find a way to talk rfcomm in windows.
Easiest option probably to bind a com port to rfcomm channel two, and then talk via that.
Do that, then try to use hyperterminal (start/accessories/communication), open the com port, and say AT[Enter].
If you can read an ‘OK’, we can modify the python to read from that instead of via the bluez stack.
Too cool you’re writing about this =) I got my new W800i just on Friday, and this is the perfect motivation to get this bluetooth dongle I have to work with Linux. It’s the cheapest model you can find on eBay, shipped from Hongkong… but I hope it’ll do. Maybe I’ll like the Linux way better than the (horrible) Windows software too.
And I can’t believe mas hasn’t yet put his hands on a Linux CD.?;) Kanotix and Ubuntu are pretty good if you want to give one a try.
Btw, if you ever loose your bluetooth connection (perhapes because of a k700i reset, whatever) and need to reset your link key, you’ll need to remove /var/bluetooth/baddr_of_your_dongle(looks like XX:YY:ZZ:TT)/linkkey.