Homework 1

Python and
Bluetooth

Modified

Resources

Overview

Bluetooth is a wireless protocol for local communications.

Python is a simple but powerful language that comes with many of the fundamental tools needed for quickly programming locally networked applications.

While many similarities exist between Internet and Bluetooth protocols, one key difference is that Bluetooth devices move in and out of radio frequency range. Normally, before commencing communication, devices must discovery others to detect the address and services that are provided by other devices.

Bluetooth Stack

Microsoft Vista provides a Bluetooth stack that can enabled through the Control Panel.

Broadcom devices, such as those in LF115, are also supported by the more reliable and robust Widcomm drivers.

 

Windows Bluetooth programming

PyBluez

A Python Bluetooth library for the Windows and GNU/Linux operating systems. Mac OSX and Linux Python are supported by LightBlue, a number of cell phones running the Symbian OS are supported under Python. The following examples use the PyBluez bluetooth library.

Discovery

The address and name of enabled devices within range can be discovered by other Bluetooth devices. Discovery can take some time to complete, given that radio communications is unreliable. The following displays address and name of all enabled devices nearby.

from bluetooth import *

print "performing inquiry..."

nearby_devices = discover_devices(lookup_names = True)

print "found %d devices" % len(nearby_devices)

for name, addr in nearby_devices:
     print " %s - %s" % (addr, name)

performing inquiry...
found 2 devices
Ray's Nokia - 00:12:D2:5A:BD:E4
Ray's MacBook - 00:1E:C2:93:DA:6F

RFCOMM service

Because RFCOMM is a connection-oriented protocol, similar to TCP, one process acts as a server accepting connections, another process acts as the client requesting the connection.

Below are basic client and server scripts, to keep things simple, we manually entered the Bluetooth device address (00:12:D2:5A:BD:E4) of the server (much like with the Internet) and a port; in the following, the client connects to the server on port 3.

Note: in the Client below, when connected to a server on a Nokia cell-phone, closing the client_socket immediately after sending data may result in a run-time error on the server. The client print statement adds time to prevent an immediate client close that would cause the server to occasionally crash!

Client

from bluetooth import *

# Create the client socket
client_socket=BluetoothSocket( RFCOMM )

client_socket.connect(("00:12:D2:5A:BD:E4", 3))

client_socket.send("Hello World")

print "Finished"

client_socket.close()

Server

from bluetooth import *

server_socket=BluetoothSocket( RFCOMM )

server_socket.bind(("", 3 ))
server_socket.listen(1)

client_socket, address = server_socket.accept()

data = client_socket.recv(1024)

print "received [%s]" % data

client_socket.close()
server_socket.close()

 

Try

Note that only one instance of IDLE can be open at a time.

  1. Save the above files as:
    • client.py
    • server.py
  2. Open two Command Prompt windows.
  3. Change the directory to the location of the Python files.
  4. Enter:
    • python server.py
    • python client.py

 

Example: Echo client and server

# echoclient.py

import sys
from bluetooth import *

HOST = sys.argv[1]       # The remote host
PORT = 8888                 # Server port

s=BluetoothSocket( RFCOMM )

s.connect((HOST, PORT)) while True : message = raw_input('Send:') if not message : break s.send(message) data = s.recv(1024) print 'Received', `data` s.close()
# echoserver.py 

from bluetooth import *

HOST = ''          # Symbolic name
PORT = 8888     # Non-privileged port
s=BluetoothSocket( RFCOMM )

s.bind((HOST, PORT))
s.listen(1)

conn, addr = s.accept()

print 'Connected by', addr
while True:
    data = conn.recv(1024)
    if not data: break
    conn.send(data)
conn.close()

Try

Note that only one instance of IDLE can be open at a time.

  1. Save the above files as:
    • client.py
    • server.py
  2. Open two Command Prompt windows.
  3. Change the directory to the location of the Python files.
  4. Enter the following, note the address of the server is read from the command line:
    • python echoserver.py
    • python echoclient.py 00:12:D2:5A:BD:E4

 Example: echoclient and echoserver as functions

# echoclient.py
import sys
from bluetooth import *

def client( host, port) :
   s=BluetoothSocket( RFCOMM )
s.connect((host, port)) while True : message = raw_input('Send:') if not message : return s.send(message) data = s.recv(1024) print 'Received', `data` s.close()
client(sys.argv[1], 8888)
# echoserver.py 

from bluetooth import *

def server( s ) :
   conn, addr = s.accept()
   print 'Connected by', addr

   while True:
       data = conn.recv(1024)
       if not data: break
       conn.send(data)
   conn.close()
s=BluetoothSocket( RFCOMM )
s.bind(('', 8888))
s.listen(1)
server( s )

 

Using Service Discovery Protocol (SDP)

We have seen that Bluetooth devices can locate other nearby devices, those that are in discovery mode. Rather than connecting by the address and port of a device and application, devices can discover the address and port by the service name.

The following versions perform the same function, sending 'Hello world' from a client to a server, as earlier examples but using SDP. On the server-side, the primary use of SDP to advertise the helloService as a serial port or RFCOMM protocol.

The client first finds a list of devices that provide the helloService (in reality, more than just helloService is returned). The list is then searched for the helloService, when found, the associated host address and port are used to connect to the service.

Client
from bluetooth import *

services=find_service(name="helloService",
                            uuid=SERIAL_PORT_CLASS)

for i in range(len(services)):
   match=services[i]
   if(match["name"]=="helloService"):
      port=match["port"]
      name=match["name"]
      host=match["host"]

      print name, port, host

      client_socket=BluetoothSocket( RFCOMM )

      client_socket.connect((host, port))

      client_socket.send("Hello world")

      client_socket.close()

      break
Server
import bluetooth

server_sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )

server_sock.bind(("",bluetooth.PORT_ANY))
server_sock.listen(1)

bluetooth.advertise_service(server_sock, "helloService",
                     service_classes=[bluetooth.SERIAL_PORT_CLASS],
                     profiles=[bluetooth.SERIAL_PORT_PROFILE])

client_sock, address = server_sock.accept()
print "Accepted connection from ",address

data = client_sock.recv(1024)
print "received [%s]" % data

client_sock.close()
server_sock.close()

 

 

Try

Note that PyBluez does not discover services using the Widcomm stack nor is an address of 'localhost' allowed.

The following assumes using the two PCs as client and server.

  1. Save the above helloServiceClient.py file and the PyBluez helloServiceServer.py file to different PCs.
  2. Run the helloServiceServer.py file.
  3. Run the helloServiceClient.py file.

 

 

Symbian Bluetooth programming

Python S60

Python includes a Bluetooth library on the Symbian S60 operating systems. The following examples use Python for the Symbian OS.

Discovery

The address, services and ports used of enabled devices within range can be discovered by other Bluetooth devices. When the following script is run, device names are automatically displayed. The selected device address, services and ports are then displayed.

Note that the results can be erratic, even crashing the Python interpreter.

import socket

print "\n\nperforming inquiry..."

address, services = socket.bt_discover()

print "Address: %s" % address

for name, port in services.items():
     print u"%s : %d" % (name, port)

 

RFCOMM service

Because RFCOMM is a connection-oriented protocol, similar to TCP, one process acts as a server accepting connections, another process acts as the client requesting the connection.

Below are basic client and server scripts, to keep things simple, we manually entered the Bluetooth device address (00:12:D2:5A:BD:E4) of the server (much like with the Internet) and a port; in the following, the client connects to the server on port 3. The address and serial port number can be determined by running the above discovery script.

Client

import socket

client_socket=socket.socket(socket.AF_BT,socket.SOCK_STREAM)

client_socket.connect(("00:18:F8:89:8B:A5",1))

client_socket.send("Hello World")

client_socket.close()

Server

import socket

server_socket=socket.socket(socket.AF_BT, socket.SOCK_STREAM)

socket.set_security(server_socket, socket.AUTH)

port = socket.bt_rfcomm_get_available_server_channel(server_socket)

server_socket.bind(("", port))
server_socket.listen(1)

client_socket, address = server_socket.accept()

data = client_socket.recv(1024)
print "received [%s]" % data

client_socket.close()
server_socket.close()

 

Try

Note that only one instance of Python can be open at a time on the phone.

The following assumes using the phone as client and a PC as server.

  1. Modify the address in client.py file to that of the PC Bluetooth device.
  2. Save the above client.py file to the phone and the PyBluez server.py file to a PC.
  3. Start Python on the phone and IDLE on the PC.
  4. Change to the PC directory to the location of the Python server.py file.
  5. On PC, enter:
    • python server.py
  6. On the phone, choose Option and Run Script, selecting client.py file.