Python 寫藍芽 Service Discovery Protocol 通訊程式

到目前為止介紹了如何偵測鄰近的藍芽裝置,且建立兩種傳輸類型的連線,都是用固定的 Bluetooth address 和 port numbers,在實務上我們不推薦這麼做。

在 PyBluez 裡, 使用 服務發現協定 Service Discovery Protocol (SDP) 來動態地配置 port number 進行尋找是很簡單的。get_available_port 函式用來查找可用的 L2CAP 或 RFCOMM 的 port。advertise_service 函式用來廣播這個本地端 SDP 伺服器的服務,find_service 函式用來搜尋指定名稱的藍芽裝置。

1
bluetooth.get_available_port( protocol )

get_available_port 回傳指定 protocol 第一個可用的 port number。目前只有支援 RFCOMM 和 L2CAP protocols。get_available_port 只是回傳一個 port number,並沒有實際預定使用任何資源,所以有可能當你要 bind 時,這 port 已經被別人 bind 走了,如果發生的話 bind 會拋出一個BluetoothException 例外。

1
2
3
bluetooth.advertise_service( sock, name, uuid )
bluetooth.stop_advertising( sock )
bluetooth.find_service( name = None, uuid = None, bdaddr = None )

以上這三種函式用來廣撥服務,advertise_service 函式參數分別為 socket, service name 服務名稱, UUID,
這廣撥服務直到呼叫 stop_advertising 函式來關閉該 socket。

find_service可以搜尋單個或者所有附近特定裝置。透過匹配 name 和 UUID 進行 service 尋找(必須至少指定其中一個)。如果 bdaddr 是 None,那麼所有附近的設備都會進行尋找。如果提供了 localhost 作為 bdaddr 參數,那麼會對本地的 SDP 進行尋找。否則,就會指定的 bdaddr 藍芽裝置進行尋找。

server 端程式

rfcomm-server-sdp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import 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()

client 端程式

rfcomm-client-sdp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import 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()

參考
https://people.csail.mit.edu/albert/bluez-intro/x290.html

相關主題
Python 的第一支藍芽程式
Python 寫藍芽 RFCOMM 通訊程式
Python 寫藍芽 L2CAP 通訊程式