Using A Bluetooth GPS From Python

Following on from my earlier posting on programming bluetooth from Python, I tried talking to a bluetooth GPS unit from Python.

I have a cheap MSI Starfinder SF100 bluetooth GPS that transmits NMEA format positioning information over a bluetooth socket. So, the first thing we have to do is to is to open a bluetooth socket.

import bluetooth
# bluetooth address of the GPS device.
addr = "00:08:1B:C2:AA:6D"
# port to use.
port = 1
# create a socket and connect to it.
socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
socket.connect((addr, port))

Fingers crossed we should now be connected to the GPS unit. In the real world we’d also be checking for exceptions to make sure we really have been able to connect, but this is just a simplified example.

Now we need to receive data from the GPS.

data = ""
while True:
data = socket.recv(1024)

Here we’re initialising a holding variable called data where the received data from the bluetooth socket goes, then we create an infinate loop and continually receive data from the bluetooth socket we creataed earlier.

We should now have some data coming in, so to test it we can just print it out.

print data

Here’s what we get back.

$GPRMC,225406.537,A,5046.3972,N,00017.
3365,E,0.00,,300107,,,A*7E
$GPGGA,225407.537,5046.3972,N,00017.3365,E,1,05,1.7,55.5,
M,,,,0000*33
$GPGSA,A,3,27,10,29,28,08,,,,,,,,3.9,1.7,3.5*35
$GPRMC,225407.537,A,5046.3972,N,00017.3365,E,0.00,,300107,,,A*7F
$GPGGA,225408.537,5046.3972,N,00017.3365,E,1,05,1.7,55.5,M,,,,0000*3C
$GPGSA,A,3,27,1
0,2
9,28,08,,,,,,,,3.9,1.7,3.5*35
$GPGSV,2,1,08,10,70,218,31,08,64,067
,35,29,49,287,30,27,37,058,40*70
$GPGSV,2,2,08,26,35,283,,28,34,133,45,24,27,254,22,21,12,324,*72
$GPRMC,225408.537,A,5046.3972,N,00017.3365,E,0.00,,300107,,,A*70
$GPGGA,225409.537,5046.3972,N,00017.3365,E,1,06,1.4,55.5,M,,,
,0000*3D

Oh dear, although we are receiving data over the bluetooth socket, it’s in random packet sizes. The NMEA data we want is sent in lines terminated with a carriage return and a line feed. So how can we get the data in this format?

Well we need to use Python’s string manipulation methods. We can use the splitlines method to split the data into a list of lines. As we can’t be sure we have a complete line at the end of the list we need to check there is a carriage return and linefeed there. By default splitlines helpfully removes these, so we need to tell it to keep them in place, after all we can use the strip method later to remove them manually. So all we need to do now is to check the last line in the list has the carriage return and linefeed, if it doesn’t we need to make sure the next data received from the bluetooth socket is appended to the end before we repeat the process again. Imagine we create a holding variable called olddata at the same time as data and this is to hold a copy of the last line. Here’s the code…

# make sure we actually have some data.
if len(data) > 0:
# append the old data to the front of data.
data = olddata + data
# split the data into a list of lines, but make
# sure we preserve the end of line information.
lines = data.splitlines(1)
# iterate over each line
for line in lines:
# if the line has a carriage return and a
# linefeed, we know we have a complete line so
# we can remove those characters and print it.
if line.find("rn") != -1 :
line = line.strip()
print line
# empty the olddata variable now we have
# used the data.
olddata = ""
# else we need to keep the line to add to data
else :
olddata = line

We now have some useful data coming in…

$GPRMC,225406.537,A,5046.3972,N,00017.3365,E,0.00,,300107,,,A*7E
$GPGGA,225407.537,5046.3972,N,00017.3365,E,1,05,1.7,55.5,M,,,,0000*33
$GPGSA,A,3,27,10,29,28,08,,,,,,,,3.9,1.7,3.5*35
$GPRMC,225407.537,A,5046.3972,N,00017.3365,E,0.00,,300107,,,A*7F
$GPGGA,225408.537,5046.3972,N,00017.3365,E,1,05,1.7,55.5,M,,,,0000*3C
$GPGSA,A,3,27,10,29,28,08,,,,,,,,3.9,1.7,3.5*35
$GPGSV,2,1,08,10,70,218,31,08,64,067,35,29,49,287,30,27,37,058,40*70
$GPGSV,2,2,08,26,35,283,,28,34,133,45,24,27,254,22,21,12,324,*72
$GPRMC,225408.537,A,5046.3972,N,00017.3365,E,0.00,,300107,,,A*70
$GPGGA,225409.537,5046.3972,N,00017.3365,E,1,06,1.4,55.5,M,,,,0000*3D

As you can see the NMEA strings are simply comma seperated blocks of data.

The most useful string is the one with the actual position in. This string is the one starting with $GPRMC. If we look out for this line and split it’s data, we can get our latitude and longitude and use it as we please.

gpsstring = line.split(',')
if gpsstring[0] == '$GPRMC' :
print "Lat: " + gpsstring[3] + gpsstring[4]
print "Long: " + gpsstring[5] + gpsstring[5]

This gives us…

Lat:  5046.3972N
Long: 000017.3365

Which translates to 50 deg 46.3972′ N and 0 deg 17.3365 E.

There you have it, it’s time to start geocoding you data.

Programming Bluetooth Using Python

I discovered the pybluez project that brings bluetooth connectivity to Python today. It’s been around for a while and is compatible with both Windows (running XP) and Linux (running the bluez stack).

I installed it using the ready made windows installer and it ran first time. It’s very simple and easy to use.

I tweaked the example inquiry.py file by Albert Huang and set it up to show all the services on nearby devices.

Here’s the code…

import bluetooth
print "looking for nearby devices..."
nearby_devices = bluetooth.discover_devices(lookup_names = True, flush_cache = True, duration = 20)
print "found %d devices" % len(nearby_devices)
for addr, name in nearby_devices:
print " %s - %s" % (addr, name)
for services in bluetooth.find_service(address = addr):
print " Name: %s" % (services["name"])
print " Description: %s" % (services["description"])
print " Protocol: %s" % (services["protocol"])
print " Provider: %s" % (services["provider"])
print " Port: %s" % (services["port"])
print " Service id: %s" % (services["service-id"])
print ""
print ""

Here’s a quick run through of the code.

Firstly we need to import the bluetooth class to give us access to all that lovely bluetooth functionality.

We now look for nearby devices using bluetooth.discover_devices. I’m adding a few parameters as well. lookup_names is set to True so we can get the devices names instead of the just their addresses, and flush_cache is also set to True to make sure we always look for fresh information. Finally we set duration to 20, meaning we look for devices for up to 20 seconds. This is a bit excessive, but useful when testing.

We should have a list of devices now, assuming some were found, so we now loop over them.

We print out the name and address then look for services offered by the device by calling the bluetooth.find_service method and passing in the device’s address.

This returns a list of dictionaries describing the services available. We iterate over this and print out details.

That’s the code, now here’s a few results. I ran this on the train home and discovered 7 active bluetooth devices offereing a variety of services. I won’t bore you with them all, so here’s the entry for my Nokia N93.

Perl - 00:16:BC:30:D8:76
Name:        AVRCP Target
Description: Audio Video Remote Control
Protocol:    L2CAP
Provider:    Symbian Software Ltd.
Port:        23
Service id:  None
Name:        Hands-Free Audio Gateway
Description:
Protocol:    RFCOMM
Provider:    None
Port:        28
Service id:  None
Name:        Headset Audio Gateway
Description:
Protocol:    RFCOMM
Provider:    None
Port:        29
Service id:  None
Name:        SyncMLClient
Description:
Protocol:    RFCOMM
Provider:    None
Port:        10
Service id:  None
Name:        OBEX File Transfer
Description:
Protocol:    RFCOMM
Provider:    None
Port:        11
Service id:  None
Name:        Nokia OBEX PC Suite Services
Description:
Protocol:    RFCOMM
Provider:    None
Port:        12
Service id:  None
Name:        SyncML DM Client
Description:
Protocol:    RFCOMM
Provider:    None
Port:        13
Service id:  None
Name:        Nokia SyncML Server
Description:
Protocol:    RFCOMM
Provider:    None
Port:        14
Service id:  None
Name:        OBEX Object Push
Description:
Protocol:    RFCOMM
Provider:    None
Port:        9
Service id:  None
Name:        Dial-Up Networking
Description:
Protocol:    RFCOMM
Provider:    None
Port:        2
Service id:  None
Name:        Imaging
Description:
Protocol:    RFCOMM
Provider:    None
Port:        15
Service id:  None

As you can see it offers a lot of interesting services, but two have caught my eye and call for a bit more investigation later.

Firstly there is the Imaging service on port 15. I wonder what that does? Does it take input from a remote camera?

Secondly there is AVRCP Target the Audio Visual Remote Control Target from Symbian. I wonder if this means I can use a seperate bluetooth device to control my Nokia N93 when it’s playing back video?

A quick google reveals a (confidential?) specification document for AVRCP

Nokia Lifeblog Posting Protocol Update

Nokia seem to have updated their Atom upload protocol in recent versions of their phones.

I’ve just got hold of a Nokia N93 and tried posting to this blog using Lifeblog and the new Web Upload functionality in the Gallery with use the Atom protocol.

These postings were failing with a bad password error. I know my username and password are correct and they worked using my old phone.

As I had written my own blogging software, and it’s Atom upload functionality I was able to debug the messages being sent from the phone to the server.

It turns out that newer versions of Nokia Lifeblog encrypt their passwords differently to older versions.

They use a method called WSSE. See my previous article on how to use WSSE with Perl for more details on how this works, plus example code.

Very quickly, the password isn’t sent, but a digest of the password and the values to generate the digest yourself are. These are then encoded using base64 for transmission over the internet.

Older versions (pre Lifeblog 2.0) expect a value called the nonce to be used as sent while the password digest is generated. Newer versions (Lifeblog 2.0+) expect the nonce to be decoded from base64 before the digest is generated.

Once I had worked out what was going on, it was simple to modify my code to check against both possible versions of the password digest. This means I can now post using old and new versions of Lifeblog, or the web upload functionality.

Here’s a very quick bit of example Perl code. Assume $my_digest is the digest with the original nonce left in place and $my_alternative_digest is the digest with the nonce decoded first. $digest is the digest sent my incoming Atom request.

## example perl code to check digests)
if (($digest eq $my_digest) || ($digest eq $my_alternative_digest)) {
## one of the digests has validated, so continue here
} else {
## neither digests has validated, so return invalid password responses here.
}

I don’t think this change has been communicated very well amongst the development community. It has probably come about due to changes in the Atom spec, but (admittedly only quickly) checking the documentation I’ve not found it.

I will be updating my WSSE validation example accordingly, and a new version of AtomServer.pm that allows posting from Lifeblog 2.0 to Movable Type shortly.

Posting To Movable Type 3.3 Using Nokia Lifeblog

We’ve been installing Movable Type as a blogging solution at work for various sites recently.

We’d been using Typepad, the hosted version of Movable Type for a while, but wanted some extra flexibility and functionality.

One problem we came across was the lack of support for Nokia Lifeblog on Movable Type, compared to Typepad.

Thankfully Martin Higham has worked on this in the past, and even used my old notes on the Nokia Lifeblog Posting Protocol.

However, the current version of Movable Type is 3.3, and Martin’s work only extends to 3.2.

I took Martin’s code, which modifies AtomServer.pm and modified it so it works on Movable Type 3.3. You can download my Nokia Lifeblog compatible AtomServer.pm for Movable Type 3.3 here.

Make sure you follow Martin’s instructions for Movable Type 3.2 as the method is exactly the same and the same caveats apply (namely, this could well break other Atom tools that use your blog as it has to disable some WSSE authentication).

I hope you find it useful!

UPDATE: 22nd November 2006

With version 2.0 of Lifeblog and web upload functionality from Nokia phones, the authentication method has changed slightly. A new version of AtomServer.pm that works with Lifeblog 2.0 is now available.

UPDATE: 26th June 2007

Neils Berkers has been in touch to say he’s adapted the script so it now works with Movable Type 3.35, Lifeblogging Fixed.

iTunes Auto Updating Now Playing in VB2005

Previously I’ve covered how to link into the iTunes COM library from VB 2005 to show now playing information. This article assumes you have already read that, or have it to hand.

Taking this application further, wouldn’t it be useful for our application to automatically update itself when a track changes takes place on iTunes?

Well I hope you are saying yes, as it’s what I’m going to cover now.

iTunes can inform our application of changes of track if we choose to listen for it’s OnPlayerPlayEvent event.

If you are not sure what an event is, it’s basically a way for one program to tell another that something has happened in that program and the other program may wish to react to it. In this case, a different track has started playing in iTunes.

So how can we get our application to listen out for this? Well firstly we need to say that our programme is interested in these events. We do this by using VB 2005’s WithEvents keyword when we create our interface into iTunes.

So previously we did this using the following code.

Dim app As New iTunesApp()

Now we have to add in the WithEvents keyword as follows.

Private WithEvents app As New iTunesApp

Now our program can listen out for events from iTunes. You may have noticed I’ve changed Dim to Private. This is because for this example I’m going to use a Windows Application and not a Console application as before.

Next we have to create our event handler so we can react to the events iTunes is sending us.

The easiest way to do this is use the method generator at the top of the code view in Visual Basic 2005 Express Edition. My iTunes object is called app so we select this, then OnPlayerPlayEvent to create our event handler stub.

Creating an iTunes event in VB2005

This passes in the variable iTrack as an Object. We know this is really an IITTrack object, so we need to cast it as such.

Dim track As IITTrack
track = CType(iTrack, IITTrack)

This creates a new varible called track and casts the existing iTrack variable as an IITTrack using CType.
Doing this, we have easy access to the track data passed to us by iTunes in the event.
We need to do something with this information seeing as we’ve gone to all the trouble of asking iTunes for it. The easiest thing to do is to just display a small window with the name of the current track.

MsgBox(track.name)

Obviously this is a simplified version of a real program, but it should give you an idea of how to get events from a remote program into your VB2005 application.

iTunes Now Playing in VB 2005

As I’ve been using VB 2005 a lot more a work the past few weeks, I thought I’d rewrite my iTunes Now Playing console app in VB.

It does the same as the previous C# example, and again I’ve chosen to use the free version of the language and Microsoft’s Visual Basic 2005 Express Edition.

The first thing to do, is to make sure you have downloaded the iTunes SDK from Apple.

In Visual Basic, create a new Console Application. We need to add a reference to the iTunes COM library, so we do this by right clicking over our application in the Solution Explorer, and selecting “Add Reference…”. Select the COM tab, and scroll down to find the iTunes library. Mine was called “iTunes 1.7 Type Library”.

adding the iTunes COM object to VB 2005

Now for some code.

Firstly, like all good programmers we turn on VB’s strict mode to make sure we’re not using too many bad programming practices.

Option Strict On

Next we need to import the libraries we want to use. In this case, System> and iTunesLib.

Imports System
Imports iTunesLib

As we’ve created a Console App in VB, we can just drop the following code into the Main sub.

Firstly we need to create an iTunesApp object so we can get talk to iTunes. After that we need to get the current track.

Dim app As New iTunesApp()
Dim track As IITTrack = app.CurrentTrack

We should now have the details of the current track in the track object so we just need to print these to the console.

Console.WriteLine("Current Track: {0}", track.Name)
Console.WriteLine("Current Artist: {0}", track.Artist)

Finally, just so we can see the result we need to wait for the user to press return before we exit.

Console.ReadLine()

Fire up iTunes if it’s not already on and start a track playing. Now start your VB program, and it should tell you the current track title and artist as shown below.

iTunes now playing script

It’s as simple as that. Obviously I’m not checking for exceptions and errors as this is just an basic example.

Your final code should look something like this.

Option Strict On
Imports System
Imports iTunesLib
Module Module1
Sub Main()
Dim app As New iTunesApp()
Dim track As IITTrack = app.CurrentTrack
Console.WriteLine("Current Track: {0}", track.Name)
Console.WriteLine("Current Artist: {0}", track.Artist)
Console.ReadLine()
End Sub
End Module

Homebrew Remote Switch For Canon EOS-350D

I’ve found myself needing a remote switch for my Canon EOS 350D camera recently. The official Canon product is the RS-060E3, but at 25 UKP that seems a bit steep.

A quick search on Google, and I came across Chantal Currid’s page on making your own remote control.

It turns out it’s actually really simple to build my own, so that’s exactly what I’ve done.

The EOS 350D uses a 2.5mm stereo socket, the three connections being ground, shutter control and auto focus control.

A quick trip down to the radio studios are work produced an old stereo cable from their junk box. This had a 3.5mm stereo jack plug on it. Next was a trip to Maplin on Great Portland Street where I bought a 3.5mm to 2.5mm adaptor plug, a handheld box, a red push to make button, a black push to make button and a toggle switch.

components

The wiring is simple, and details are on Chantal’s page on the theory of operation.

The toggle switch is used to latch the auto focus. The black push button is a momentary connection to the auto focus for when we don’t want to use the latch. The red push button is used to trigger the shutter release. If the toggle switch is on, this keeps the shutter open until the toggle is switched back. Very handy for those long “bulb” exposures.

Here’s the wired up box.

wired up canon switch

And here’s the final finished (and working) remote switch.

finished switch 1

finished switch 2

finished switch 3

finished switch 4

It should be possible to do more interesting stuff with this. How about one of Maplin’s IR beam kits, that we can use to trigger a shot if an invisible IR beam is crossed? Or even fitting in one of their remote control units? There are a lot of cool ideas to try.

iTunes Now Playing In Perl

After working on the C# iTunes Now Playing program, I thought I’d give the Perl Win32::OLE module a try.

This module is Activestate Perl‘s COM interface for Microsoft Windows.

After using Perl for nearly 8 years, I’ve never given it a try before, and it turns out to be surprisingly easy to use.

The following script works exactly the same way as the C# version.

Firstly we need to create a new iTunes.Application object.

my $iTunesApp = new Win32::OLE("iTunes.Application");

Next we get the current track and print the name and artist.

my $track = $iTunesApp->CurrentTrack;
print "Current Track: " . $track->Name . "nCurrent Artist: " . $track->Artist . "n"

And that’s it. Obviously we should be checking to make sure the objects were create correctly, but this is just a simple example, not live code.

So to recap, here’s the final working example code.

#!/usr/bin/perl

use strict;
use Win32::OLE;

my $iTunesApp = new Win32::OLE("iTunes.Application");
my $track = $iTunesApp->CurrentTrack;

print "Current Track: " . $track->Name . "nCurrent Artist: " . $track->Artist . "n"

iTunes Now Playing In C#

I’ve been playing about with the COM interface to Apple’s iTunes running on a windows machine with .NET installed.

My choice of language has been C# as it’s a bit more Perl like than VB. I’ve used Microsoft’s “free” Visual C# Express in this case.

The iTunes SDK is available from Apple and has all the documentation needed.

I’m going to run through how to get Now Playing information out of iTunes. The quickest way to do this is as a console application.

Start up Visual C# and create a new console application. I called mine NowPlaying.

You’ll need to add a reference to the iTunes come library. Do this on the righthand side of the C# project window by right clicking and selecting “Add Reference…”, selecting the COM tab, and finding the iTunes library.

The first thing you’ll need to in your code is to import the iTunes namespace to make the code look a little cleaner. We’ll also need the System interface for our console input and output.

using System;
using iTunesLib;

In your Main method, the first thing we need to do is to create an instance of the iTunesAppClass. I’ve rather originally called mine, app.

// Create a new iTunesApp object to use
iTunesApp app = new iTunesAppClass();

Next we need to get the current track. This is a simple attribute call to the app object.

// Get the current track from iTunes.
ITTrack track = app.CurrentTrack;

Finally we need to show the current track. To do this we call two attributes on our track variable, name and artist. There are plenty of other attributes we could call, but these are the two most useful for this example. See the SDK for more choice.

Once we have displayed our name and artist, we need to wait for the user to hit return. This is useful if our program wasn’t launched from a console window as it would end before we’ve had a chance to read any output.

// Display some info on the current track.
Console.WriteLine("Current Track: {0}rnCurrent Artist: {1}" , track.Name, track.Artist);
// Pause until we hit return.
Console.ReadLine();

That’s it, nice and easy.

Here’s the full .cs source code.

using System;
using iTunesLib;
namespace NowPlaying
{
class Program
{
static void Main(string[] args)
{
// Create a new iTunesApp object to use
iTunesApp app = new iTunesAppClass();
// Get the current track from iTunes and return its artist and name.
IITTrack track = app.CurrentTrack;
Console.WriteLine("Current Track: {0}rnCurrent Artist: {1}" , track.Name, track.Artist);
// Pause until we hit return.
Console.ReadLine();
}
}
}