前言
因为需要对蓝牙信息进行获取,但是找了一些python模块,比如bluepy只支持Linux、bleson项目文档又太烂。因此这里干脆就直接通过命令行获取,然后对信息进行处理了。
步骤
分析命令行
Mac获取蓝牙信息可以使用下面的命令:
system_profiler SPBluetoothDataType
使用python的os
模块即可,执行完成之后如下。
Bluetooth:
Apple Bluetooth Software Version: 7.0.0f8
Hardware, Features, and Settings:
Name: Zheyi的MacBook Pro
Address: F0-18-98-0B-B7-35
Bluetooth Low Energy Supported: Yes
Handoff Supported: Yes
Instant Hot Spot Supported: Yes
Manufacturer: Broadcom
Transport: UART
Chipset: 4364B0
Firmware Version: v83 c4405
Bluetooth Power: On
Discoverable: Off
Connectable: Yes
Auto Seek Pointing: On
Remote wake: On
Vendor ID: 0x05AC
Product ID: 0x007B
Bluetooth Core Spec: 5.0 (0x9)
HCI Revision: 0x1135
LMP Version: 5.0 (0x9)
LMP Subversion: 0x2053
Device Type (Major): Computer
Device Type (Complete): Mac Portable
Composite Class Of Device: 0x38010C
Device Class (Major): 0x01
Device Class (Minor): 0x03
Service Class: 0x1C0
Auto Seek Keyboard: On
Devices (Paired, Configured, etc.):
BlueBlueSky’s Beats Solo³:
Address: D4-90-9C-3A-C6-41
Major Type: Audio
Minor Type: Headphones
Services: Handsfree, AAP Server, SPP Server, AVRCP Controller, Audio Sink, Wireless iAP, AVRCP Target
Paired: Yes
Configured: Yes
Connected: Yes
Manufacturer: Apple (0x6, 0x03)
Bluetooth Core Spec: 4.0
Firmware Version: 0x0772
Vendor ID: 0x004C
Product ID: 0x2006
Class of Device: 0x04 0x06 0x240418
RSSI: -32
Role: Master
Connection Mode: Sniff Mode
Interval: 441.25 ms
EDR Supported: Yes
eSCO Supported: Yes
SSP Supported: Yes
......
剩下的一些输出信息就不写了,我们的目标其实是获取Devices那一部分后面的设备信息。其实有很明显的层级结构,第一行Bluetooth
是第0级,Devices (Paired, Configured, etc.)
与其他一些信息都是第1级,设备的名称处于第2级,设备的具体信息处于第3级。
还有一个很明显的特征,键值是通过:
分割的,和json数据很相似,python里面我们就可以使用字典dict来表示。如果我们将这些字符串信息转化成字典dict那么就可以很方便的获取相关信息了,比如这样dict["Bluetooth"]["Devices"]
就可以获取所有设备相关信息的数组。
步骤
简单描述一下代码思路
执行命令行并获取层级信息
获取每行的信息,主要是根据缩进判定该行的层级,我们将行的信息从字符串转化成如下结构, 篇幅限制我就写前两行:
[{'name': 'Bluetooth', 'value': '', 'level': 0},
{'name': 'Apple Bluetooth Software Version', 'value': '7.0.0f8', 'level': 1.0},
......]
这里需要注意的是,命令行里面的缩进并不是制表符,第0级是0个空格缩进,第1级是6个空格缩进,第2级是10个空格缩进,第n级是4n+2个缩进(n≠0)。
根据层级信息生成字典
这里就根据上面的层级信息生成字典数据。因为我们生成的层级信息上下之间是有联系的,比如层级依次是这样的01222122,前三个2是属于第一个1的,后面两个2是属于第一个1的。因此下一层级的所有数据可以作为一个整体list成为上一级的值,这里递归就可以根据层级结构较为方便地生成字典结构。
代码
具体代码如下:
import os
def bluetooth_rssi_get():
cmd = "system_profiler SPBluetoothDataType"
devices = get_bluetooth_devices(cmd)
print(devices)
for device_name, device_info in devices.items():
for key, value in device_info.items():
if key == 'Connected':
if value == 'Yes':
print(device_name, "连接中")
else:
print(device_name, "未连接")
if key == 'RSSI':
print('RSSI:', value)
def get_bluetooth_devices(cmd):
'''
执行cmd命令获取所有蓝牙相关信息
:param cmd: 命令行
:return: 返回所有连接中或连接过的蓝牙设备
'''
r = os.popen(cmd)
info = r.readlines() # 读取命令行的输出到一个list
level_map = process_info(info)
r.close()
return level_map2dict(level_map)["Bluetooth"]["Devices (Paired, Configured, etc.)"]
def process_info(info):
'''
处理命令行结果,生成根据缩进判定的层级
:param info: 命令行结果,每行以数组形成存储
:return: 带有层级的数组
'''
level_map = []
for line in info: # 按行遍历
line = line.strip('\r\n')
if len(line) > 0: # 第二行是空行
line_info = get_line_info(line)
if line_info["level"] >= 0: # 把第一行Bluetooth去除
level_map.append(line_info)
print(level_map)
return level_map
def get_line_info(line):
'''
解析命令行每行信息
:param line: 传入行
:return: 根据冒号分割以及缩进,生成的每行信息(字典形式)
'''
split = line.split(':')
name = split[0].lstrip(' ')
value = split[1].lstrip(' ')
level = (len(line) - len(line.lstrip(' ')) - 2) / 4
if level < 0:
level = 0 # 针对第一行
line_info = {}
line_info["name"] = name
line_info["value"] = value
line_info["level"] = level
return line_info
def level_map2dict(ttree, level=0):
'''
根据层级信息转化成字典结构
:param ttree:
:param level:
:return:
'''
result = {}
for i in range(0, len(ttree)):
current_node = ttree[i]
try:
next_node = ttree[i + 1]
except:
next_node = {'level': -1}
# 边界条件,非当前层级
if current_node['level'] > level: # 已经作为整体插入,跳过
continue
if current_node['level'] < level: # 当前是上一级的,直接返回现有结果
return result
# 递归生成
if next_node['level'] == level: # 同级
dict_insert_or_append(result, current_node['name'], current_node['value'])
elif next_node['level'] > level: # 下一级,将下一级整体插入
next_level = level_map2dict(ttree[i + 1:], level=next_node['level']) # 剩下的进行处理
dict_insert_or_append(result, current_node['name'], next_level)
else: # 下一个是上一级的,当前插入完成直接返回
dict_insert_or_append(result, current_node['name'], current_node['value'])
return result
return result
def dict_insert_or_append(adict, key, val):
'''
针对key是否存在,新增或者添加
:param adict:
:param key:
:param val:
:return:
'''
if key in adict: # 添加
if type(adict[key]) != list:
adict[key] = [adict[key]] # 将单独存在的转化成list
adict[key].append(val)
else: # 新增
adict[key] = val
bluetooth_rssi_get()