先安裝好blue-tooth 的套件
sudo apt-get update
sudo apt-get install bluetooth bluez-utils blueman bluez python-gobject python-gobject-2
sudo apt-get install python-bluez
sudo hciconfig hci0 piscan [make your device discover-able]sudo hciconfig hci0 name 'Device Name'
接下來這個動作很重要....因為bluetooth有bug... 需要用一個workaround的方式
Disable bluetooth pnat support as there seems to be a bug which stops proper operation with pnat enabled. Full details can be found here: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=6907492A workaround is to add the following to /etc/bluetooth/main.conf:
如果上面的事情沒有做...就會產生下面的error message(111, 'Connection refused')
接著開始啟動藍牙:
確認作業系統是否有抓到藍牙裝置。
lsusb
確認藍牙裝置接收器已被啟動。
hciconfig
可以看得出來目前的藍芽裝置只有一個, 就是 hci0....
dev_addr 為 00:1A:7D:DA:71:04
一些小工具....hcitool scan...可以掃描附近的藍芽裝置
接下來就是重頭戲...開始來寫programming...
請參考ref 1.. Chapter 3
It is written for the Windows XP (Microsoft Bluetooth stack) and GNU/Linux (BlueZ stack)
Bluetooth programming with Python - PyBluez
chapter 3.1
findmyphone.py
import bluetooth target_name = "chifc iphone" target_address = None nearby_devices = bluetooth.discover_devices() for bdaddr in nearby_devices:
print bluetooth.lookup_name( bdaddr ) # for debug used if target_name == bluetooth.lookup_name( bdaddr ): target_address = bdaddr break if target_address is not None: print "found target bluetooth device with address ", target_address else: print "could not find target bluetooth device nearby"
從上面的例子來看....他使用了 bluetooth 的library...
呼叫 bluetooth.discover_devices() 來找到最近的 devices....
接著用一個for loop.....來找名字是 "My Phone" 的target...
最後判斷 target_address是不是NULL....如果不是...代表找到了
我用我的手機打開藍芽... 手機名稱為 chifc iphone.....掃到第二個裝置就找到了 ....
同時印出target address
至於iphone怎麼修改名稱 .... 設定>一般>關於本機>名稱
chapter 3.2 Communicating with RFCOMM
Example 3-2. rfcomm-server.py
import bluetooth server_sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM ) port = 1 server_sock.bind(("",port)) server_sock.listen(1) 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()
接下來就是傳送資料Example 3-3. rfcomm-client.pyimport bluetooth bd_addr = "01:23:45:67:89:AB" # here need to modify. use hciconfig to get address port = 1 sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM ) sock.connect((bd_addr, port)) sock.send("hello!!") sock.close()這邊有兩個 code...一個是server...一個是client..在server 端呼叫 server_sock.accept()來得到client_socket 和 address然後再由client_socket來得到傳送的datadata = client_sock.recv(1024)在client端就是寫一個傳送的test code...首先先指定對方的address ..."01:23:45:67:89:AB"然後呼叫下面的function 來建立連線sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM ) sock.connect((bd_addr, port))
sock.send("hello!!")
3.3. Communicating with L2CAP
Example 3-4. l2cap-server.py
import bluetooth server_sock=bluetooth.BluetoothSocket( bluetooth.L2CAP ) port = 0x1001 server_sock.bind(("",port)) server_sock.listen(1) 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()
Example 3-5. l2cap-client.py
import bluetooth sock=bluetooth.BluetoothSocket(bluetooth.L2CAP) bd_addr = "01:23:45:67:89:AB" port = 0x1001 sock.connect((bd_addr, port)) sock.send("hello!!") sock.close()
===============================================================
sample code 和 chapter 3.2差不多...只差在指定傳輸的方式
3.4. Service Discovery Protocol
Dynamically allocating port numbers and using the Service Discovery Protocol (SDP) to search for and advertise services is a simple process in PyBluez
動態地配置port number 和 使用 service Dsicovery Protocol 去尋找和配置服務在PyBluez 是一個很簡單的過程
luetooth.get_available_port( protocol )
The get_available_port method finds available L2CAP and RFCOMM ports
bluetooth.advertise_service( sock, name, uuid ) bluetooth.stop_advertising( sock ) bluetooth.find_service( name = None, uuid = None, bdaddr = None )
advertise_service advertises a service with the local SDP server, and find_service searches Bluetooth devices for a specific service.
The UUID must always be a string of the form ``xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" or ``xxxxxxxx" or ``xxxx", where each 'x' is a hexadecimal digit
find_service looks for a service with name and UUID that match name and uuid, at least one of which must be specified
In the special case that ``localhost" is used for bdaddr,
直接看範例吧...
Example 3-6. rfcomm-server-sdp.pyimport bluetooth server_sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM ) port = bluetooth.get_available_port( bluetooth.RFCOMM ) server_sock.bind(("",port)) server_sock.listen(1) print "listening on port %d" % port uuid = "1e0ca4ea-299d-4335-93eb-27fcfe7fa848" bluetooth.advertise_service( server_sock, "FooBar Service", uuid ) 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()Example 3-7. rfcomm-client-sdp.pyimport sys import bluetooth uuid = "1e0ca4ea-299d-4335-93eb-27fcfe7fa848" service_matches = bluetooth.find_service( uuid = uuid ) if len(service_matches) == 0: print "couldn't find the FooBar service" sys.exit(0) first_match = service_matches[0] port = first_match["port"] name = first_match["name"] host = first_match["host"] print "connecting to \"%s\" on %s" % (name, host) sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM ) sock.connect((host, port)) sock.send("hello!!") sock.close()==========================================================在執行這個範例... 需要先找到你的UUID...從Ref 5可以得知vi get_uuid.pyget_uuid.py 的內容如下:#!/usr/bin/python
import sys,uuid
print uuid.uuid4().hex
執行後的結果如下所以要把內文中的uuid 改成你執行後所得到的值.....在執行/rfcomm-server-sdp.py 會遇到下面的問題查了一下 google...從ref 6 可以得知...原來get_available_port(protocol)deprecated. bind to port zero instead.
get_available_port 函式已經被放棄了請改用 port 0來代替...所以修改你的code#port = bluetooth.get_available_port( bluetooth.RFCOMM )
port = 0
在client 端使用 find_service...來尋找 service...他指定了uuid ..藉由找到的service_match[0]來得到 port 和 name 和 host...然後再用sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )sock.connect((host, port))
來產生連線....執行結果如下:
3.5. Advanced usage
They don't return until the requests are complete, which can often taken a long time . During this time, the controlling thread blocks and can't do anything else....PyBluez provides the DeviceDiscoverer class for asynchronous device discovery and name lookup.Example 3-8. asynchronous-inquiry.pyimport bluetooth import select class MyDiscoverer(bluetooth.DeviceDiscoverer): def pre_inquiry(self): self.done = False def device_discovered(self, address, device_class, name): print "%s - %s" % (address, name) def inquiry_complete(self): self.done = True d = MyDiscoverer() d.find_devices(lookup_names = True) readfiles = [ d, ] while True: rfds = select.select( readfiles, [], [] )[0] if d in rfds: d.process_event() if d.done: break
To asynchronously detect nearby bluetooth devices, create a subclass of DeviceDiscoverer and override the pre_inquiry, device_discovered, and inquiry_complete methods.
Reference 1: https://people.csail.mit.edu/albert/bluez-intro/
Reference 2 : http://cheng-min-i-taiwan.blogspot.tw/2015/03/raspberry-pi-40ibeacon.html
Reference 3 : https://github.com/karulis/pybluez
Reference 4 : http://forum.erlerobotics.com/t/working-with-bluetooth/453
Reference 5 : http://www.wadewegner.com/2014/05/create-an-ibeacon-transmitter-with-the-raspberry-pi/
Reference 6 : https://www.raspberrypi.org/forums/viewtopic.php?f=32&t=113987