最近要写一款蓝牙耳机PC端的调试工具,和蓝牙耳机进行通讯卡了整整一周,总算是搞定了,鉴于网上相关资料实在太少,避免后面的朋友跟我一样走弯路,简单写一下实现过程。
下面简单介绍一下环境的配置:
1.SDK,地址:https://developer.microsoft.com/zh-cn/windows/downloads/windows-10-sdk/,装了win10的SDK之后,要在SDK的安装目录中,将文件名由:v10.0A为v7.0A,不然会报错
2. 最新的Visual C++ Redistributable:https://www.microsoft.com/en-us/download/details.aspx?id=48145
3. NET.Framework,网址就不贴了,好像很多电脑自带的都有,没有的就装一个。
4. 另外,现在pybluez库最新的版本为0.23,但使用的时候,connect和find_service函数会报错,原因尚不清楚,后来换成0.22就不存在该问题了。
蓝牙通讯双方通讯,一端为server,一端为client,移动端蓝牙大部分都是server;
#server端:
from bluetooth import *
server_sock=BluetoothSocket( RFCOMM )
server_sock.bind(("",PORT_ANY))
server_sock.listen(1)
port = server_sock.getsockname()[1]
uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ee"
advertise_service( server_sock, "SampleServer",
service_id = uuid,
service_classes = [ uuid, SERIAL_PORT_CLASS ],
profiles = [ SERIAL_PORT_PROFILE ],
# protocols = [ OBEX_UUID ]
)
print("Waiting for connection on RFCOMM channel %d" % port)
client_sock, client_info = server_sock.accept()
print("Accepted connection from ", client_info)
try:
while True:
data = client_sock.recv(1024)
if len(data) == 0: break
print("received [%s]" % data)
except IOError:
pass
print("disconnected")
client_sock.close()
server_sock.close()
client端:
from bluetooth import *
import sys
if sys.version < '3':
input = raw_input
addr = None
if len(sys.argv) < 2:
print("no device specified. Searching all nearby bluetooth devices for")
print("the SampleServer service")
else:
addr = sys.argv[1]
print("Searching for SampleServer on %s" % addr)
# search for the SampleServer service
uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ee"
service_matches = find_service( uuid = uuid, address = addr )
if len(service_matches) == 0:
print("couldn't find the SampleServer 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))
# Create the client socket
sock=BluetoothSocket( RFCOMM )
sock.connect((host, port))
print("connected. type stuff")
while True:
data = input()
if len(data) == 0: break
sock.send(data)
sock.close()
官方的文档还是可以的,运行可能会存在一点小问题。看不懂的朋友可以试试下面的内容,亲测可行;
我写的是PC端的工具,代码为client,话不多说直接公布代码吧:
import bluetooth
import sys
import time
name='小米手机10pro'#需连接的设备名字
nearby_devices = bluetooth.discover_devices(lookup_names=True)
print(nearby_devices)#附近所有可连的蓝牙设备
addr=None
for device in nearby_devices:
if name==device[1]:
addr = device[0]
print("device found!",name," address is: ",addr)
break
if addr==None:
print("device not exist")
services = bluetooth.find_service(address=addr)
print(services)
for svc in services:
print("Service Name: %s" % svc["name"])
print(" Host: %s" % svc["host"])
print(" Description: %s" % svc["description"])
print(" Provided By: %s" % svc["provider"])
print(" Protocol: %s" % svc["protocol"])
print(" channel/PSM: %s" % svc["port"])
print(" svc classes: %s "% svc["service-classes"])
print(" profiles: %s "% svc["profiles"])
print(" service id: %s "% svc["service-id"]) #打印蓝牙设备的各种属性
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
'''sock.connect((addr, 2))
print("连接成功,端口:")'''
i=0
while i<255:
try:
sock.connect((addr, i))
print("连接成功,端口:",i)
break
except Exception as e:
print("端口:",i,"连接失败",e)
i=i+1 #遍历端口号,进行连接
C:\Users\Administrator.DESKTOP-2F8V7EJ\AppData\Local\Programs\Python\Python38\python.exe D:\Python\2\bt_connect.py
[('41:42:21:9C:43:1F', 'F9 '), ('A4:4B:D5:09:A9:14', '小米手机10pro')]
device found! address is A4:4B:D5:09:A9:14
...篇幅原因,省略中间蓝牙属性打印
端口: 0 连接失败
端口: 1 连接失败
端口: 2 连接失败
连接成功,端口: 3
Process finished with exit code 0
用这个基本能实现PC端和各种移动蓝牙设备的连接,包括手机,蓝牙耳机,蓝牙音箱等;
虽然蓝牙连接上了,但是蓝牙那端不一定能正常收发数据,pybluez创建套接字是在RFCOMM这一层,蓝牙耳机用的是SPP协议,所以需找到对应的SPP协议,才能完成正常通讯,可以通过uuid找到SPP协议对应的端口,然后再进行通讯,代码如下:
import time
import sys
import bluetooth
#uuid = "98B97136-36A2-11EA-8467-484D7E99A198"
nearby_devices = bluetooth.discover_devices(lookup_names=True)
print(nearby_devices)
uuid = "00001101-0000-1000-8000-00805f9b34fb"
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]
print(first_match)
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((addr, port))
print("连接成功")'''
sock.connect((host, port))
print("连接成功")
while True: #进入循环,不然通讯会自动关闭
sock.send("12345".encode('utf-8'))
sock.send("hello".encode('utf-8'))
data=sock.recv(10) #1024为数据长度
print("received:",data)
time.sleep(5)
以下为打印结果:
C:\Users\Administrator.DESKTOP-2F8V7EJ\AppData\Local\Programs\Python\Python38\python.exe D:/Python/project/test8.py
[('41:42:21:9C:43:1F', 'F9 '), ('A4:4B:D5:09:A9:14', '小米手机10pro')]
{'host': 'A4:4B:D5:09:A9:14', 'name': b'Spp Server', 'description': '', 'port': 5, 'protocol': 'RFCOMM', 'rawrecord': b'6\x00E\t\x00\x00\n\x00\x01\x00\x0e\t\x00\x015\x03\x19\x11\x01\t\x00\x045\x0c5\x03\x19\x01\x005\x05\x19\x00\x03\x08\x05\t\x00\x055\x03\x19\x10\x02\t\x00\t5\x085\x06\x19\x11\x01\t\x01\x02\t\x01\x00%\nSpp Server', 'service-classes': [b'1101'], 'profiles': [(b'1101', 258)], 'provider': None, 'service-id': None, 'handle': 65550}
connecting to "b'Spp Server'" on A4:4B:D5:09:A9:14
连接成功
received: b'12345' #移动端蓝牙采用应答模式,即发什么,会马上回一个相同的字符串
received: b'hello'
用这个便能成功实现蓝牙通讯啦!!!