LightBlue: a cross-platform Python Bluetooth API

http://lightblue.sourceforge.net

Bea Lam <blammit@gmail.com>

LightBlue is a cross-platform Bluetooth API for Python which provides simple access to Bluetooth operations. It is available for Mac OS X, GNU/Linux and Nokia's Python for Series 60 platform for mobile phones.

Downloads are available below, or see the sourceforge project page for the full list of downloads.

Features

LightBlue provides simple access to:

See the online API documentation for more details.

The Mac OS X implementation also introduces LightAquaBlue, an Objective-C framework that enables the implementation of custom OBEX clients and servers. See the LightAquaBlue documentation for more details.

LightBlue is released under the MIT License.

Comments, suggestions, questions, etc. are most welcome and appreciated.


::: News :::

March 21, 08: Version 0.3.2 is out. This includes some major bug fixes:

February 17, 08: Version 0.3.1 is out:

February 3, '08: Version 0.3 is out! The major features of this release are:

October 16, '07: Version 0.2.3 is out:

August 21, '07: Version 0.2.2 is out:

March 22, '07: Version 0.2.1 (intended to fix PyS60 build issues, but didn't)

March 6, '07: Version 0.2 has been released! The changes for this version are:


::: Downloads :::

For Mac OS X:

Requires Python 2.3 or later, and at least Xcode 2.1 and Mac OS 10.4 for building the included LightAquaBlue .xcodeproj package. (For Xcode 1.5 and Mac OS 10.3 you can create a .xcode project yourself and build that; see the readme for some tips.)

To install:

  1. If you have Mac OS 10.4 or earlier, install PyObjC (required by LightBlue to access Objective-C libraries). (PyObjC is built into Mac OS 10.5.)
  2. Download the LightBlue source files and extract them to some directory. Open a Terminal window, change to that directory, and run the command python setup.py install

Or, if you need to run with root access, use sudo python setup.py install instead.

Along with installing the LightBlue python library, this also installs the LightAquaBlue Objective-C framework into /Library/Frameworks/.

Some things to note:

For GNU/Linux:

Requires Python 2.3 or later, with the BlueZ bluetooth stack and development libraries. (Tkinter must be included with Python to call selectdevice() and selectservice().)

To install:

  1. First, install PyBluez (0.9 or later) and OpenOBEX (1.3 or later)
  2. Make sure you have installed the python development package for your distro (e.g. python-dev on ubuntu) or else you will get compile errors.
  3. Get the LightBlue source files, extract and run the usual python setup.py install (or with root access, sudo python setup.py install)

For Python for Series 60:

Requires Python for Series 60 1.4 or later for PyS60 3rd Edition, or 1.3.1 or later for earlier editions. (If you don't have Python for Series 60, and don't know which version to get, this page makes it easy.)

To install:

  1. Download the appropriate SIS installer file for your Series 60 phone:
  2. Send the SIS file to your phone via Bluetooth, then open it and install it as a library. (Or, use the Nokia PC Suite to install it.)

Please let me know if there are any problems with these builds, because it's impossible to test them for all the different editions.

If you're interested, the LightBlue source files (tar.gz or zip) include the python and C++ extensions source code as well as MMP files etc. for recompiling everything.


::: Basic examples :::

Here are some examples of using the LightBlue API. Obviously, for the sake of simplicity, they assume lightblue has already been imported, like this:

    import lightblue
    

So to discover nearby devices and available services:

    >>> lightblue.finddevices()
    [('00:0E:6D:71:A2:0B', u'My6600', 5243396), ('00:0D:93:19:C8:68', 
    u'pantherbox', 1057028)]
    
    >>> lightblue.findservices('00:0D:93:19:C8:68')
    [('00:0D:93:19:C8:68', 10, 'OBEX Object Push'), ('00:0D:93:19:C8:68', 15, 
    'OBEX File Transfer'), ('00:0D:93:19:C8:68', 1, 'Bluetooth-PDA-Sync'),
    ('00:0D:93:19:C8:68', 3, 'Palm Serial Port')]

To ask the end user to select a device or service:

    >>> lightblue.selectdevice()      # brings up a device-selection GUI 
    ('00:0E:6D:71:A2:0B', u'My6600', 5243396)
    
    >>> lightblue.selectservice()     # brings up a service-selection GUI 
    ('00:0E:6D:71:A2:0B', 2, u'Bluetooth Serial Port')
    

To use RFCOMM socket objects:

    # client socket
    >>> s = lightblue.socket()
    >>> s.connect(("00:12:2c:45:8a:7b", 5))
    >>> s.send("hello")
    5
    >>> s.close()
    
    # server socket
    >>> s = lightblue.socket()
    >>> s.bind(("", 0))  # bind to 0 to bind to dynamically assigned port 
    >>> s.listen(1)
    >>> lightblue.advertise("My RFCOMM Service", s, lightblue.RFCOMM)
    >>> conn, addr = s.accept()
    >>> print "Connected by", addr
    Connected by ('00:0D:93:19:C8:68', 5)   
    >>> conn.recv(1024)
    "hello"
    >>> conn.close()
    >>> s.close()

To send and receive files over OBEX:

    # send a file (can pass file name or file object)
    >>> lightblue.obex.sendfile("00:12:2c:45:8a:7b", 10, "MyFile.txt")
    
    # receive a file and save it as MyFile.txt
    >>> s = lightblue.socket()
    >>> s.bind(("", 0))
    >>> lightblue.advertise("My OBEX Service", s, lightblue.OBEX)
    >>> lightblue.obex.recvfile(s, "MyFile.txt")  # or pass file object instead
    >>> s.close()
    

To run OBEX client sessions:

    # send a business card (vCard) to an Object Push service
    >>> client = lightblue.obex.OBEXClient("00:12:2c:45:8a:7b", 10)
    >>> client.connect()
    <OBEXResponse reason='OK' code=0x20 (0xa0) headers={}>
    >>> client.put({"name": "MyBusinessCard.vcf"}, file("MyBusinessCard.vcf", "r"))
    <OBEXResponse reason='OK' code=0x20 (0xa0) headers={}>
    >>> client.disconnect()
    <OBEXResponse reason='OK' code=0x20 (0xa0) headers={}>
    
    # get a directory listing from a File Transfer service
    # (see examples/obex_ftp_client.py for a basic File Transfer client implementation)
    >>> client = lightblue.obex.OBEXClient("00:12:2c:45:8a:7b", 15)
    >>> ftp_target_uuid = '\xf9\xec{\xc4\x95<\x11\xd2\x98NRT\x00\xdc\x9e\t'
    >>> client.connect({"target": ftp_target_uuid})
    <OBEXResponse reason='OK' code=0x20 (0xa0) headers={'connection-id': 327258,
    'who': '\xf9\xec{\xc4\x95<\x11\xd2\x98NRT\x00\xdc\x9e\t'}>
    >>> import StringIO
    >>> dirlist = StringIO.StringIO()
    >>> client.get({'type': 'x-obex/folder-listing'}, dirlist)
    <OBEXResponse reason='OK' code=0x20 (0xa0) headers={'length': 292}>
    >>> dirlist.getvalue()
    '<?xml version="1.0"?>\n<!DOCTYPE folder-listing SYSTEM 
    "obex-folder-listing.dtd"\n  [ <!ATTLIST folder mem-type CDATA #IMPLIED>\n  
    <!ATTLIST folder label CDATA #IMPLIED> ]>\n<folder-listing version="1.0">\n   
    <folder name="C:" user-perm="RW" mem-type="DEV" label="Phone memory"/>\n</folder-listing>'
    >>> client.disconnect()
    <OBEXResponse reason='OK' code=0x20 (0xa0) headers={}> 
        

To read local device information:

    >>> lightblue.gethostaddr()
    '00:0F:3D:5F:20:F0'
    >>> lightblue.finddevicename(lightblue.gethostaddr())  # get local device name
    u'susebox'
    >>> lightblue.gethostclass()    # class of device
    3670276

::: Other notes :::

Implementation

LightBlue's implementation uses native and third-party libraries on the three platforms, including:

Current limitations